forked from sent/waves
415 lines
9.0 KiB
JavaScript
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;
|
|
|
|
|
|
} |