Files
wechat-minigame/js/gameplay/difficulty/overlap-graph.js
2026-03-29 00:36:28 +08:00

75 lines
2.1 KiB
JavaScript

function getPieceArea(piece) {
return piece.width * piece.height
}
function overlapArea(left, right) {
const overlapWidth = Math.max(0, Math.min(left.x + left.width, right.x + right.width) - Math.max(left.x, right.x))
const overlapHeight = Math.max(0, Math.min(left.y + left.height, right.y + right.height) - Math.max(left.y, right.y))
return overlapWidth * overlapHeight
}
function overlapsCenterZone(lower, upper) {
const centerWidth = lower.width * 0.5
const centerHeight = lower.height * 0.5
const centerBox = {
x: lower.x + lower.width * 0.25,
y: lower.y + lower.height * 0.25,
width: centerWidth,
height: centerHeight,
}
return overlapArea(centerBox, upper) > 0
}
export function buildOverlapGraph(pieces) {
const graph = Object.fromEntries(pieces.map((piece) => [piece.id, []]))
for (let leftIndex = 0; leftIndex < pieces.length; leftIndex += 1) {
for (let rightIndex = 0; rightIndex < pieces.length; rightIndex += 1) {
if (leftIndex === rightIndex) {
continue
}
const blocker = pieces[leftIndex]
const blocked = pieces[rightIndex]
if (blocker.layer <= blocked.layer) {
continue
}
const ratio = overlapArea(blocker, blocked) / getPieceArea(blocked)
if (ratio >= 0.2 && overlapsCenterZone(blocked, blocker)) {
graph[blocker.id].push(blocked.id)
}
}
}
return graph
}
export function getClickablePieces(boardState) {
const pieces = (boardState.pieces ?? []).filter((piece) => !piece.removed)
const indegree = Object.fromEntries(pieces.map((piece) => [piece.id, 0]))
const graph = boardState.overlapGraph ?? {}
for (const blockedIds of Object.values(graph)) {
for (const blockedId of blockedIds) {
if (blockedId in indegree) {
indegree[blockedId] += 1
}
}
}
return pieces.filter((piece) => indegree[piece.id] === 0)
}
export function rebuildGraphAfterShuffle(boardState) {
return buildOverlapGraph(boardState.pieces ?? [])
}
export function rebuildGraphAfterUndo(boardState) {
return buildOverlapGraph(boardState.pieces ?? [])
}