Skip to content
69 changes: 65 additions & 4 deletions __tests__/board-printer.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,67 @@
import { checkIfNoMovesLeft } from "../board-printer";
import { printBoard, checkIfNoMovesLeft } from "../board-printer"

test("checkIfNoMovesLeft should return true if there are no moves left", () => {
const board = [];
expect(checkIfNoMovesLeft(board)).toBe(true);
describe("printBoard", () => {
test("should print the formatted tic-tac-toe board correctly", () => {
const board = [
["X", "_", "_"],
["_", "X", "_"],
["O", "O", "X"],
];
const expectedOutput =
" X | | \n=================\n | X | \n=================\n O | O | X \n";

expect(printBoard(board)).toBe(expectedOutput);
});

test("should return an empty board when provided with an empty board", () => {
const board = [];
const expectedOutput =
" | | \n============= \n | | \n============= \n | | ";

expect(printBoard(board)).toBe(expectedOutput);
});

test("should handle a partially filled board", () => {
const board = [
["X", "_", "O"],
["_", "_", "_"],
["X", "O", "X"],
];
const expectedOutput =
" X | | O \n=================\n | | \n=================\n X | O | X \n";

expect(printBoard(board)).toBe(expectedOutput);
});
});

describe("checkIfNoMovesLeft", () => {
test("should return true if no moves are left", () => {
const board = [
["X", "O", "X"],
["O", "X", "O"],
["X", "O", "X"],
];
expect(checkIfNoMovesLeft(board)).toBe(true);
});

test("should return false if there are moves left", () => {
const board = [
["X", "_", "X"],
["O", "X", "O"],
["X", "O", "_"],
];
expect(checkIfNoMovesLeft(board)).toBe(false);
});

test("should throw an error if the board is not an array of arrays", () => {
const invalidBoard1 = "invalid format";
const invalidBoard2 = ["X", "O", "_"]; // Not an array of arrays

expect(() => checkIfNoMovesLeft(invalidBoard1)).toThrow(
"Invalid board format. Expected an array of arrays."
);
expect(() => checkIfNoMovesLeft(invalidBoard2)).toThrow(
"Invalid board format. Expected an array of arrays."
);
});
});
47 changes: 47 additions & 0 deletions __tests__/move-maker.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { makeMove } from "../move-maker";

let board;

beforeEach(() => {
// Reset the board before each test
board = [
['_', '_', '_'],
['_', '_', '_'],
['_', '_', '_']
];
});

test('allows a valid move and updates the board', () => {
const result = makeMove(board, '1,1', 'X');
expect(result).toBe(true);
expect(board[0][0]).toBe('X'); // Zero-based index for row and column
});

test('rejects a move outside the board boundaries', () => {
expect(makeMove(board, '4,1', 'X')).toBe(false); // Row out of bounds
expect(makeMove(board, '0,1', 'X')).toBe(false); // Row out of bounds
expect(makeMove(board, '1,4', 'X')).toBe(false); // Column out of bounds
expect(makeMove(board, '1,0', 'X')).toBe(false); // Column out of bounds
});

test('rejects a move in an occupied space', () => {
board[0][0] = 'X'; // Pre-occupy a cell
const result = makeMove(board, '1,1', 'O'); // Try to overwrite
expect(result).toBe(false);
expect(board[0][0]).toBe('X'); // Ensure the board didn't change
});

test('rejects invalid move formats', () => {
expect(makeMove(board, 'invalid', 'X')).toBe(false); // Non-numeric input
expect(makeMove(board, '1-1', 'X')).toBe(false); // Wrong delimiter
expect(makeMove(board, '1,', 'X')).toBe(false); // Missing column
expect(makeMove(board, ',1', 'X')).toBe(false); // Missing row
});

test('allows moves on the edges of the board', () => {
expect(makeMove(board, '1,3', 'O')).toBe(true); // Top-right corner
expect(board[0][2]).toBe('O'); // Check board update

expect(makeMove(board, '3,1', 'X')).toBe(true); // Bottom-left corner
expect(board[2][0]).toBe('X'); // Check board update
});
64 changes: 64 additions & 0 deletions __tests__/status-checker.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@

import { isGameOver } from "../status-checker";
let board;
beforeEach(() => {
board = [
['_', '_', '_'],
['_', '_', '_'],
['_', '_', '_']
];
});


test('Player X wins on a row', () => {
board = [
['X', 'X', 'X'],
['_', '_', '_'],
['O', 'O', '_']
];
expect(isGameOver(board)).toBe(true); // X has won the game!
});
test('Player X wins on a row', () => {
board = [
['X', 'X', 'X'],
['_', '_', '_'],
['O', 'O', '_']
];
expect(isGameOver(board)).toBe(true); // X has won the game!
});

test('Game is a draw!', () => {
board = [
['O', '_', '_'],
['X', '_', 'O'],
['X', '_', 'O']
];
expect(isGameOver(board)).toBe(false); // Game is a draw!
});

test('Player X wins on a diagonal', () => {
board = [
['X', '_', 'O'],
['_', 'X', '_'],
['O', '_', 'X']
];
expect(isGameOver(board)).toBe(true); // X has won the game!
});

test('Tie game', () => {
board = [
['X', 'O', 'X'],
['O', 'X', 'O'],
['O', 'X', 'X']
];
expect(isGameOver(board)).toBe(true); // Game Over - It's a tie!
});

test('Game is not over yet', () => {
board = [
['X', '_', 'O'],
['_', '_', '_'],
['O', '_', '_']
];
expect(isGameOver(board)).toBe(false); // Game is still ongoing
});
38 changes: 38 additions & 0 deletions board-printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,50 @@
Test your function by calling it with an example tic-tac-toe board.
*/
export function printBoard(board) {
if (Array.isArray(board) && board.length === 0) {
return ` | |
=============
| |
=============
| | `;
}

let result = "";

for (let i = 0; i < board.length; i++) {
let row = board[i].map((cell) => (cell === "_" ? " " : cell)).join(" | ");
result += ` ${row} \n`;
if (i < board.length - 1) {
result += "=================\n";
}
}

return result;
}

console.log(
printBoard([
["X", "_", "_"],
["_", "X", "_"],
["O", "O", "X"],
])
);


/*
Given a tic-tac-toe board (an array of arrays),
- return true if there are no moves left to make (there are no more '_' values)
- return false if there are still moves that can be made
*/
export function checkIfNoMovesLeft(board) {
if (!Array.isArray(board) || board.some((row) => !Array.isArray(row))) {
throw new Error("Invalid board format. Expected an array of arrays.");
}

for (let i = 0; i < board.length; i++) {
if (board[i].includes("_")) {
return false;
}
}
return true;
}
24 changes: 22 additions & 2 deletions move-maker.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,18 @@
];
*/
function validateMove(move, board) {
// Implement this at the end if you have time, otherwise you can help your teammates!
const [row, col] = move.split(',').map(Number);
if (isNaN(row) || isNaN(col) || row < 1 || row > 3 || col < 1 || col > 3) {
console.log('Try again...');
return false;
}
const rowIndex = row - 1;
const colIndex = col - 1;

if (board[rowIndex][colIndex] !== '_') {
console.log('Try again...');
return false;
}
return true;
}

Expand All @@ -32,5 +43,14 @@ function validateMove(move, board) {
- Return true
*/
export function makeMove(board, move, player) {
return false;
if (!validateMove(move, board)) {
return false;
}
const [row, col] = move.split(',').map(Number);
const rowIndex = row - 1;
const colIndex = col - 1;

board[rowIndex][colIndex] = player;

return true;
}
Loading