Skip to content

Instantly share code, notes, and snippets.

@bryanbraun
Last active May 23, 2019 14:33
Show Gist options
  • Save bryanbraun/9292bb57dab2e01aa59d02c5300d775f to your computer and use it in GitHub Desktop.
Save bryanbraun/9292bb57dab2e01aa59d02c5300d775f to your computer and use it in GitHub Desktop.
Tic Tac Term
// 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