Skip to content

Instantly share code, notes, and snippets.

@ben-x9
Created January 5, 2017 08:33
Show Gist options
  • Save ben-x9/abf829bd85ea6dba87013073f6c5646a to your computer and use it in GitHub Desktop.
Save ben-x9/abf829bd85ea6dba87013073f6c5646a to your computer and use it in GitHub Desktop.
// Tic Tac Toe State Machine
// interface that implements the following function
// makeMove(r, c) -> one of the following enum values describing the state of the game after the given move.
// 1. INCOMPLETE - the given moven was valid, there remain open spaces, and there are no winners.
// 2. INVALID -- the previous play was out of bounds (0 < x < 2), or a piece already occupied the given position
// 3. X_WINS -- X is winning along either a row, column, or diagonal
// 4. O_WINS -- same as above except for O
// 5. STALEMATE -- the previous move was valid, there are no winners, but there remain open spaces.
// makeMove is called alternatingly by X and O players (X is first).
// You will need to keep state as consecutive plays are made; I don't care where or how, as long as you can reset it.
// globals, function, closure, class
// You can assume that after any of 2-5 is returned, no other plays will be made for that board.
let board, numMarks;
function resetBoard() {
board = [
[null, null, null],
[null, null, null],
[null, null, null]
];
numMarks = 0;
}
resetBoard();
function makeMove(row, col) {
if (invalidMove(row, col)) return 'INVALID';
const player = currentPlayer();
markBoard(player, row, col);
return moveResult(player, row, col);
}
const invalidMove = (row, col) =>
outOfRange(row, col) ||
isMarked(board[row][col]);
const currentPlayer = () =>
isEven(numMarks) ?
'X' :
'O';
function markBoard(player, row, col) {
board[row][col] = player;
numMarks++;
}
const moveResult = (player, row, col) =>
testWin(player, row, col) ?
player + '_WINS' :
numMarks === 9 ?
'STALEMATE' :
'INCOMPLETE';
const outOfRange = (row, col) =>
row < 0 || row > 2 ||
col < 0 || col > 2;
const isMarked = (x) =>
x !== null;
const isEven = (n) =>
n % 2 === 0
const testWin = (player, row, col) =>
testWinRow(player, row) ||
testWinCol(player, col) ||
testWinDiags(player);
const testWinRow = (player, row) =>
board[row][0] === player &&
board[row][1] === player &&
board[row][2] === player;
const testWinCol = (player, col) =>
board[0][col] === player &&
board[1][col] === player &&
board[2][col] === player;
const testWinDiags = (player) =>
testWinDiag1(player) ||
testWinDiag2(player);
const testWinDiag1 = (player) =>
board[0][0] === player &&
board[1][1] === player &&
board[2][2] === player;
const testWinDiag2 = (player) =>
board[0][2] === player &&
board[1][1] === player &&
board[2][0] === player;
function assertPlay(row, col, expected) {
expected = expected || 'INCOMPLETE';
const got = makeMove(row, col);
if (got !== expected) throw new Error("Got " + got + " Expected " + expected);
}
resetBoard();
assertPlay(0, 1);
assertPlay(-2, 1, 'INVALID');
resetBoard();
assertPlay(0, 2);
assertPlay(-2, 1, 'INVALID');
resetBoard();
assertPlay(1, 3, 'INVALID');
resetBoard();
assertPlay(1, -1, 'INVALID');
resetBoard();
assertPlay(2, 0);
assertPlay(1, 1);
assertPlay(2, 1);
assertPlay(1, 2);
assertPlay(2, 2, 'X_WINS');
resetBoard();
assertPlay(0, 0); // X
assertPlay(1, 1); // O
assertPlay(0, 2); // X
assertPlay(2, 1); // O
assertPlay(1, 2); // X
assertPlay(0, 1, 'O_WINS') // O
resetBoard();
assertPlay(1, 1);
assertPlay(1, 2);
assertPlay(0, 2);
assertPlay(2, 1);
assertPlay(2, 0, 'X_WINS');
resetBoard();
assertPlay(2, 1);
assertPlay(1, 1); // O
assertPlay(1, 2); // X
assertPlay(2, 2); // O
assertPlay(0, 1); // X
assertPlay(0, 0, 'O_WINS'); // O
resetBoard();
assertPlay(0, 0); // X
assertPlay(0, 1); // O
assertPlay(0, 2); // X
assertPlay(1, 2); // O
assertPlay(1, 0); // X
assertPlay(2, 0); // O
assertPlay(1, 1); // X
assertPlay(2, 2); // O
assertPlay(2, 1, 'STALEMATE'); // X
console.log('Success');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment