function colourValue(value) { return value < 4; } function parsePosition(str) { if (str.length != 2) return null; var a = str.toUpperCase().charCodeAt(0), b = str.charCodeAt(1); if (a < 65 || a > 65+25) return null; if (b < 48 || b > 48+9) return null; return N * (N - (b - 48)) + a - 65; } function parseMove(str) { if (str.length != 5) return null; if (str[2] != "-" && str[2] != " ") return null; var from, to; from = parsePosition(str.substr(0, 2)); if (from != null) { to = parsePosition(str.substr(3, 2)); if (to != null) { return {from: from, to: to}; } } return null; } function stringifyPosition(pos) { return String.fromCharCode(65 + pos % N) + String.fromCharCode(48 + N - ~~(pos / N)); } function stringifyMove(mv) { return stringifyPosition(mv.from) + '-' + stringifyPosition(mv.to); } function stringifyMoveExt(mv, captures) { var s = stringifyMove(mv); if (captures.length > 0) { for (var i = 0; i < captures.length; i++) { s += (i == 0 ? "x" : "/") + stringifyPosition(captures[i]); } } return s; } function stoneFlankedH(pos, by) { if (by & (WHITE|KING)) by = WHITE|KING; return ((board[pos-1] & by) || (pos-1 == BOARDMID && board[BOARDMID] == EMPTY)) && ((board[pos+1] & by) || (pos+1 == BOARDMID && board[BOARDMID] == EMPTY)); } function stoneFlankedV(pos, by) { if (by & (WHITE|KING)) by = WHITE|KING; return ((board[pos-N] & by) || (pos-N == BOARDMID && board[BOARDMID] == EMPTY)) && ((board[pos+N] & by) || (pos+N == BOARDMID && board[BOARDMID] == EMPTY)); } function kingEncircled(pos) { if (pos == BOARDMID) { return board[pos-1] == BLACK && board[pos+1] == BLACK && board[pos-N] == BLACK && board[pos+N] == BLACK; } else if (pos == BOARDMID-1) { return board[pos-1] == BLACK && board[pos-N] == BLACK && board[pos+N] == BLACK; } else if (pos == BOARDMID+1) { return board[pos+1] == BLACK && board[pos-N] == BLACK && board[pos+N] == BLACK; } else if (pos == BOARDMID-N) { return board[pos-1] == BLACK && board[pos+1] == BLACK && board[pos-N] == BLACK; } else if (pos == BOARDMID+N) { return board[pos-1] == BLACK && board[pos+1] == BLACK && board[pos+N] == BLACK; } else { var x = pos % N, y = ~~(pos / N); return (x > 0 && x < N-1 && board[pos-1] == BLACK && board[pos+1] == BLACK) || (y > 0 && y < N-1 && board[pos-N] == BLACK && board[pos+N] == BLACK); } } function applyMove(mv) { board[mv.to] = board[mv.from]; board[mv.from] = EMPTY; var i = mv.to; var x = i % N, y = ~~(i / N); var captures = []; if (x > 1 && board[i-1] != EMPTY && colourValue(board[i-1]) != colourValue(board[i])) { if (board[i-1] == KING ? kingEncircled(i-1) : stoneFlankedH(i-1, board[i])) { board[i-1] = EMPTY; captures.push(i-1); } } if (y > 1 && board[i-N] != EMPTY && colourValue(board[i-N]) != colourValue(board[i])) { if (board[i-N] == KING ? kingEncircled(i-N) : stoneFlankedV(i-N, board[i])) { board[i-N] = EMPTY; captures.push(i-N); } } if (x < N-2 && board[i+1] != EMPTY && colourValue(board[i+1]) != colourValue(board[i])) { if (board[i+1] == KING ? kingEncircled(i+1) : stoneFlankedH(i+1, board[i])) { board[i+1] = EMPTY; captures.push(i+1); } } if (y < N-2 && board[i+N] != EMPTY && colourValue(board[i+N]) != colourValue(board[i])) { if (board[i+N] == KING ? kingEncircled(i+N) : stoneFlankedV(i+N, board[i])) { board[i+N] = EMPTY; captures.push(i+N); } } return captures; } function checkWin() { for (var x = 0; x < N; x++) if (board[x] == KING) return 1; for (var y = 0; y < N; y++) if (board[N * y] == KING) return 1; for (var x = 0; x < N; x++) if (board[N * (N-1) + x] == KING) return 1; for (var y = 0; y < N; y++) if (board[N * y + N-1] == KING) return 1; for (var i = 0; i < N * N; i++) { if (board[i] == KING) return 0; } return -1; } function isValid(mv) { if (mv.from < 0 || mv.from >= N * N || mv.to < 0 || mv.to >= N * N) return false; if (mv.from == mv.to) return false; if (board[mv.from] == EMPTY || board[mv.to] != EMPTY) return false; if (mv.to == BOARDMID) return false; var x1 = mv.from % N, y1 = ~~(mv.from / N); var x2 = mv.to % N, y2 = ~~(mv.to / N); if (x1 != x2 && y1 != y2) return false; if (x1 == x2) { var delta = y2 < y1 ? -1 : 1; for (var y = y1 + delta; y != y2; y += delta) { if (board[N * y + x1] != EMPTY) return false; } } else { var delta = x2 < x1 ? -1 : 1; for (var x = x1 + delta; x != x2; x += delta) { if (board[N * y1 + x] != EMPTY) return false; } } return true; } function isValidForPlayer(mv, player) { var mask = player == 1 ? WHITE|KING : BLACK; return isValid(mv) && (board[mv.from] & mask) != 0; }