function PCEINDEX(pce, pceNum) { return (pce * 10 + pceNum); } var GameBoard = {}; GameBoard.pieces = new Array(BRD_SQ_NUM); GameBoard.side = COLOURS.WHITE; GameBoard.fiftyMove = 0; GameBoard.hisPly = 0; GameBoard.history = []; GameBoard.ply = 0; GameBoard.enPas = 0; GameBoard.castlePerm = 0; GameBoard.material = new Array(2); // WHITE,BLACK material of pieces GameBoard.pceNum = new Array(13); // indexed by Pce GameBoard.pList = new Array(14 * 10); GameBoard.posKey = 0; GameBoard.moveList = new Array(MAXDEPTH * MAXPOSITIONMOVES); GameBoard.moveScores = new Array(MAXDEPTH * MAXPOSITIONMOVES); GameBoard.moveListStart = new Array(MAXDEPTH); GameBoard.PvTable = []; GameBoard.PvArray = new Array(MAXDEPTH); GameBoard.searchHistory = new Array(14 * BRD_SQ_NUM); GameBoard.searchKillers = new Array(3 * MAXDEPTH); function CheckBoard() { var t_pceNum = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var t_material = [0, 0]; var sq64, t_piece, t_pce_num, sq120, colour, pcount; for (t_piece = PIECES.wP; t_piece <= PIECES.bK; ++t_piece) { for (t_pce_num = 0; t_pce_num < GameBoard.pceNum[t_piece]; ++t_pce_num) { sq120 = GameBoard.pList[PCEINDEX(t_piece, t_pce_num)]; if (GameBoard.pieces[sq120] != t_piece) { console.log('Error Pce Lists'); return BOOL.FALSE; } } } for (sq64 = 0; sq64 < 64; ++sq64) { sq120 = SQ120(sq64); t_piece = GameBoard.pieces[sq120]; t_pceNum[t_piece]++; t_material[PieceCol[t_piece]] += PieceVal[t_piece]; } for (t_piece = PIECES.wP; t_piece <= PIECES.bK; ++t_piece) { if (t_pceNum[t_piece] != GameBoard.pceNum[t_piece]) { console.log('Error t_pceNum'); return BOOL.FALSE; } } if (t_material[COLOURS.WHITE] != GameBoard.material[COLOURS.WHITE] || t_material[COLOURS.BLACK] != GameBoard.material[COLOURS.BLACK]) { console.log('Error t_material'); return BOOL.FALSE; } if (GameBoard.side != COLOURS.WHITE && GameBoard.side != COLOURS.BLACK) { console.log('Error GameBoard.side'); return BOOL.FALSE; } if (GeneratePosKey() != GameBoard.posKey) { console.log('Error GameBoard.posKey'); return BOOL.FALSE; } return BOOL.TRUE; } function PrintBoard() { var sq, file, rank, piece; console.log("\nGame Board:\n"); for (rank = RANKS.RANK_8; rank >= RANKS.RANK_1; rank--) { var line = (RankChar[rank] + " "); for (file = FILES.FILE_A; file <= FILES.FILE_H; file++) { sq = FR2SQ(file, rank); piece = GameBoard.pieces[sq]; line += (" " + PceChar[piece] + " "); } console.log(line); } console.log(""); var line = " "; for (file = FILES.FILE_A; file <= FILES.FILE_H; file++) { line += (' ' + FileChar[file] + ' '); } console.log(line); console.log("side:" + SideChar[GameBoard.side]); console.log("enPas:" + GameBoard.enPas); line = ""; if (GameBoard.castlePerm & CASTLEBIT.WKCA) line += 'K'; if (GameBoard.castlePerm & CASTLEBIT.WQCA) line += 'Q'; if (GameBoard.castlePerm & CASTLEBIT.BKCA) line += 'k'; if (GameBoard.castlePerm & CASTLEBIT.BQCA) line += 'q'; console.log("castle:" + line); console.log("key:" + GameBoard.posKey.toString(16)); } function GeneratePosKey() { var sq = 0; var finalKey = 0; var piece = PIECES.EMPTY; for (sq = 0; sq < BRD_SQ_NUM; ++sq) { piece = GameBoard.pieces[sq]; if (piece != PIECES.EMPTY && piece != SQUARES.OFFBOARD) { finalKey ^= PieceKeys[(piece * 120) + sq]; } } if (GameBoard.side == COLOURS.WHITE) { finalKey ^= SideKey; } if (GameBoard.enPas != SQUARES.NO_SQ) { finalKey ^= PieceKeys[GameBoard.enPas]; } finalKey ^= CastleKeys[GameBoard.castlePerm]; return finalKey; } function PrintPieceLists() { var piece, pceNum; for (piece = PIECES.wP; piece <= PIECES.bK; ++piece) { for (pceNum = 0; pceNum < GameBoard.pceNum[piece]; ++pceNum) { console.log('Piece ' + PceChar[piece] + ' on ' + PrSq(GameBoard.pList[PCEINDEX(piece, pceNum)])); } } } function UpdateListsMaterial() { var piece, sq, index, colour; for (index = 0; index < 14 * 120; ++index) { GameBoard.pList[index] = PIECES.EMPTY; } for (index = 0; index < 2; ++index) { GameBoard.material[index] = 0; } for (index = 0; index < 13; ++index) { GameBoard.pceNum[index] = 0; } for (index = 0; index < 64; ++index) { sq = SQ120(index); piece = GameBoard.pieces[sq]; if (piece != PIECES.EMPTY) { colour = PieceCol[piece]; GameBoard.material[colour] += PieceVal[piece]; GameBoard.pList[PCEINDEX(piece, GameBoard.pceNum[piece])] = sq; GameBoard.pceNum[piece]++; } } } function ResetBoard() { var index = 0; for (index = 0; index < BRD_SQ_NUM; ++index) { GameBoard.pieces[index] = SQUARES.OFFBOARD; } for (index = 0; index < 64; ++index) { GameBoard.pieces[SQ120(index)] = PIECES.EMPTY; } GameBoard.side = COLOURS.BOTH; GameBoard.enPas = SQUARES.NO_SQ; GameBoard.fiftyMove = 0; GameBoard.ply = 0; GameBoard.hisPly = 0; GameBoard.castlePerm = 0; GameBoard.posKey = 0; GameBoard.moveListStart[GameBoard.ply] = 0; } //rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 function ParseFen(fen) { ResetBoard(); var rank = RANKS.RANK_8; var file = FILES.FILE_A; var piece = 0; var count = 0; var i = 0; var sq120 = 0; var fenCnt = 0; // fen[fenCnt] while ((rank >= RANKS.RANK_1) && fenCnt < fen.length) { count = 1; switch (fen[fenCnt]) { case 'p': piece = PIECES.bP; break; case 'r': piece = PIECES.bR; break; case 'n': piece = PIECES.bN; break; case 'b': piece = PIECES.bB; break; case 'k': piece = PIECES.bK; break; case 'q': piece = PIECES.bQ; break; case 'P': piece = PIECES.wP; break; case 'R': piece = PIECES.wR; break; case 'N': piece = PIECES.wN; break; case 'B': piece = PIECES.wB; break; case 'K': piece = PIECES.wK; break; case 'Q': piece = PIECES.wQ; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': piece = PIECES.EMPTY; count = fen[fenCnt].charCodeAt() - '0'.charCodeAt(); break; case '/': case ' ': rank--; file = FILES.FILE_A; fenCnt++; continue; default: console.log("FEN error"); return; } for (i = 0; i < count; i++) { sq120 = FR2SQ(file, rank); GameBoard.pieces[sq120] = piece; file++; } fenCnt++; } // while loop end //rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 GameBoard.side = (fen[fenCnt] == 'w') ? COLOURS.WHITE : COLOURS.BLACK; fenCnt += 2; for (i = 0; i < 4; i++) { if (fen[fenCnt] == ' ') { break; } switch (fen[fenCnt]) { case 'K': GameBoard.castlePerm |= CASTLEBIT.WKCA; break; case 'Q': GameBoard.castlePerm |= CASTLEBIT.WQCA; break; case 'k': GameBoard.castlePerm |= CASTLEBIT.BKCA; break; case 'q': GameBoard.castlePerm |= CASTLEBIT.BQCA; break; default: break; } fenCnt++; } fenCnt++; if (fen[fenCnt] != '-') { file = fen[fenCnt].charCodeAt() - 'a'.charCodeAt(); rank = fen[fenCnt + 1].charCodeAt() - '1'.charCodeAt(); console.log("fen[fenCnt]:" + fen[fenCnt] + " File:" + file + " Rank:" + rank); GameBoard.enPas = FR2SQ(file, rank); } GameBoard.posKey = GeneratePosKey(); UpdateListsMaterial(); } function PrintSqAttacked() { var sq, file, rank, piece; console.log("\nAttacked:\n"); for (rank = RANKS.RANK_8; rank >= RANKS.RANK_1; rank--) { var line = ((rank + 1) + " "); for (file = FILES.FILE_A; file <= FILES.FILE_H; file++) { sq = FR2SQ(file, rank); if (SqAttacked(sq, GameBoard.side ^ 1) == BOOL.TRUE) piece = "X"; else piece = "-"; line += (" " + piece + " "); } console.log(line); } console.log(""); } function SqAttacked(sq, side) { var pce; var t_sq; var index; if (side == COLOURS.WHITE) { if (GameBoard.pieces[sq - 11] == PIECES.wP || GameBoard.pieces[sq - 9] == PIECES.wP) { return BOOL.TRUE; } } else { if (GameBoard.pieces[sq + 11] == PIECES.bP || GameBoard.pieces[sq + 9] == PIECES.bP) { return BOOL.TRUE; } } for (index = 0; index < 8; index++) { pce = GameBoard.pieces[sq + KnDir[index]]; if (pce != SQUARES.OFFBOARD && PieceCol[pce] == side && PieceKnight[pce] == BOOL.TRUE) { return BOOL.TRUE; } } for (index = 0; index < 4; ++index) { dir = RkDir[index]; t_sq = sq + dir; pce = GameBoard.pieces[t_sq]; while (pce != SQUARES.OFFBOARD) { if (pce != PIECES.EMPTY) { if (PieceRookQueen[pce] == BOOL.TRUE && PieceCol[pce] == side) { return BOOL.TRUE; } break; } t_sq += dir; pce = GameBoard.pieces[t_sq]; } } for (index = 0; index < 4; ++index) { dir = BiDir[index]; t_sq = sq + dir; pce = GameBoard.pieces[t_sq]; while (pce != SQUARES.OFFBOARD) { if (pce != PIECES.EMPTY) { if (PieceBishopQueen[pce] == BOOL.TRUE && PieceCol[pce] == side) { return BOOL.TRUE; } break; } t_sq += dir; pce = GameBoard.pieces[t_sq]; } } for (index = 0; index < 8; index++) { pce = GameBoard.pieces[sq + KiDir[index]]; if (pce != SQUARES.OFFBOARD && PieceCol[pce] == side && PieceKing[pce] == BOOL.TRUE) { return BOOL.TRUE; } } return BOOL.FALSE; }