Skip to content

Instantly share code, notes, and snippets.

@bigomega
Last active March 23, 2016 22:27
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 bigomega/86c67796b032f8fc74e6 to your computer and use it in GitHub Desktop.
Save bigomega/86c67796b032f8fc74e6 to your computer and use it in GitHub Desktop.
simple tic-tac-toe
'use strict'
const _utils = require('./_utils')
function getColumns(game) { return game.board }
function getRows(game) { return _utils.inverse2D(game.board) }
function getNWDiagonals(game) {
return _utils.range(game.width + game.height - 1).map(edge => {
// taking top and left edge
let i = edge < game.width ? edge : 0
let j = edge < game.width ? 0 : edge - game.width + 1
const arr = []
while(i < game.width && j < game.height) {
arr.push(game.board[i][j])
i++, j++
}
return arr
})
}
function getNEDiagonals(game) {
return _utils.range(game.width + game.height - 1).map(edge => {
// taking top and right edge
let i = edge < game.width ? edge : game.width - 1
let j = edge < game.width ? 0 : edge - game.width + 1
const arr = []
while(i >= 0 && j < game.height) {
arr.push(game.board[i][j])
i--, j++
}
return arr
})
}
function getItems(game) {
return getColumns(game).reduce((mem, column) => mem.concat(column), [])
}
module.exports = {
getColumns,
getRows,
getItems,
getNWDiagonals,
getNEDiagonals,
}
'use strict'
const fs = require('fs')
// util function modified from github.com/bucaran/sget
module.exports.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)))
}
module.exports.range = n => Array(n + 1).join(1).split('').map((x, i) => i)
module.exports.inverse2D = Arr => Arr[0].map((val, j) => Arr.map(column => column[j]))
'use strict'
const _utils = require('./_utils')
const _boardUtil = require('./_board-utils')
function initiateBoard(game) {
_utils.range(game.width).forEach(i => {
game.board[i] = []
_utils.range(game.height).forEach(j => game.board[i][j] = 0)
})
}
function end(game) {
const checkWin = Arr2D => Arr2D.some(list => {
const max = { p: 0, val: 0 }
return list.some(value => {
if (value && value === max.p) max.val++
else max.p = value, max.val = 1
return max.p && max.val >= game.win
})
})
const verticalEnd = checkWin(_boardUtil.getColumns(game))
const horizontalEnd = checkWin(_boardUtil.getRows(game))
const diagonalNW = checkWin(_boardUtil.getNWDiagonals(game))
const diagonalNE = checkWin(_boardUtil.getNEDiagonals(game))
const coinCount = _boardUtil.getItems(game).reduce((mem, value) => mem + Boolean(value))
const staleMate = coinCount >= game.width * game.height
return (staleMate && 'draw') || verticalEnd || horizontalEnd || diagonalNW || diagonalNE
}
function print(game) {
console.log('\x1B[2J\x1B[0f') // Clear screen
console.log([' '].concat(_utils.range(game.width)).join(' '));
_boardUtil.getRows(game).forEach((row, i) => {
console.log(i + ' ', row.map(value => coin[value] ).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(position, game) {
const x = position[0]
const y = position[1]
if (isNaN(x) || isNaN(y)) return false
if (x < 0 || x > game.width - 1) return false
if (y < 0 || y > game.height - 1) return false
if (game.currentPlayer < 1 || game.board[x][y]) return false
return game.board[x][y] = game.currentPlayer
}
function getInput(message, game) {
const text = _utils.readLineSync(message)
const split = text.split(',').length < 2 ? text.split(' ') : text.split(',')
return split.map(v => parseInt(v))
}
function switchPlayer(game, reverse) {
if(reverse) game.currentPlayer -= 1
else game.currentPlayer += 1
return game.currentPlayer = game.currentPlayer < 1 ? game.playerCount : 1
}
const coin = { 0: '_', 1: 'X', 2: 'O', 3: '#' }
;(function(){
let endState;
const game = {
board: [],
width: 3,
height: 3,
win: 3,
playerCount: 2,
currentPlayer: 1,
}
initiateBoard(game)
print(game)
while(!(endState = end(game))) {
const position = getInput(`Player "${coin[game.currentPlayer]}" (x y):`, game)
if (place(position, game)) {
print(game)
switchPlayer(game)
} else {
console.log('Invalid move')
}
}
switchPlayer(game, true)
printEnd(endState, game.currentPlayer)
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment