| 5 | 5 | |
| 6 | 6 | export class GoCounting { |
| 7 | 7 | constructor(board) { |
| 8 | | throw new Error('Remove this line and implement the function'); |
| 8 | this.board = board; |
| 9 | this.height = board.length; |
| 10 | this.width = board.length > 0 ? board[0].length : 0; |
| 9 | 11 | } |
| 10 | 12 | |
| 11 | 13 | getTerritory(x, y) { |
| 12 | | throw new Error('Remove this line and implement the function'); |
| 14 | // Edge Case: Invalid coordinates (negative) |
| 15 | if (x < 0 || y < 0) { |
| 16 | return { error: 'Invalid coordinate' }; |
| 17 | } |
| 18 | |
| 19 | // Edge Case: Invalid coordinates (out of bounds) |
| 20 | if (x >= this.width || y >= this.height) { |
| 21 | return { error: 'Invalid coordinate' }; |
| 22 | } |
| 23 | |
| 24 | // Edge Case: Coordinate is not empty (occupied by stone) |
| 25 | if (this.board[y][x] !== ' ') { |
| 26 | return { owner: 'NONE', territory: [] }; |
| 27 | } |
| 28 | |
| 29 | // Edge Case: Empty board with single empty intersection |
| 30 | return this._calculateTerritory(x, y); |
| 31 | } |
| 32 | |
| 33 | _calculateTerritory(x, y) { |
| 34 | const visited = new Set(); |
| 35 | const territory = []; |
| 36 | const neighbors = new Set(); |
| 37 | const queue = [[x, y]]; |
| 38 | |
| 39 | while (queue.length > 0) { |
| 40 | const [cx, cy] = queue.shift(); |
| 41 | const key = `${cx},${cy}`; |
| 42 | |
| 43 | // Edge Case: Already visited position |
| 44 | if (visited.has(key)) { |
| 45 | continue; |
| 46 | } |
| 47 | |
| 48 | visited.add(key); |
| 49 | |
| 50 | // Edge Case: Position is empty - part of territory |
| 51 | if (this.board[cy][cx] === ' ') { |
| 52 | territory.push([cx, cy]); |
| 53 | |
| 54 | // Check all four neighbors |
| 55 | const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; |
| 56 | for (const [dx, dy] of directions) { |
| 57 | const nx = cx + dx; |
| 58 | const ny = cy + dy; |
| 59 | |
| 60 | // Edge Case: Neighbor is within board boundaries |
| 61 | if (nx >= 0 && nx < this.width && ny >= 0 && ny < this.height) { |
| 62 | queue.push([nx, ny]); |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | // Edge Case: Position has a stone - add to neighbors |
| 67 | else { |
| 68 | neighbors.add(this.board[cy][cx]); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | // Edge Case: Territory with no enclosing stones |
| 73 | if (neighbors.size === 0) { |
| 74 | return { owner: 'NONE', territory: territory.sort() }; |
| 75 | } |
| 76 | |
| 77 | // Edge Case: Territory enclosed by stones of one player |
| 78 | if (neighbors.size === 1) { |
| 79 | const owner = neighbors.has('B') ? 'BLACK' : 'WHITE'; |
| 80 | return { owner: owner, territory: territory.sort() }; |
| 81 | } |
| 82 | |
| 83 | // Edge Case: Territory with stones of both players |
| 84 | return { owner: 'NONE', territory: territory.sort() }; |
| 13 | 85 | } |
| 14 | 86 | |
| 15 | 87 | getTerritories() { |
| 16 | | throw new Error('Remove this line and implement the function'); |
| 88 | const territories = { |
| 89 | 'territoryBlack': [], |
| 90 | 'territoryWhite': [], |
| 91 | 'territoryNone': [] |
| 92 | }; |
| 93 | const visited = new Set(); |
| 94 | |
| 95 | // Edge Case: Empty board |
| 96 | if (this.height === 0 || this.width === 0) { |
| 97 | return territories; |
| 98 | } |
| 99 | |
| 100 | for (let y = 0; y < this.height; y++) { |
| 101 | for (let x = 0; x < this.width; x++) { |
| 102 | // Edge Case: Only process empty intersections |
| 103 | if (this.board[y][x] === ' ' && !visited.has(`${x},${y}`)) { |
| 104 | const result = this._calculateTerritory(x, y); |
| 105 | const territoryKey = result.owner === 'BLACK' ? 'territoryBlack' : |
| 106 | result.owner === 'WHITE' ? 'territoryWhite' : 'territoryNone'; |
| 107 | territories[territoryKey] = territories[territoryKey].concat(result.territory); |
| 108 | |
| 109 | // Mark all territory points as visited |
| 110 | for (const [tx, ty] of result.territory) { |
| 111 | visited.add(`${tx},${ty}`); |
| 112 | } |
| 113 | } |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | // Sort all territories |
| 118 | territories['territoryBlack'].sort(); |
| 119 | territories['territoryWhite'].sort(); |
| 120 | territories['territoryNone'].sort(); |
| 121 | |
| 122 | return territories; |
| 17 | 123 | } |
| 18 | 124 | } |
| 125 | |
| 126 | // Handled Edge Cases: Invalid coordinates (negative), Invalid coordinates (out of bounds), Coordinate is not empty (occupied by stone), Empty board with single empty intersection, Already visited position, Position is empty - part of territory, Neighbor is within board boundaries, Position has a stone - add to neighbors, Territory with no enclosing stones, Territory enclosed by stones of one player, Territory with stones of both players, Empty board, Only process empty intersections |