UNPKG

@wirelineio/shogiboardjsx

Version:

Shogiboardjsx is a shogiboard for React. Inspired by Chessboardjsx

163 lines (124 loc) 5.22 kB
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } import diff from 'deep-diff'; export var ItemTypes = { PIECE: 'piece' }; export var COLUMNS = 'abcdefghi'.split(''); export var constructPositionAttributes = function constructPositionAttributes(currentPosition, position) { var difference = diff(currentPosition, position); var squaresAffected = difference.length; var sourceSquare = difference && difference[1] && difference && difference[1].kind === 'D' ? difference[1].path && difference[1].path[0] : difference[0].path && difference[0].path[0]; var targetSquare = difference && difference[1] && difference && difference[1].kind === 'D' ? difference[0] && difference[0].path[0] : difference[1] && difference[1].path[0]; var sourcePiece = difference && difference[1] && difference && difference[1].kind === 'D' ? difference[1] && difference[1].lhs : difference[1] && difference[1].rhs; return { sourceSquare: sourceSquare, targetSquare: targetSquare, sourcePiece: sourcePiece, squaresAffected: squaresAffected }; }; function isString(s) { return typeof s === 'string'; } export function fenToObj(fen) { if (!validFen(fen)) return false; // cut off any move, castling, etc info from the end // we're only interested in position information fen = fen.replace(/ .+$/, ''); var rows = fen.split('/'); var position = {}; var currentRow = 9; for (var i = 0; i < 9; i++) { var row = rows[i].split(''); var colIdx = 0; // loop through each character in the FEN section for (var j = 0; j < row.length; j++) { // number / empty squares if (row[j].search(/[1-9]/) !== -1) { var numEmptySquares = parseInt(row[j], 10); colIdx = colIdx + numEmptySquares; } else { // piece var square = COLUMNS[colIdx] + currentRow; position[square] = fenToPieceCode(row[j]); colIdx = colIdx + 1; } } currentRow = currentRow - 1; } return position; } function expandFenEmptySquares(fen) { return fen.replace(/9/g, '111111111').replace(/8/g, '11111111').replace(/7/g, '1111111').replace(/6/g, '111111').replace(/5/g, '11111').replace(/4/g, '1111').replace(/3/g, '111').replace(/2/g, '11'); } export function validFen(fen) { if (!isString(fen)) return false; // cut off any move, castling, etc info from the end // we're only interested in position information fen = fen.replace(/ .+$/, ''); // expand the empty square numbers to just 1s fen = expandFenEmptySquares(fen); // SFEN should be 9 sections separated by slashes var chunks = fen.split('/'); if (chunks.length !== 9) return false; // TODO(burdon): Promoted pieces are prefixed with "+". // check each section for (var i = 0; i < 9; i++) { if (chunks[i].length !== 9 || chunks[i].search(/[^lnsgkrbpLNSGKRBP1]/) !== -1) { return false; } } return true; } // TODO(burdon): Promoted pieces (+X) // convert FEN piece code to bP, wK, etc function fenToPieceCode(piece) { // black piece if (piece.toLowerCase() === piece) { return 'b' + piece.toUpperCase(); } // white piece return 'w' + piece.toUpperCase(); } function validSquare(square) { return isString(square) && square.search(/^[a-i][1-9]$/) !== -1; } // TODO(burdon): Promoted pieces (+X) function validPieceCode(code) { return isString(code) && code.search(/^[bw][LNSGKRB]$/) !== -1; } export function validPositionObject(pos) { if (pos === null || _typeof(pos) !== 'object') return false; for (var i in pos) { if (!pos.hasOwnProperty(i)) continue; if (!validSquare(i) || !validPieceCode(pos[i])) { return false; } } return true; } function squeezeFenEmptySquares(fen) { return fen.replace(/111111111/g, '9').replace(/11111111/g, '8').replace(/1111111/g, '7').replace(/111111/g, '6').replace(/11111/g, '5').replace(/1111/g, '4').replace(/111/g, '3').replace(/11/g, '2'); } // TODO(burdon): "+" for promoted piece. // convert bP, wK, etc code to FEN structure function pieceCodeToFen(piece) { var pieceCodeLetters = piece.split(''); // white piece if (pieceCodeLetters[0] === 'w') { return pieceCodeLetters[1].toUpperCase(); } // black piece return pieceCodeLetters[1].toLowerCase(); } // position object to FEN string // returns false if the obj is not a valid position object export function objToFen(obj) { if (!validPositionObject(obj)) return false; var fen = ''; var currentRow = 9; for (var i = 0; i < 9; i++) { for (var j = 0; j < 9; j++) { var square = COLUMNS[j] + currentRow; // piece exists if (obj.hasOwnProperty(square)) { fen = fen + pieceCodeToFen(obj[square]); } else { // empty space fen = fen + '1'; } } if (i !== 7) { fen = fen + '/'; } currentRow = currentRow - 1; } // squeeze the empty numbers together fen = squeezeFenEmptySquares(fen); return fen; }