fortitude

Finished
44//
55
66/**
7 * @param {string[]} board
8 * @returns {string}
7 * Determines the state of a Tic-Tac-Toe game based on the given board.
8 *
9 * @param {string[]} board - An array of 3 strings, each representing a row of the 3x3 board.
10 * Each character is either 'X', 'O', or ' ' (empty space).
11 * @returns {string} - Returns 'win', 'draw', or 'ongoing' based on the game state.
12 * @throws {Error} - Throws an error for invalid board states with specific messages.
913 */
1014export const gamestate = (board) => {
11 throw new Error('Remove this line and implement the function');
12};
15 // Validate board structure
16 if (!Array.isArray(board) || board.length !== 3) {
17 throw new Error('Invalid board: must have 3 rows');
18 }
19
20 for (let i = 0; i < 3; i++) {
21 if (typeof board[i] !== 'string' || board[i].length !== 3) {
22 throw new Error('Invalid board: each row must be a string of length 3');
23 }
24 }
25
26 // Count X's and O's
27 let xCount = 0;
28 let oCount = 0;
29
30 for (let i = 0; i < 3; i++) {
31 for (let j = 0; j < 3; j++) {
32 const char = board[i][j];
33 if (char === 'X') {
34 xCount++;
35 } else if (char === 'O') {
36 oCount++;
37 } else if (char !== ' ') {
38 throw new Error('Invalid board: contains invalid characters');
39 }
40 }
41 }
42
43 // Validate turn order - X starts and players alternate
44 // Valid states:
45 // - xCount == oCount (X started, O just played)
46 // - xCount == oCount + 1 (X started, X just played)
47 // Invalid states:
48 // - oCount > xCount (O started or O played twice)
49 // - xCount > oCount + 1 (X played twice)
50
51 if (oCount > xCount) {
52 // O has more moves than X - this is invalid
53 // Need to determine if O started or if a player went twice
54
55 // Collect moves in order to determine sequence
56 let moves = [];
57 for (let i = 0; i < 3; i++) {
58 for (let j = 0; j < 3; j++) {
59 if (board[i][j] !== ' ') {
60 moves.push(board[i][j]);
61 }
62 }
63 }
64
65 // If first move is O, then O started the game
66 if (moves.length > 0 && moves[0] === 'O') {
67 throw new Error('Wrong turn order: O started');
68 } else {
69 // X started, but O went twice in a row
70 // Check for consecutive O's
71 for (let i = 1; i < moves.length; i++) {
72 if (moves[i] === 'O' && moves[i-1] === 'O') {
73 throw new Error('Wrong turn order: O went twice');
74 }
75 }
76
77 // If we get here, there's some other invalid pattern
78 throw new Error('Wrong turn order: O started');
79 }
80 }
81
82 if (xCount > oCount + 1) {
83 // X has more than one extra move - this is invalid
84 // Need to check if X went twice in a row
85
86 // Collect moves in order to determine sequence
87 let moves = [];
88 for (let i = 0; i < 3; i++) {
89 for (let j = 0; j < 3; j++) {
90 if (board[i][j] !== ' ') {
91 moves.push(board[i][j]);
92 }
93 }
94 }
95
96 // Check for consecutive X's
97 for (let i = 1; i < moves.length; i++) {
98 if (moves[i] === 'X' && moves[i-1] === 'X') {
99 throw new Error('Wrong turn order: X went twice');
100 }
101 }
102
103 // If we get here, there's some other invalid pattern
104 throw new Error('Wrong turn order: X went twice');
105 }
106
107 // Check for wins
108 const checkWin = (player) => {
109 // Check rows
110 for (let i = 0; i < 3; i++) {
111 if (board[i][0] === player && board[i][1] === player && board[i][2] === player) {
112 return true;
113 }
114 }
115
116 // Check columns
117 for (let j = 0; j < 3; j++) {
118 if (board[0][j] === player && board[1][j] === player && board[2][j] === player) {
119 return true;
120 }
121 }
122
123 // Check diagonals
124 if (board[0][0] === player && board[1][1] === player && board[2][2] === player) {
125 return true;
126 }
127
128 if (board[0][2] === player && board[1][1] === player && board[2][0] === player) {
129 return true;
130 }
131
132 return false;
133 };
134
135 const xWins = checkWin('X');
136 const oWins = checkWin('O');
137
138 // Edge Case: Both players win (impossible in a valid game)
139 if (xWins && oWins) {
140 throw new Error('Impossible board: game should have ended after the game was won');
141 }
142
143 // Edge Case: Game continued after a win
144 // If a player has won, no more moves should be made
145 if (xWins) {
146 // X has won, so O should not have played after X's win
147 // This means oCount should be < xCount (X won and then no more moves)
148 // or oCount == xCount (X won and O just played - still invalid)
149 if (oCount >= xCount) {
150 throw new Error('Impossible board: game should have ended after the game was won');
151 }
152 }
153
154 if (oWins) {
155 // O has won, so X should not have played after O's win
156 // This means xCount should be <= oCount (O won and then no more moves or O just played)
157 // But since X starts, xCount should be == oCount (O won and X just played - still invalid)
158 if (xCount > oCount) {
159 throw new Error('Impossible board: game should have ended after the game was won');
160 }
161 }
162
163 // Determine game state
164 if (xWins || oWins) {
165 return 'win';
166 }
167
168 // Edge Case: Board is full (draw)
169 if (xCount + oCount === 9) {
170 return 'draw';
171 }
172
173 // Edge Case: Game is not finished yet
174 return 'ongoing';
175};
Test NameStatus
Finished game where X won via left column victory
Pass
Finished game where X won via middle column victory
Pass
Finished game where X won via right column victory
Pass
Finished game where O won via left column victory
Pass
Finished game where O won via middle column victory
Pass
Finished game where O won via right column victory
Pass
Finished game where X won via top row victory
Pass
Finished game where X won via middle row victory
Pass
Finished game where X won via bottom row victory
Pass
Finished game where O won via top row victory
Pass
Finished game where O won via middle row victory
Pass
Finished game where O won via bottom row victory
Pass
Finished game where X won via falling diagonal victory
Pass
Finished game where X won via rising diagonal victory
Pass
Finished game where O won via falling diagonal victory
Pass
Finished game where O won via rising diagonal victory
Pass
Finished game where X won via a row and a column victory
Pass
Finished game where X won via two diagonal victories
Pass
Draw
Pass
Another draw
Pass
Ongoing game: one move in
Pass
Ongoing game: two moves in
Pass
Ongoing game: five moves in
Pass
Invalid board: X went twice
Pass
Invalid board: O started
Pass
Invalid board: X won and O kept playing
Pass
Invalid board: players kept playing after a win
Pass

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