1
0
forked from sent/waves
waves/public/assets/g/chess/other-implementations/example3/js/board.js
2025-04-09 17:11:14 -05:00

415 lines
9.0 KiB
JavaScript

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;
}