Skip to content

Instantly share code, notes, and snippets.

@bigomega
Last active March 23, 2016 22:27
Show Gist options
  • Select an option

  • Save bigomega/86c67796b032f8fc74e6 to your computer and use it in GitHub Desktop.

Select an option

Save bigomega/86c67796b032f8fc74e6 to your computer and use it in GitHub Desktop.
simple tic-tac-toe
'use strict'
const fs = require('fs')
// util function modified from github.com/bucaran/sget
const readLineSync = function(message) {
message = message || ''
const win32 = () => 'win32' === process.platform
const readSync = function(buffer) {
var fd = win32() ? process.stdin.fd : fs.openSync('/dev/stdin', 'rs')
var bytes = fs.readSync(fd, buffer, 0, buffer.length)
if (!win32()) fs.closeSync(fd)
return bytes
}
return (function(buffer) {
try {
process.stdout.write(message + ' ')
return buffer.toString(null, 0, readSync(buffer))
} catch (e) {
throw e
}
}(new Buffer(256)))
}
const range = n => Array(n + 1).join(1).split('').map((x, i) => i)
function end(game) {
const verticalEnd = range(game.width).some(i => {
const column = game.board[i] || []
const max = { p: 0, val: 0 }
return range(game.height).some(j => {
const value = column[j]
if (value && value === max.p) max.val++
else max.p = value, max.val = 1
return max.p && max.val >= game.win
})
})
const horizontalEnd = range(game.height).some(j => {
const max = { p: 0, val: 0 }
return range(game.width).some(i => {
const value = (game.board[i] || [])[j]
if (value && value === max.p) max.val++
else max.p = value, max.val = 1
return max.p && max.val >= game.win
})
})
const diagonalNW = range(game.width + game.height - 1).some(k => {
// taking top and left edge
let i = k < game.width ? k : 0
let j = k < game.width ? 0 : k - game.width + 1
const max = { p: 0, val: 0 }
while(i < game.width && j < game.height) {
const value = (game.board[i] || [])[j]
if (value && value === max.p) max.val++
else max.p = value, max.val = 1
if (max.p && max.val >= game.win) return true
i++, j++
}
})
const diagonalNE = range(game.width + game.height - 1).some(k => {
// taking top and right edge
let i = k < game.width ? k : game.width - 1
let j = k < game.width ? 0 : k - game.width + 1
const max = { p: 0, val: 0 }
while(i >= 0 && j < game.height) {
const value = (game.board[i] || [])[j]
if (value && value === max.p) max.val++
else max.p = value, max.val = 1
if (max.p && max.val >= game.win) return true
i--, j++
}
})
const coinCount = range(game.width).reduce((mem, i) => (
mem + range(game.height).reduce((deepMem, j) => (
deepMem + Boolean((game.board[i] || [])[j])
), 0)
), 0)
return (coinCount >= game.width * game.height && 'draw') || verticalEnd || horizontalEnd || diagonalNW || diagonalNE
}
function print(game) {
console.log('\x1B[2J\x1B[0f') // Clear screen
// x index
console.log([' '].concat(range(game.width)).join(' '));
range(game.height).map(j => {
console.log(
j + ' ', // y index
range(game.width).map(i => coin[(game.board[i] || [])[j] || 0] ).join(' ')
)
})
console.log('')
}
function printEnd(state, currentPlayer) {
if(state === 'draw') console.log('Game over. The game ended in a draw.\n')
else console.log(`Game over. Player "${coin[currentPlayer]}" won.\n`)
}
function place(i, j, game) {
if (isNaN(i) || isNaN(j)) return false
if (i < 0 || i > game.width - 1) return false
if (j < 0 || j > game.height - 1) return false
if (game.currentPlayer < 1) return false
if (!game.board[i]) game.board[i] = []
if (game.board[i][j]) return false
return game.board[i][j] = game.currentPlayer
}
function parse(text, game) {
const split = text.split(',').length < 2 ? text.split(' ') : text.split(',')
return split.map(v => parseInt(v))
}
function switchPlayer(game) {
game.currentPlayer++
if (game.currentPlayer > 2) game.currentPlayer = 1
}
const coin = { 0: '_', 1: 'X', 2: 'O' }
;(function(){
let endState;
const game = {
board: [],
width: 3,
height: 3,
win: 3,
currentPlayer: 1,
}
print(game)
while(!(endState = end(game))) {
const position = parse(readLineSync(`Player "${coin[game.currentPlayer]}" (x y):`), game)
if(place(position[0], position[1], game)) {
print(game)
switchPlayer(game)
} else {
console.log('Invalid move')
}
}
printEnd(endState, game.currentPlayer)
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment