Last active
May 23, 2019 14:33
-
-
Save bryanbraun/9292bb57dab2e01aa59d02c5300d775f to your computer and use it in GitHub Desktop.
Tic Tac Term
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
// Tic Tac Term! | |
// | |
// A 2-player Tic Tac Toe game, played in the terminal | |
// (written in JavaScript 💪) | |
// Set up user prompt interface. | |
const rl = require("readline").createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}) | |
// Set up the game state. | |
let currentPlayer = "x"; | |
let gameover = false; | |
let board = | |
[["", "", ""], | |
["", "", ""], | |
["", "", ""]]; | |
// Start the game! | |
(async function play() { | |
console.log(`Welcome to Tic Tac Term. 👋`) | |
printBoard(board); | |
while (!gameover) { | |
var { row, column } = await promptUser(currentPlayer, board); | |
board[row][column] = currentPlayer; | |
printBoard(board); | |
if (isHorizontalWin(board) || isVerticalWin(board) || isDiagonalWin(board)) { | |
console.log(`${currentPlayer} is the winner. Congrats! 🎉`); | |
gameover = true; | |
} else if (isBoardFull(board)) { | |
console.log(`The game is a draw!`); | |
gameover = true; | |
} | |
currentPlayer = switchPlayer(currentPlayer); | |
} | |
rl.close(); | |
})(); | |
// GAME FUNCTIONS | |
function printBoard(board) { | |
console.log(` | |
A B C | |
1 ${board[0][0] || ' '} | ${board[0][1] || ' '} | ${board[0][2] || ' '} | |
---|---|--- | |
2 ${board[1][0] || ' '} | ${board[1][1] || ' '} | ${board[1][2] || ' '} | |
---|---|--- | |
3 ${board[2][0] || ' '} | ${board[2][1] || ' '} | ${board[2][2] || ' '} | |
`); | |
} | |
async function promptUser(currentPlayer, board) { | |
const validCells = /^[a-cA-C][1-3]$/; | |
console.log(`It's ${currentPlayer}'s turn.`); | |
const cellRef = await ask(`Where do you want to place your piece? `); | |
if (!validCells.test(cellRef)) { | |
console.log(``); | |
console.log(`🚨 D'oh! That's not a valid location.`); | |
console.log(`Valid locaitons include a letter followed by a number, like "A1", or "C3".`); | |
console.log(``); | |
printBoard(board); | |
return await promptUser(currentPlayer, board); | |
} | |
const { row, column } = convertCellRefToMatrixLocation(cellRef); | |
const cellContent = board[row][column]; | |
if (cellContent) { | |
console.log(``); | |
console.log(`🚨 Oops. That space is occupied. 😅`); | |
console.log(``); | |
printBoard(board); | |
return await promptUser(currentPlayer, board); | |
} | |
return { row, column }; | |
} | |
function switchPlayer(currentPlayer) { | |
return (currentPlayer === "x") ? "o" : "x"; | |
} | |
function isBoardFull(board) { | |
for (var row = 0; row < board.length; row++) { | |
for (var col = 0; col < board[row].length; col++) { | |
if (!board[row][col]) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
function isHorizontalWin(board) { | |
var sameValues, | |
isWin = false; | |
board.forEach(row => { | |
sameValues = row.every((cell, index, row) => cell === row[0]); | |
if (sameValues && !!row[0]) { | |
isWin = true; | |
} | |
}); | |
return isWin; | |
} | |
function isVerticalWin(board) { | |
var sameValues, | |
isWin = false; | |
board[0].forEach((topRowlVal, colIndex) => { | |
sameValues = board | |
.map(row => row[colIndex]) | |
.every((value, index, array) => value === array[0]); | |
if (sameValues && !!topRowlVal) { | |
isWin = true; | |
} | |
}); | |
return isWin; | |
} | |
function isDiagonalWin(board) { | |
const downLeftWin = | |
(board[0][0] === board[1][1] && | |
board[1][1] === board[2][2] && | |
!!board[2][2] === true); | |
const downRightWin = | |
(board[0][2] === board[1][1] && | |
board[1][1] === board[2][0] && | |
!!board[2][0] === true); | |
return downLeftWin || downRightWin; | |
} | |
function convertCellRefToMatrixLocation(cellref) { | |
const matrixMap = { | |
// Column numbers | |
"A": 0, "a": 0, | |
"B": 1, "b": 1, | |
"C": 2, "c": 2, | |
// Row numbers | |
"1": 0, | |
"2": 1, | |
"3": 2 | |
}; | |
return { | |
row: matrixMap[cellref[1]], | |
column: matrixMap[cellref[0]] | |
}; | |
} | |
// A convenince function for working with node's readline | |
// tool to prompt the user via the terminal. | |
function ask(question) { | |
return new Promise(resolve => { | |
rl.question(question, resolve); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment