export class GoCounting {
constructor(board) {
this.board = board.split('\n').map((row) => [...row]);
this.height = this.board.length;
this.width = this.board[0] ? this.board[0].length : 0;
}
getTerritory(x, y) {
if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
return { owner: 'NONE', territory: [] };
}
if (this.board[y][x] !== ' ') {
return { owner: 'NONE', territory: [] };
}
const territory = [];
const visited = new Set();
const queue = [[x, y]];
const owners = new Set();
visited.add(`${x},${y}`);
while (queue.length > 0) {
const [cx, cy] = queue.shift();
territory.push([cx, cy]);
[[0, 1], [0, -1], [1, 0], [-1, 0]].forEach(([dx, dy]) => {
const nx = cx + dx;
const ny = cy + dy;
if (nx >= 0 && nx < this.width && ny >= 0 && ny < this.height) {
if (this.board[ny][nx] === ' ') {
if (!visited.has(`${nx},${ny}`)) {
visited.add(`${nx},${ny}`);
queue.push([nx, ny]);
}
} else {
owners.add(this.board[ny][nx] === 'B' ? 'BLACK' : 'WHITE');
}
}
});
}
let owner = 'NONE';
if (owners.size === 1) owner = owners.values().next().value;
return {
owner,
territory: territory.sort((a, b) => a[0] - b[0] || a[1] - b[1]),
};
}
getTerritories() {
const territories = { BLACK: [], WHITE: [], NONE: [] };
const visitedGlobal = new Set();
for (let y = 0; y < this.height; y++) {
for (let x = 0; x < this.width; x++) {
if (this.board[y][x] === ' ' && !visitedGlobal.has(`${x},${y}`)) {
const { owner, territory } = this.getTerritory(x, y);
territories[owner].push(...territory);
territory.forEach(([tx, ty]) => visitedGlobal.add(`${tx},${ty}`));
}
}
}
return territories;
}
}