Skip to content

Instantly share code, notes, and snippets.

@zzzbra
Created January 5, 2020 04:10
Show Gist options
  • Save zzzbra/8a4f7c9401abd829b6a387ce888a820e to your computer and use it in GitHub Desktop.
Save zzzbra/8a4f7c9401abd829b6a387ce888a820e to your computer and use it in GitHub Desktop.
Tic Tac Toe
#!/usr/bin/env node
const readline = require("readline");
const boxen = require("boxen");
const NUM_ROWS = 3;
const NUM_COLS = 3;
// Set up game loop
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// track game state as 2d array
const getEmptyBoard = () => Array.from(Array(NUM_ROWS), () => Array.from(new Array(NUM_COLS)));
const INITIAL_GAME_STATE = {
board: getEmptyBoard(),
turn: 'o',
winner: undefined,
}
const getNextPlayer = (turn) => turn === 'o' ? 'x' : 'o';
// FIXME: DRY this out
const checkForWinner = (boardState) => {
const winningMoves = [
[[0,0], [0,1], [0,2]],
[[1,0], [1,1], [1,2]],
[[2,0], [2,1], [2,2]],
[[0,0], [1,0], [2,0]],
[[0,1], [1,1], [2,1]],
[[0,2], [1,2], [2,2]],
[[0,0], [1,1], [2,2]],
[[0,2], [1,1], [2,0]],
];
const theWinningMove = winningMoves.filter(combo => {
// TODO: put in helper function
return boardState[combo[0][0]][combo[0][1]] !== undefined
&& boardState[combo[0][0]][combo[0][1]] === boardState[combo[1][0]][combo[1][1]]
&& boardState[combo[1][0]][combo[1][1]] === boardState[combo[2][0]][combo[2][1]];
});
return theWinningMove.length > 0
&& boardState[theWinningMove[0][0][0]][theWinningMove[0][0][1]];
}
const makeMove = (x, y, gameState) => {
const {
board,
turn,
turn: playerSymbol,
} = gameState;
// if move already made only logging error and not advancing game state
if (board[x][y]) {
console.error('INVALID MOVE');
return gameState;
}
// Update position
board[x][y] = playerSymbol;
return {
...gameState,
turn: getNextPlayer(turn),
board,
}
}
// Main game engine
const getMove = (gameState) => {
const {
turn,
} = gameState;
rl.question(`It's ${turn}'s move: `, (coordinates) => {
// Assume input = 'x,y' for now
const [x, y] = coordinates.trim().split(',');
const newGameState = makeMove(x, y, gameState);
const { board } = newGameState;
renderBoard(board);
const winner = checkForWinner(board);
if (winner) {
console.log('We have a winner!!! Congratulations Player:', winner);
rl.close();
} else {
getMove(newGameState);
}
});
}
// pass in 2d array to re-render board with new state
const renderBoard = (movesPlayed) => {
const boxenOptions = {
padding: 1,
margin: 1,
borderStyle: "round",
borderColor: "green",
};
const board = movesPlayed.map(row =>{
return row.map(cell => {
return cell === undefined ? '_' : cell;
}).join(' ');
}).join('\n');
const gameBox = boxen(board, boxenOptions);
console.log(gameBox);
}
const initGame = () => {
const gameState = {
board,
} = INITIAL_GAME_STATE;
console.log('Please enter the (0-indexed) row and column you would like to play at. ');
renderBoard(board);
getMove(gameState);
}
initGame();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment