UNPKG

tictactoejs

Version:

provide a library like chess.js but for tic tac toe.. you can make your own GUI

235 lines (193 loc) 5.38 kB
/* * @license * Copyright (c) 2016 ryan hs <mr.ryansilalahi@gmail.com> * MIT License * https://github.com/ryanhs/TicTacToeJS.git */ (function(){ 'use strict'; var TicTacToe = function(requestSize){ var game = {}, size = 3, board = [], moveCount = 1, history = [], statusCache = [moveCount, 'in progress'], legalMovesCache = [0, []] ; game.reset = function(requestSize){ if(parseInt(requestSize) >= 3) size = requestSize; var tmp = [], i, j; board = []; for(i = 0; i < size; i++){ tmp = []; for(j = 0; j < size; j++) tmp.push(null); board.push(tmp); } moveCount = 1; history = []; } game.getSize = function(){ return size; } game.turn = function(){ return moveCount % 2 == 0 ? 'O' : 'X'; } game.ascii = function(){ var o = '', i, j; for(i = 0; i < size; i++){ for(j = 0; j < size; j++){ if(j == 0) o += ' '; o += board[i][j] == null ? ' ' : board[i][j]; if(j < size - 1) o += ' | '; } if(i < size - 1) o += "\r\n" + '-'.repeat(size * 4 - 1) + "\r\n"; } return o; } game.ascii2 = function(){ var o = '', i, j; for(i = 0; i < size; i++){ for(j = 0; j < size; j++){ if(j == 0) o += (size - i) + ' '; o += ' '; o += board[i][j] == null ? '.' : board[i][j]; o += ' '; } o += "\r\n"; } o += " "; for(j = 0; j < size; j++) o += (j + 1) + ' '; return o; } /* * default move * move with Cartesian coordinate system, but array still in normal style :-) * * usually board game like chess using cartesian coordinate, but x in alphabet * since tic tac toe have no formal notation, lets use this * * 1,3 | 2,3 | 3,3 * --------------- * 1,2 | 2,2 | 3,2 * --------------- * 1,1 | 2,1 | 3,1 * */ game.move = function(x, y){ x--; y = Math.abs(y - size); if(y < 0 || y >= size || x < 0 || x >= size) return false; if(board[y][x] != null) return false; board[y][x] = game.turn(); moveCount++; return true; } /* * exists x, y */ game.exists = function(x, y){ x--; y = Math.abs(y - size); if(y < 0 || y >= size || x < 0 || x >= size) return false; return board[y][x] != null; } /* * move with Array style * 0,0 | 0,1 | 0,2 * --------------- * 1,0 | 1,1 | 1,2 * --------------- * 2,0 | 2,1 | 2,2 * */ game.moveArray = function(row, col){ if(row < 0 || row >= size || col < 0 || col >= size) return false; if(board[row][col] != null) return false; board[row][col] = game.turn(); moveCount++; return true; } /* * return "X" or "O" or "draw" or "in progress" * */ function status(){ var i, j, Xh, Oh, // X O horizontal Xv, Ov, // X O vertical Xd1, Od1, // diagonal \ Xd2, Od2, // diagonal / draw = true; Xh = Oh = Xv = Ov = Xd1 = Od1 = Xd2 = Od2 = 0; for(i = 0; i < size; i++){ // horizontal&vertical reset Xh = Oh = Xv = Ov = 0; for(j = 0; j < size; j++){ // draw checker if(board[i][j] == null) draw = false; // horizontal check if(board[i][j] == 'X') Xh++; if(board[i][j] == 'O') Oh++; // vertical check if(board[j][i] == 'X') Xv++; if(board[j][i] == 'O') Ov++; } // horizontal&vertical breaker if(Xh == size || Xv == size) return 'X'; if(Oh == size || Ov == size) return 'O'; // diagonal \ checker if(board[i][i] == 'X') Xd1++; if(board[i][i] == 'O') Od1++; // diagonal / checker if(board[i][size - i - 1] == 'X') Xd2++; if(board[i][size - i - 1] == 'O') Od2++; } // diagonal breaker if(Xd1 == size || Xd2 == size) return 'X'; if(Od1 == size || Od2 == size) return 'O'; return draw ? 'draw' : 'in progress'; } game.status = function(){ if(statusCache[0] == moveCount) return statusCache[1]; statusCache[0] = moveCount; statusCache[1] = status(); return game.status(); // hmm } game.gameOver = function(){ return game.status() != 'in progress'; } game.isDraw = function(){ return game.status() == 'draw'; } /* * some functions here is usefull for something like AI * */ /* * legal moves Cartesian Style * */ game.legalMoves = function(){ if(legalMovesCache[0] == moveCount) return legalMovesCache[1]; var x, y, moves = []; for(y = 0; y < size; y++){ for(x = 0; x < size; x++){ //~ x--; //~ y = Math.abs(y - size); if(board[y][x] == null) moves.push({'x': x + 1, 'y': size - y}); } } legalMovesCache[0] = moveCount; legalMovesCache[1] = moves; return game.legalMoves(); // hmm } /* * AI moves, just random :-p * */ game.randomMove = function(){ var move = game.legalMoves()[Math.floor(Math.random() * game.legalMoves().length)] game.move(move.x, move.y); return move; } game.reset(requestSize); return game; } if(typeof exports !== 'undefined') exports.TicTacToe = TicTacToe; if(typeof window !== 'undefined') window.TicTacToe = TicTacToe; })()