Skip to content

Instantly share code, notes, and snippets.

@spitis
Last active October 18, 2015 23:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spitis/47a243774808a9c124f9 to your computer and use it in GitHub Desktop.
Save spitis/47a243774808a9c124f9 to your computer and use it in GitHub Desktop.
Simple node tictactoe
var assert = require('assert');
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function game() {
var board = [
0,0,0,
0,0,0,
0,0,0];
var turn = 1; //1 is player 1, -1 is player 2
var gameOn = 0; //0 is a no game (newgame needs to be called); 1 is game
var compTurn = 0;
//returns true if any column or row contains all "player"
function checkColRow (player, board) {
var i, j;
var colCt = 0, rowCt = 0;
for (j = 0; j < 3; j++) {
for (i = 0; i < 3; i++) {
//check column i (e.g., indexes 0, 3, 6)
colCt += board[j + 3*i];
//check row j (e.g., index 0, 1, 2)
rowCt += board[3*j + i];
}
if ((colCt === 3*player) || (rowCt === 3*player)) {return true;}
colCt = 0; rowCt = 0;
}
return false;
}
assert(checkColRow(-1, [1,0,0, 0,1,0, 0,0,1]) === false);
assert(checkColRow(1, [1,0,0, 1,1,0, 1,0,1]) === true);
assert(checkColRow(-1, [0,0,-1, 0,1,-1, 0,0,-1]) === true);
assert(checkColRow(-1, [1,0,-1, -1,-1,-1, -1,0,1]) === true);
assert(checkColRow(-1, [0,0,0, 0,0,0, 0,0,0]) === false);
assert(checkColRow(1, [0,0,0, 1,1,1, 0,0,0]) === true);
//returns true if a diagonal contains all "player"
function checkDiag (player, board) {
var diagCt = 0, i;
//check 2, 4, 6 diagonal
for (i = 2; i< 7; i+=2) {
diagCt += board[i];
}
//check 0, 4, 8 diagonal
if (diagCt === 3*player) {return true;}
diagCt = 0;
for (i = 0; i<9; i+=4) {
diagCt += board[i];
}
return (diagCt === 3*player) ? true:false;
}
assert(checkDiag(-1, [1,0,0, 0,1,0, 0,0,1]) === false);
assert(checkDiag(1, [1,0,0, 0,1,0, 0,0,1]) === true);
assert(checkDiag(-1, [0,0,0, 0,1,0, 0,0,1]) === false);
assert(checkDiag(-1, [1,0,-1, 0,-1,0, -1,0,1]) === true);
function checkVictor (player,board) {
return checkColRow (player,board) || checkDiag (player,board);
}
function checkDraw (board) {
var i;
for (i = 0; i < 9; i++) {
if (board[i] === 0) return false;
}
return true;
}
function tryMove (player, x, y) {
if (x>3) {throw "illegal move";}
var idx = (3*(y-1) + x - 1);
if (board[idx] === 0) {
board[idx] = player;
} else {
throw "illegal move";
}
}
//an actual move on the board
function move(y, x) {
try {
if (gameOn === 1) {
tryMove(turn, x, y);
printBoard(board);
if (checkVictor(turn, board)) {
console.log('Player ' + (turn === 1 ? "X" : "O") + ' wins!');
//player wins
gameOn = 0;
turn = 0;
} else if (checkDraw(board)) {
gameOn = 0;
turn = 0;
console.log("Draw game!");
} else {
turn = turn * -1;
if (compTurn === turn) {
console.log("Computer moves:");
moveComp();
} else {
console.log('Player ' + (turn === 1 ? "X" : "O") + ' to move.');
}
}
} else {
console.log("No game is running. Use function newGame() to start a new game.");
}
} catch (e) {
console.log("Illegal move. Try again.");
}
}
//a hypothetical move function, takes a move, a board, and returns a board
//assumes the move is legal
function hypoMove(player,y,x,board) {
var idx = (3*(x-1) + y - 1);
var newBoard = board.slice(0);
newBoard[idx] = player;
return newBoard;
}
//returns the winning move, if there is one
function winningMove(player,legalMoves,board) {
var i, move;
for (i = 0; i < legalMoves.length; i++) {
move = legalMoves[i];
if (checkVictor(player,hypoMove(player,move[0],move[1],board))) {
return move;
}
}
return false;
}
function legalMoves (board) {
var i;
var arr = [];
for (i = 0; i < board.length; i++) {
if (board[i]===0) {
arr.push([Math.floor((i/3)) +1, i % 3 +1]);
}
}
return arr;
}
assert(legalMoves([1,1,0, 1,1,1, 1,0,1])[0][0] === 1);
assert(legalMoves([1,1,0, 1,1,1, 1,0,1])[0][1] === 3);
assert(legalMoves([1,1,0, 1,1,1, 1,0,1])[1][0] === 3);
assert(legalMoves([1,1,0, 1,1,1, 1,0,1])[1][1] === 2);
function moveComp() {
var moves = legalMoves(board);
var compMove = winningMove(turn,moves.slice(0),board) || moves[Math.floor(Math.random() * moves.length)];
move(compMove[0], compMove[1]);
}
function clearBoard () {
board = [0,0,0,0,0,0,0,0,0];
}
function newGame (arg) {
console.log();
console.log("******************");
console.log();
console.log("Starting new game.");
turn = 1;
gameOn = 1;
compPlayer = 0;
clearBoard();
if (arg === "comp") {
compTurn = Math.random() > 0.5 ? 1 : -1;
}
if (compTurn === turn) {
console.log("Computer moves first:");
moveComp();
} else {
printBoard(board);
console.log();
console.log("Player X to move. Use function move(row,col) to move.");
console.log();
}
}
function XO (x) {
return (x===1) ? "X": (x===-1) ? "O" : " ";
}
function printBoard (board) {
var i;
console.log(" |_1_|_2_|_3_|");
for (i = 1; i < 8; i+=3 ) {
console.log((i+2)/3 +': | ' + XO(board[i-1]) + ' | ' + XO(board[i]) + ' | ' + XO(board[i+1]) + ' |');
}
}
var gameExport = {
newGame: newGame,
move: move,
moveComp: moveComp
};
return gameExport;
}
var game = game();
var newGame = game.newGame;
var move = game.move;
var moveComp = game.moveComp;
function quit() {
rl.close();
rl = null;
}
function repl () {
rl && rl.question("",function (input) {
try {
eval(input);
} catch (e) {
console.log(e);
} finally {
repl();
}
});
}
console.log("*************************************************************");
console.log("*** TIC TAC TOE ***");
console.log("*************************************************************");
console.log("*** Instructions: ***");
console.log("*** newGame(): starts a new game ***");
console.log("*** newGame('comp'): new game against a compute ***");
console.log("*** move(y,x): make move at row y and col x ***");
console.log("*************************************************************");
newGame();
repl();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment