Last active
September 7, 2016 02:11
-
-
Save heatherbooker/5f80f1e46ba79bc628c3b56b72bdf45e to your computer and use it in GitHub Desktop.
Improved version of ticTacToe for command line
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
function chooseMove(board) { | |
function getAvailableLocations() { | |
var availableLocations = []; | |
for (var location in board) { | |
// Since key === value is the default, if this is true, | |
// it means the spot has not yet been played. | |
if (location === board[location]) { | |
availableLocations.push(location); | |
} | |
} | |
return availableLocations; | |
} | |
var locationToChose; | |
var counter = 0; | |
getAvailableLocations().forEach(function(location) { | |
// For the n-th location in the array, there is a 1/n chance of it being selected. | |
if (Math.random() < 1 / counter++) { | |
locationToChose = location; | |
} | |
}); | |
return locationToChose; | |
} | |
function takeTurn(board, symbol) { | |
return new Promise((resolve, reject) => { | |
// Pausing for a moment makes the game feel more natural. | |
setTimeout(function() { | |
var location = chooseMove(board); | |
board[location] = symbol; | |
resolve(); | |
}, 800); | |
}); | |
} | |
exports.takeTurn = takeTurn; |
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
module.exports = { | |
togglePlayer(player) { | |
if (player === '1') { | |
return '2'; | |
} | |
return '1'; | |
}, | |
checkStatus(board, counter) { | |
function isTied() { | |
return counter < 9 ? false : true; | |
} | |
var winner; | |
function checkForWinningStreak(board, triad) { | |
if (board[triad[0]] === board[triad[1]]) { | |
if (board[triad[1]] === board[triad[2]]) { | |
winner = board[triad[0]]; | |
return true; | |
} | |
} | |
return false; | |
} | |
function matchesWinningPattern() { | |
var triads = [['A1','A2','A3'], ['B1','B2','B3'], ['C1','C2','C3'], | |
['A1','B1','C1'], ['A2','B2','C2'], ['A3','B3','C3'], | |
['A1','B2','C3'], ['A3','B2','C1']]; | |
var matches = triads.filter(function(triad) { | |
return checkForWinningStreak(board, triad); | |
}); | |
return matches.length > 0; | |
} | |
if (matchesWinningPattern()) { | |
return 'Winner:' + winner + 's!'; | |
} else if (isTied()) { | |
return 'Tied'; | |
} else { | |
return false; | |
} | |
} | |
} |
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
module.exports = { | |
printBoard(board) { | |
console.log(` | |
${board.A1} | ${board.B1} | ${board.C1}\n | |
___|____|___\n | |
| | \n | |
${board.A2} | ${board.B2} | ${board.C2}\n | |
___|____|___\n | |
| | \n | |
${board.A3} | ${board.B3} | ${board.C3} | |
`); | |
}, | |
prompt(player, symbol, isVsComputer, rl) { | |
function getPrompt() { | |
if (isVsComputer) { | |
if (player === '2') { | |
return 'Computer\'s turn!'; | |
} | |
} | |
return `Player ${player} (${symbol} ), please enter the location you would like to play next: `; | |
} | |
rl.setPrompt(getPrompt()); | |
rl.prompt(); | |
} | |
} | |
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
var readline = require('readline'); | |
// Computer contains functions for one-player (vs. computer) games. | |
var computer = require('./computer.js'); | |
// Interface displays text to user. | |
var interface = require('./interface.js'); | |
// Games contains helper functions specific to the proceedings of the game. | |
var game = require('./game.js'); | |
var rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
function playTheGame(isVsComputer) { | |
var board = { | |
A1: 'A1', A2: 'A2', A3: 'A3', | |
B1: 'B1', B2: 'B2', B3: 'B3', | |
C1: 'C1', C2: 'C2', C3: 'C3' | |
}; | |
var playerMap = {'1': ' X', '2': ' O'}; | |
var currentPlayer = '1'; | |
var counter = 0; | |
interface.printBoard(board); | |
interface.prompt(currentPlayer, playerMap[currentPlayer], isVsComputer, rl); | |
// rl.on('line') callback will run every time user presses 'enter' key on keyboard. | |
rl.on('line', function(input) { | |
var location = input.toUpperCase(); | |
// The value should equal the key; otherwise, the location has already been played. | |
if (location === board[location]) { | |
board[location] = playerMap[currentPlayer]; | |
// afterEveryMove returns true to continue game, false if game is over. | |
if (afterEveryMove() && isVsComputer) { | |
// computer.takeTurn uses setTimeout with a promise. | |
computer.takeTurn(board, playerMap[currentPlayer]) | |
.then(() => { | |
afterEveryMove(); | |
}); | |
} | |
} else { | |
interface.printBoard(board); | |
console.log('You can\'t do that! Try again:'); | |
} | |
}); | |
function afterEveryMove() { | |
counter ++; | |
interface.printBoard(board); | |
var gameStatus = game.checkStatus(board, counter); | |
if (gameStatus) { | |
console.log('Game over!', gameStatus); | |
rl.close(); | |
return false; | |
} else { | |
currentPlayer = game.togglePlayer(currentPlayer); | |
interface.prompt(currentPlayer, playerMap[currentPlayer], isVsComputer, rl); | |
return true; | |
} | |
} | |
} | |
rl.question('To play against a friend, press 1; To play against the computer, press 2: ', function (response) { | |
if (response === '1') { | |
playTheGame(false); | |
} else { | |
playTheGame(true); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment