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 coin = ['_', 'X', 'O']
const range = n => Array(n + 1).join(1).split('').map((x, i) => i)
function end() {
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++
}
})
return verticalEnd || horizontalEnd || diagonalNW || diagonalNE
}
function print() {
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 place(i, j, p) {
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 (p < 1) return false
if (!game.board[i]) game.board[i] = []
if (game.board[i][j]) return false
return game.board[i][j] = p
}
const game = {
board: [],
width: 3,
height: 3,
win: 3,
}
let currentPlayer = 1;
while(!end()) {
print()
let i, j
do {
const inp = readLineSync(`Player "${coin[currentPlayer]}" (x y):`)
const split = inp.split(',').length < 2 ? inp.split(' ') : inp.split(',')
i = parseInt(split[0]), j = parseInt(split[1])
} while(!place(i, j, currentPlayer) && (console.log('Invalid move'), true))
currentPlayer++
if (currentPlayer > 2) currentPlayer = 1
}
print()
console.log(`\nGame over. Player "${coin[currentPlayer]}" won.\n`)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment