Finished
88 * @param {string[]} board
99 */
1010 constructor(board) {
11 throw new Error('Remove this line and implement the function');
11 this.board = board;
12 this.height = board.length;
13 this.width = this.height > 0 ? board[0].length : 0;
1214 }
1315
1416 /**
1719 * @return {{owner: 'BLACK' | 'WHITE' | 'NONE', territory: [number, number][]}}
1820 */
1921 getTerritory(x, y) {
20 throw new Error('Remove this line and implement the function');
22 // Edge Case: Invalid coordinates (out of bounds)
23 if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
24 throw new Error('Invalid coordinate');
25 }
26
27 // Edge Case: Coordinate is not empty (including ignored stones)
28 if (this.board[y][x] !== ' ') {
29 return { owner: 'NONE', territory: [] };
30 }
31
32 // Edge Case: Empty board or single empty intersection
33 return this._calculateTerritory(x, y);
2134 }
2235
2336 /**
2437 * @return {{territoryBlack: [number, number][], territoryWhite: [number, number][], territoryNone: [number, number][]}}
2538 */
2639 getTerritories() {
27 throw new Error('Remove this line and implement the function');
40 const territories = {
41 territoryBlack: [],
42 territoryWhite: [],
43 territoryNone: []
44 };
45
46 const visited = Array(this.height).fill().map(() => Array(this.width).fill(false));
47
48 // Edge Case: Empty board
49 if (this.height === 0 || this.width === 0) {
50 return territories;
51 }
52
53 for (let y = 0; y < this.height; y++) {
54 for (let x = 0; x < this.width; x++) {
55 if ((this.board[y][x] === ' ' || this.board[y][x] === 'I') && !visited[y][x]) {
56 // Only process empty spaces, not ignored stones
57 if (this.board[y][x] === 'I') {
58 visited[y][x] = true;
59 continue;
60 }
61 const { owner, territory } = this._calculateTerritory(x, y);
62
63 // Mark all points in this territory as visited
64 for (const [tx, ty] of territory) {
65 visited[ty][tx] = true;
66 }
67
68 // Add territory points to appropriate category
69 if (owner === 'BLACK') {
70 territories.territoryBlack.push(...territory);
71 } else if (owner === 'WHITE') {
72 territories.territoryWhite.push(...territory);
73 } else {
74 territories.territoryNone.push(...territory);
75 }
76 }
77 }
78 }
79
80 return territories;
81 }
82
83 /**
84 * Helper method to calculate territory starting from a point
85 * @param {number} x
86 * @param {number} y
87 * @return {{owner: 'BLACK' | 'WHITE' | 'NONE', territory: [number, number][]}}
88 */
89 _calculateTerritory(x, y) {
90 const visited = new Set();
91 const queue = [[x, y]];
92 const territory = [];
93 let owner = null;
94 let hasOwner = true;
95
96 // Edge Case: Board with no empty spaces
97 if (this.board[y][x] !== ' ') {
98 return { owner: 'NONE', territory: [] };
99 }
100
101 while (queue.length > 0) {
102 const [cx, cy] = queue.shift();
103 const key = `${cx},${cy}`;
104
105 // Edge Case: Already visited this position
106 if (visited.has(key)) {
107 continue;
108 }
109
110 visited.add(key);
111
112 // Edge Case: Position is a stone - check ownership but don't add to territory
113 if (this.board[cy][cx] === 'B' || this.board[cy][cx] === 'W' || this.board[cy][cx] === 'I') {
114 if (this.board[cy][cx] === 'B') {
115 if (owner === null) {
116 owner = 'BLACK';
117 } else if (owner !== 'BLACK') {
118 hasOwner = false;
119 }
120 } else if (this.board[cy][cx] === 'W') {
121 if (owner === null) {
122 owner = 'WHITE';
123 } else if (owner !== 'WHITE') {
124 hasOwner = false;
125 }
126 }
127 // Stones and ignored stones are not part of territory and block connectivity
128 // Remove from visited so they don't block other territory calculations
129 visited.delete(key);
130 continue;
131 }
132
133 // Add empty space to territory
134 territory.push([cx, cy]);
135
136 // Check neighbors
137 const neighbors = [
138 [cx - 1, cy], // left
139 [cx + 1, cy], // right
140 [cx, cy - 1], // up
141 [cx, cy + 1] // down
142 ];
143
144 for (const [nx, ny] of neighbors) {
145 // Edge Case: Neighbor is out of bounds (territory touching board edges)
146 if (nx >= 0 && nx < this.width && ny >= 0 && ny < this.height) {
147 const nKey = `${nx},${ny}`;
148 if (!visited.has(nKey)) {
149 // Edge Case: Neighbor is empty space
150 if (this.board[ny][nx] === ' ') {
151 queue.push([nx, ny]);
152 }
153 // Edge Case: Neighbor is a stone
154 else if (this.board[ny][nx] === 'B') {
155 if (owner === null) {
156 owner = 'BLACK';
157 } else if (owner !== 'BLACK') {
158 hasOwner = false;
159 }
160 } else if (this.board[ny][nx] === 'W') {
161 if (owner === null) {
162 owner = 'WHITE';
163 } else if (owner !== 'WHITE') {
164 hasOwner = false;
165 }
166 }
167 // Edge Case: Neighbor is ignored stone - treat as wall, don't add to queue
168 else if (this.board[ny][nx] === 'I') {
169 // Ignored stones act as walls and don't affect territory ownership
170 }
171 }
172 }
173 // Edge Case: Neighbor is out of bounds - board edge acts as a wall
174 // and does not affect territory ownership
175 }
176 }
177
178 // Edge Case: Territory with mixed owners or touching edges
179 if (!hasOwner) {
180 owner = 'NONE';
181 } else if (owner === null) {
182 owner = 'NONE';
183 }
184
185 // Sort territory coordinates for consistent output
186 territory.sort((a, b) => {
187 if (a[1] !== b[1]) return a[1] - b[1];
188 return a[0] - b[0];
189 });
190
191 return { owner, territory };
28192 }
29193}
194
195// Handled Edge Cases: Invalid coordinates, coordinate is not empty, empty board, single empty intersection, board with no empty spaces, already visited position, position is a stone, neighbor is out of bounds, neighbor is empty space, neighbor is a stone, territory with mixed owners or touching edges
Test NameStatus
Black corner territory on 5x5 board
Fail
Invalid because X is too low for 5x5 board
Fail
Invalid because X is too high for 5x5 board
Fail
Invalid because Y is too low for 5x5 board
Fail
Invalid because Y is too high for 5x5 board
Fail
White center territory on 5x5 board
Pass
Open corner territory on 5x5 board
Pass
A stone and not a territory on 5x5 board
Pass
One territory is the whole board
Pass
Two territory rectangular board
Pass
Two region rectangular board
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.