A.2.1

Finished
1//
2// This is only a SKELETON file for the 'State of Tic Tac Toe' exercise. It's been provided as a
3// convenience to get you started writing code faster.
4//
5
6/**
7 * @param {string[]} board
8 * @returns {string}
1/*
2 * Determines the state of a Tic-Tac-Toe game based on the given board.
3 * @param {string[]} board - An array of strings representing the game board.
4 * @returns {string} - Returns 'win', 'draw', or 'ongoing' based on the game state.
5 * @throws {Error} - Throws an error for invalid board states with specific messages.
96 */
107export const gamestate = (board) => {
11 throw new Error('Remove this line and implement the function');
12};
8 // Validate board dimensions
9 if (board.length !== 3 || board.some(row => row.length !== 3)) {
10 throw new Error('Invalid board: must be 3x3');
11 }
12
13 // Count X's and O's
14 let xCount = 0;
15 let oCount = 0;
16
17 for (let i = 0; i < 3; i++) {
18 for (let j = 0; j < 3; j++) {
19 const cell = board[i][j];
20 if (cell === 'X') xCount++;
21 else if (cell === 'O') oCount++;
22 else if (cell !== ' ') {
23 throw new Error('Invalid board: contains invalid characters');
24 }
25 }
26 }
27
28 // Check who started by looking at the first non-empty position
29 let firstPlayer = null;
30 outer: for (let i = 0; i < 3; i++) {
31 for (let j = 0; j < 3; j++) {
32 if (board[i][j] === 'X') {
33 firstPlayer = 'X';
34 break outer;
35 } else if (board[i][j] === 'O') {
36 firstPlayer = 'O';
37 break outer;
38 }
39 }
40 }
41
42 // Edge Case: Invalid turn order - O started the game
43 if (firstPlayer === 'O') {
44 throw new Error('Wrong turn order: O started');
45 }
46
47 // Edge Case: Invalid turn order - X went twice in a row (more than one turn difference)
48 if (xCount > oCount + 1) {
49 throw new Error('Wrong turn order: X went twice');
50 }
51
52 // Edge Case: Invalid turn order - O went twice in a row
53 if (oCount > xCount && firstPlayer !== 'O') {
54 throw new Error('Wrong turn order: O went twice');
55 }
56
57 // Check for wins
58 const winPatterns = [
59 // Rows
60 [[0,0], [0,1], [0,2]],
61 [[1,0], [1,1], [1,2]],
62 [[2,0], [2,1], [2,2]],
63 // Columns
64 [[0,0], [1,0], [2,0]],
65 [[0,1], [1,1], [2,1]],
66 [[0,2], [1,2], [2,2]],
67 // Diagonals
68 [[0,0], [1,1], [2,2]],
69 [[0,2], [1,1], [2,0]]
70 ];
71
72 let xWins = false;
73 let oWins = false;
74
75 for (const pattern of winPatterns) {
76 const [a, b, c] = pattern;
77 const valA = board[a[0]][a[1]];
78 const valB = board[b[0]][b[1]];
79 const valC = board[c[0]][c[1]];
80
81 if (valA !== ' ' && valA === valB && valB === valC) {
82 if (valA === 'X') xWins = true;
83 else if (valA === 'O') oWins = true;
84 }
85 }
86
87 // Only check for consecutive moves if there's no win
88 if (!xWins && !oWins) {
89 // Check for consecutive moves by the same player in rows
90 for (let i = 0; i < 3; i++) {
91 for (let j = 0; j < 2; j++) {
92 if (board[i][j] !== ' ' && board[i][j] === board[i][j+1]) {
93 // Found consecutive moves by the same player
94 if (board[i][j] === 'X') {
95 throw new Error('Wrong turn order: X went twice');
96 } else {
97 throw new Error('Wrong turn order: O went twice');
98 }
99 }
100 }
101 }
102 }
103
104 // Edge Case: Game continued after win (both players have winning positions)
105 if (xWins && oWins) {
106 throw new Error('Impossible board: game should have ended after the game was won');
107 }
108
109 // Edge Case: Game continued after win (X won but O made an extra move)
110 if (xWins && oCount > xCount) {
111 throw new Error('Impossible board: game should have ended after the game was won');
112 }
113
114 // Edge Case: Game continued after win (O won but X made an extra move)
115 if (oWins && xCount > oCount + 1) {
116 throw new Error('Impossible board: game should have ended after the game was won');
117 }
118
119 // Determine game state
120 if (xWins || oWins) {
121 return 'win';
122 }
123
124 // Edge Case: Game is a draw (board is full with no winner)
125 if (xCount + oCount === 9) {
126 return 'draw';
127 }
128
129 // Edge Case: Game is ongoing (not won and not drawn)
130 return 'ongoing';
131
132 // Handled Edge Cases:
133 // - Invalid turn order (O started)
134 // - Invalid turn order (X went twice)
135 // - Game continued after win (both players won)
136 // - Game continued after win (X won but O kept playing)
137 // - Game continued after win (O won but X kept playing)
138 // - Game is a draw
139 // - Game is ongoing
140};
Test NameStatus
Finished game where X won via middle column victory
Fail
Finished game where X won via right column victory
Fail
Finished game where O won via left column victory
Fail
Finished game where X won via middle row victory
Fail
Finished game where X won via bottom row victory
Fail
Finished game where O won via top row victory
Fail
Finished game where X won via rising diagonal victory
Fail
Finished game where O won via falling diagonal victory
Fail
Finished game where O won via rising diagonal victory
Fail
Draw
Fail
Another draw
Fail
Ongoing game: two moves in
Fail
Finished game where X 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 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 a row and a column victory
Pass
Finished game where X won via two diagonal victories
Pass
Ongoing game: one move 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.