Finished
88 * @param {string[]} board
99 */
1010 constructor(board) {
11 throw new Error('Remove this line and implement the function');
11 // Edge Case: Handle empty board
12 if (!board || board.length === 0) {
13 this.board = [];
14 this.height = 0;
15 this.width = 0;
16 return;
17 }
18
19 // Normalize the board by trimming leading spaces and converting to array of arrays
20 // For hexagonal boards, we need to handle the space-separated format properly
21 this.board = board.map(row => {
22 // Remove leading spaces and split by spaces to get individual cells
23 const trimmed = row.replace(/^\s+/, '');
24 return trimmed.split(/\s+/); // Split by one or more spaces
25 });
26 this.height = this.board.length;
27 this.width = this.height > 0 ? this.board[0].length : 0;
1228 }
1329
1430 /**
1531 * @return {'X' | 'O' | ''}
1632 */
1733 winner() {
18 throw new Error('Remove this line and implement the function');
34 // Edge Case: Handle empty board
35 if (this.height === 0 || this.width === 0) {
36 return '';
37 }
38
39 // Check if O (top to bottom) has won
40 if (this.checkWinner('O')) {
41 return 'O';
42 }
43
44 // Check if X (left to right) has won
45 if (this.checkWinner('X')) {
46 return 'X';
47 }
48
49 return '';
50 }
51
52 /**
53 * @param {'X' | 'O'} player
54 * @return {boolean}
55 */
56 checkWinner(player) {
57 const visited = Array(this.height).fill().map(() => Array(this.width).fill(false));
58
59 if (player === 'O') {
60 // For O, check if there's a path from top to bottom
61 for (let col = 0; col < this.width; col++) {
62 if (this.board[0][col] === player && !visited[0][col]) {
63 if (this.dfs(0, col, player, visited, 'vertical')) {
64 return true;
65 }
66 }
67 }
68 } else if (player === 'X') {
69 // For X, check if there's a path from left to right
70 for (let row = 0; row < this.height; row++) {
71 if (this.board[row][0] === player && !visited[row][0]) {
72 if (this.dfs(row, 0, player, visited, 'horizontal')) {
73 return true;
74 }
75 }
76 }
77 }
78
79 return false;
80 }
81
82 /**
83 * @param {number} row
84 * @param {number} col
85 * @param {'X' | 'O'} player
86 * @param {boolean[][]} visited
87 * @param {'vertical' | 'horizontal'} direction
88 * @return {boolean}
89 */
90 dfs(row, col, player, visited, direction) {
91 // Check bounds
92 if (row < 0 || row >= this.height || col < 0 || col >= this.width) {
93 return false;
94 }
95
96 // Check if already visited or not the player's stone
97 if (visited[row][col] || this.board[row][col] !== player) {
98 return false;
99 }
100
101 // Check win condition
102 if (player === 'O' && direction === 'vertical' && row === this.height - 1) {
103 return true; // Reached bottom row
104 }
105
106 if (player === 'X' && direction === 'horizontal' && col === this.width - 1) {
107 return true; // Reached rightmost column
108 }
109
110 // Mark as visited
111 visited[row][col] = true;
112
113 // Hexagonal neighbors - correct pattern for hexagonal grid
114 const neighbors = [];
115
116 // Standard hexagonal neighbors (6 directions)
117 neighbors.push(
118 [row - 1, col], // Top
119 [row + 1, col], // Bottom
120 [row, col - 1], // Left
121 [row, col + 1], // Right
122 [row - 1, col - 1], // Top-left
123 [row + 1, col + 1] // Bottom-right
124 );
125
126 // Check all neighbors
127 for (const [nRow, nCol] of neighbors) {
128 if (this.dfs(nRow, nCol, player, visited, direction)) {
129 return true;
130 }
131 }
132
133 return false;
19134 }
20135}
136
137// Handled Edge Cases: empty board, invalid board dimensions, disconnected components, games with no winner yet
Test NameStatus
illegal diagonal does not make a winner
Fail
nobody wins crossing adjacent angles
Fail
O wins crossing from top to bottom
Fail
X wins using a convoluted path
Fail
an empty board has no winner
Pass
X can win on a 1x1 board
Pass
O can win on a 1x1 board
Pass
only edges does not make a winner
Pass
X wins crossing from left to right
Pass
X wins using a spiral path
Pass

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