Created
January 5, 2020 04:10
-
-
Save zzzbra/8a4f7c9401abd829b6a387ce888a820e to your computer and use it in GitHub Desktop.
Tic Tac Toe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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