int main(int argc, char **argv) { my_srand(12345); unsigned iterations = 5000000; if (argc > 1) iterations = atoi(argv[1]); printf("Initialize...\n"); init(); size_t d; for (d = 0; d < sizeof(data)/sizeof(data[0]); ++d) { unsigned long long datum = 0; switch (my_rand() % 4) { case 3: datum |= ((unsigned long long)my_rand() & 0xff) << 24; case 2: datum |= ((unsigned long long)my_rand() & 0xff) << 16; case 1: datum |= ((unsigned long long)my_rand() & 0xff) << 8; default: datum |= ((unsigned long long)my_rand() & 0xff); } data[d] = datum; } printf("ok, runing %u iterations\n", iterations); unsigned final_checksum = 0; unsigned i; for (i = 0; i < iterations; ++i) { unsigned checksum = 0; for (d = 0; d < sizeof(data)/sizeof(data[0]); ++d) { checksum += FirstOne(data[d]); } final_checksum = checksum; } printf("checksum %u\n", final_checksum); return 0; }
int getPassedPawnScore(ChessBoard * board, bool white) { BITBOARD pawns = (white) ? board->whitePawns : board->blackPawns; BITBOARD originalPawns = pawns; BITBOARD otherPawns = (white) ? board->blackPawns : board->whitePawns; BITBOARD* doubledPawnMask = (white) ? whiteDoubledPawnMask : blackDoubledPawnMask; BITBOARD* passedPawnMask = (white) ? whitePassedPawnMask : blackPassedPawnMask; int* passedPawnRankScale = (white) ? EvalParameters::whitePassedPawnRankScale : EvalParameters::blackPassedPawnRankScale; int passedPawnScore = 0; while (pawns != 0) { short pawnOffset = FirstOne(pawns); pawns ^= offset_to_mask(pawnOffset); if ((passedPawnMask[pawnOffset] & otherPawns) == 0) { // pawn is passed. give bonus // check if pawn is doubled BITBOARD isDoubled = doubledPawnMask[pawnOffset] & originalPawns; if (isDoubled == 0) { if (board->gamePhase == PHASE_ENDGAME) { passedPawnScore += EvalParameters::passedPawnBonus * passedPawnRankScale[8 - Rank(pawnOffset)]; } else { passedPawnScore += (1/4.0) * EvalParameters::passedPawnBonus * passedPawnRankScale[8 - Rank(pawnOffset)]; } } // no passed pawn bonus if pawn is doubled } } return passedPawnScore; }
int getCenterControlScore(ChessBoard * board, bool white) { int whiteCenterScore = 0; int blackCenterScore = 0; BITBOARD iterateCenterSquares = centerSquares; while(iterateCenterSquares != 0) { short centerSquare = FirstOne(iterateCenterSquares); iterateCenterSquares ^= offset_to_mask(centerSquare); BITBOARD attackBitboard = get_attacksto_bitboard(board, centerSquare); short whiteAttacks = NumOnes(attackBitboard & board->whitePieces); short blackAttacks = NumOnes(attackBitboard & board->blackPieces); short contents = board->boardContents[centerSquare]; if (contents != EMPTY) { if (IsPieceWhite(contents)) whiteAttacks += 2; else blackAttacks += 2; } whiteCenterScore += whiteAttacks * EvalParameters::whiteCenterControlScale[centerSquare]; blackCenterScore += blackAttacks * EvalParameters::blackCenterControlScale[centerSquare]; } if (white) return whiteCenterScore - blackCenterScore; else return blackCenterScore - whiteCenterScore; }
BITBOARD ValidateComputeRookAttacks(int square) { BITBOARD attacks, temp_attacks; BITBOARD temp1, temp8; attacks=rook_attacks[square]; temp_attacks=And(attacks,Compl(Occupied)); temp_attacks=Compl(Or(temp_attacks,Compl(rook_attacks[square]))); temp1=And(temp_attacks,plus1dir[square]); temp8=And(temp_attacks,plus8dir[square]); attacks=Xor(attacks,plus1dir[FirstOne(temp1)]); attacks=Xor(attacks,plus8dir[FirstOne(temp8)]); temp1=And(temp_attacks,minus1dir[square]); temp8=And(temp_attacks,minus8dir[square]); attacks=Xor(attacks,minus1dir[LastOne(temp1)]); attacks=Xor(attacks,minus8dir[LastOne(temp8)]); return(attacks); }
BITBOARD ValidateComputeBishopAttacks(int square) { BITBOARD attacks, temp_attacks; BITBOARD temp7, temp9; attacks=bishop_attacks[square]; temp_attacks=And(attacks,Compl(Occupied)); temp_attacks=Compl(Or(temp_attacks,Compl(bishop_attacks[square]))); temp7=And(temp_attacks,plus7dir[square]); temp9=And(temp_attacks,plus9dir[square]); attacks=Xor(attacks,plus7dir[FirstOne(temp7)]); attacks=Xor(attacks,plus9dir[FirstOne(temp9)]); temp7=And(temp_attacks,minus7dir[square]); temp9=And(temp_attacks,minus9dir[square]); attacks=Xor(attacks,minus7dir[LastOne(temp7)]); attacks=Xor(attacks,minus9dir[LastOne(temp9)]); return(attacks); }
// check whether all moves end up in wins for the opponent // if we are here, all captures are losing static int check_loss(int *pcs, long64 idx0, ubyte *table, bitboard occ, int *p) { int sq; long64 idx, idx2; bitboard bb; int best = LOSS_IN_ONE; int k = *pcs++; if (k == 0) { // white king bb = WhiteKingMoves; while (bb) { sq = FirstOne(bb); idx2 = MakeMove0(idx0, sq); int v = win_loss[table[idx2]]; if (!v) return 0; if (v < best) best = v; ClearFirst(bb); } } else { // otherwise k == 1, i.e. black king bb = BlackKingMoves; while (bb) { sq = FirstOne(bb); idx2 = MakeMove1(idx0, sq); int v = win_loss[table[idx2]]; if (!v) return 0; if (v < best) best = v; ClearFirst(bb); } } while ((k = *pcs++) >= 0) { bb = PieceMoves(p[k], pt[k], occ); idx = idx0 & ~mask[k]; while (bb) { sq = FirstOne(bb); idx2 = MakeMove2(idx, k, sq); int v = win_loss[table[idx2]]; if (!v) return 0; if (v < best) best = v; ClearFirst(bb); } } return best; }
static int check_mate(int *pcs, long64 idx0, ubyte *table, bitboard occ, int *p) { int sq; long64 idx, idx2; bitboard bb; int k = *pcs++; if (k == 0) { // white king bb = WhiteKingMoves; while (bb) { sq = FirstOne(bb); idx2 = MakeMove0(idx0, sq); if (table[idx2] != ILLEGAL) return 0; ClearFirst(bb); } } else { // otherwise k == 1, i.e. black king bb = BlackKingMoves; while (bb) { sq = FirstOne(bb); idx2 = MakeMove1(idx0, sq); if (table[idx2] != ILLEGAL) return 0; ClearFirst(bb); } } while ((k = *pcs++) >= 0) { bb = PieceMoves(p[k], pt[k], occ); idx = idx0 & ~mask[k]; while (bb) { sq = FirstOne(bb); idx2 = MakeMove2(idx, k, sq); if (table[idx2] != ILLEGAL) return 0; ClearFirst(bb); } } return 1; }
int getDoubledPawnPenalty(ChessBoard* board, bool white) { BITBOARD pawns = (white) ? board->whitePawns : board->blackPawns; BITBOARD originalPawns = pawns; BITBOARD* doubledPawnMask = (white) ? whiteDoubledPawnMask : blackDoubledPawnMask; int doubledPawnPenalty = 0; while(pawns != 0) { short pawnOffset = FirstOne(pawns); pawns ^= offset_to_mask(pawnOffset); BITBOARD maskResult = doubledPawnMask[pawnOffset] & originalPawns; if (maskResult != 0) { doubledPawnPenalty += EvalParameters::doubledPawnPenalty * NumOnes(maskResult); } } return doubledPawnPenalty; }
// captures should be taken care of already int check_mate_pieces(int *pcs, long64 idx0, ubyte *table, bitboard occ, int *p) { int sq; long64 idx, idx2; bitboard bb; do { int k = *pcs; bb = PieceMoves(p[k], pt[k], occ); idx = idx0 & ~mask[k]; while (bb) { sq = FirstOne(bb); idx2 = MakeMove(idx, k, sq); if (table[idx2] < WDL_ILLEGAL) return 0; ClearFirst(bb); } } while (*(++pcs) >= 0); return 1; }
static int probe_tb2(struct Player *player, struct Player *opp, bitboard player_occ, bitboard opp_occ, int alpha, int beta) { int i, j; bitboard player_att[5]; bitboard opp_att[5]; // first try captures if (opp->num > 1) { int capts = 0; for (i = 0; i < player->num; i++) { int from = player->pos[i]; bitboard bb = PieceRange(from, player->type[i], player_occ | opp_occ); player_att[i] = bb; bb &= opp_occ; if (bb) { capts = 1; opp->num--; bitboard occ2 = player_occ ^ bit[from]; do { int to = FirstOne(bb); player->pos[i] = to; for (j = 0; opp->pos[j] != to; j++); int tmp_type = opp->type[j]; opp->type[j] = opp->type[opp->num]; opp->pos[j] = opp->pos[opp->num]; #ifdef HAS_PAWNS if ((player->type[i] & 0x07) == PAWN && ((to + 0x08) & 0x30) == 0) { int t = player->type[i]; int m; for (m = KING - PAWN; m >= KNIGHT - PAWN; m--) { player->type[i] = t + m; int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha); if (v > alpha) { alpha = v; if (alpha >= beta) break; } } player->type[i] = t; } else { #endif int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha); if (v > alpha) alpha = v; #ifdef HAS_PAWNS } #endif opp->type[j] = tmp_type; opp->pos[j] = to; if (alpha >= beta) { player->pos[i] = from; opp->num++; return alpha; } ClearFirst(bb); } while (bb); player->pos[i] = from; opp->num++; } } if (capts) return alpha; } else { for (i = 0; i < player->num; i++) { bitboard bb = PieceRange(player->pos[i], player->type[i], player_occ); player_att[i] = bb; if (bb & opp_occ) return -2; } } #if 1 if (player->num + opp->num < 6) goto skip_threats; #endif // now try threats. there are two cases bitboard atts = 0ULL; for (i = 0; i < opp->num; i++) { opp_att[i] = PieceRange(opp->pos[i], opp->type[i], player_occ | opp_occ); atts |= opp_att[i]; } // first case: opponent currently is not attacking any pieces // we only need to consider moves moving into opponent attacks if (!(atts & player_occ)) { if (player->num > 1) { player->num--; for (i = 0; i <= player->num; i++) { #ifdef HAS_PAWNS if ((player->type[i] & 0x07) == 1) continue; #endif bitboard bb = player_att[i] & atts; if (!bb) continue; int pos = player->pos[i]; int type = player->type[i]; player->pos[i] = player->pos[player->num]; player->type[i] = player->type[player->num]; do { int sq = FirstOne(bb); int beta2 = beta; for (j = 0; j < opp->num; j++) { if (!(bit[sq] & opp_att[j])) continue; int tmp_pos = opp->pos[j]; opp->pos[j] = sq; #ifdef HAS_PAWNS if ((opp->type[j] & 0x07) == PAWN && ((sq + 0x08) & 0x30) == 0) { int t = opp->type[j]; int m; for (m = KING - PAWN; m >= KNIGHT - PAWN; m--) { opp->type[j] = t + m; int v = probe_tb2(player, opp, player_occ ^ bit[pos], opp_occ ^ bit[sq] ^ bit[tmp_pos], alpha, beta2); if (v < beta2) { beta2 = v; if (beta2 <= alpha) break; } } opp->type[j] = t; } else { #endif int v = probe_tb2(player, opp, player_occ ^ bit[pos], opp_occ ^ bit[sq] ^ bit[tmp_pos], alpha, beta2); if (v < beta2) beta2 = v; #ifdef HAS_PAWNS } #endif opp->pos[j] = tmp_pos; if (beta2 <= alpha) break; } if (beta2 > alpha) { if (beta2 >= beta) { player->pos[i] = pos; player->type[i] = type; player->num++; return beta2; } alpha = beta2; } ClearFirst(bb); } while (bb); player->pos[i] = pos; player->type[i] = type; } player->num++; } else { for (i = 0; i < player->num; i++) { #ifdef HAS_PAWNS if ((player->type[i] & 0x07) == 1) continue; #endif if (player_att[i] & atts) return 2; } } } else { // second case: just try all moves for (i = 0; i < player->num; i++) { #ifdef HAS_PAWNS if ((player->type[i] & 0x07) == 1) continue; #endif bitboard bb = player_att[i] & ~player_occ; if (bb) { int from = player->pos[i]; do { int capts; int to = FirstOne(bb); player->pos[i] = to; int v = -probe_tb_capts(opp, player, opp_occ, player_occ ^ bit[from] ^ bit[to], -beta, -alpha, &capts); if (capts && v > alpha) { if (v >= beta) { player->pos[i] = from; return v; } alpha = v; } ClearFirst(bb); } while (bb); player->pos[i] = from; } } } int pieces[6]; int pos[6]; skip_threats: for (i = 0; i < player->num; i++) { pieces[i] = player->type[i]; pos[i] = player->pos[i]; } for (j = 0; j < opp->num; j++, i++) { pieces[i] = opp->type[j]; pos[i] = opp->pos[j]; } for (; i < numpcs; i++) pieces[i] = 0; int v = probe_table(pieces, pos, pieces[0] < 8); return alpha > v ? alpha : v; }
void ValidatePosition(int ply, int move, char *caller) { BITBOARD temp, temp1, temp_occ, temp_occ_rl90, temp_occ_rl45; BITBOARD temp_occ_rr45, temp_occx, cattacks, rattacks; int i,square,error; int temp_score; /* first, test w_occupied and b_occupied */ error=0; temp_occ=Or(Or(Or(Or(Or(WhitePawns,WhiteKnights),WhiteBishops), WhiteRooks),WhiteQueens),WhiteKing); if(Xor(WhitePieces,temp_occ)) { Print(1,"ERROR white occupied squares is bad!\n"); Display2BitBoards(temp_occ,WhitePieces); error=1; } temp_occ=Or(Or(Or(Or(Or(BlackPawns,BlackKnights),BlackBishops), BlackRooks),BlackQueens),BlackKing); if(Xor(BlackPieces,temp_occ)) { Print(1,"ERROR black occupied squares is bad!\n"); Display2BitBoards(temp_occ,BlackPieces); error=1; } /* now test rotated occupied bitboards. */ temp_occ_rl90=0; temp_occ_rl45=0; temp_occ_rr45=0; for (i=0;i<64;i++) { if (PieceOnSquare(i)) { temp_occ_rl90=Or(temp_occ_rl90,set_mask_rl90[i]); temp_occ_rl45=Or(temp_occ_rl45,set_mask_rl45[i]); temp_occ_rr45=Or(temp_occ_rr45,set_mask_rr45[i]); } } if(Xor(OccupiedRL90,temp_occ_rl90)) { Print(1,"ERROR occupied squares (rotated left 90) is bad!\n"); Display2BitBoards(temp_occ_rl90,OccupiedRL90); error=1; } if(Xor(OccupiedRL45,temp_occ_rl45)) { Print(1,"ERROR occupied squares (rotated left 45) is bad!\n"); Display2BitBoards(temp_occ_rl45,OccupiedRL45); error=1; } if(Xor(OccupiedRR45,temp_occ_rr45)) { Print(1,"ERROR occupied squares (rotated right 45) is bad!\n"); Display2BitBoards(temp_occ_rr45,OccupiedRR45); error=1; } /* now test bishops_queens and rooks_queens */ temp_occ=Or(Or(Or(WhiteBishops,WhiteQueens),BlackBishops), BlackQueens); if(Xor(BishopsQueens,temp_occ)) { Print(1,"ERROR bishops_queens is bad!\n"); Display2BitBoards(temp_occ,BishopsQueens); error=1; } temp_occ=Or(Or(Or(WhiteRooks,WhiteQueens),BlackRooks), BlackQueens); if(Xor(RooksQueens,temp_occ)) { Print(1,"ERROR rooks_queens is bad!\n"); Display2BitBoards(temp_occ,RooksQueens); error=1; } /* check individual piece bit-boards to make sure two pieces don't occupy the same square (bit) */ temp_occ=Xor(Xor(Xor(Xor(Xor(Xor(Xor(Xor(Xor(Xor(Xor( WhitePawns,WhiteKnights),WhiteBishops),WhiteRooks), WhiteQueens),BlackPawns),BlackKnights),BlackBishops), BlackRooks),BlackQueens),WhiteKing),BlackKing); temp_occx=Or(Or(Or(Or(Or(Or(Or(Or(Or(Or(Or( WhitePawns,WhiteKnights),WhiteBishops),WhiteRooks), WhiteQueens),BlackPawns),BlackKnights),BlackBishops), BlackRooks),BlackQueens),WhiteKing),BlackKing); if(Xor(temp_occ,temp_occx)) { Print(1,"ERROR two pieces on same square\n"); error=1; } /* test material_evaluation */ temp_score=PopCnt(WhitePawns)*PAWN_VALUE; temp_score-=PopCnt(BlackPawns)*PAWN_VALUE; temp_score+=PopCnt(WhiteKnights)*KNIGHT_VALUE; temp_score-=PopCnt(BlackKnights)*KNIGHT_VALUE; temp_score+=PopCnt(WhiteBishops)*BISHOP_VALUE; temp_score-=PopCnt(BlackBishops)*BISHOP_VALUE; temp_score+=PopCnt(WhiteRooks)*ROOK_VALUE; temp_score-=PopCnt(BlackRooks)*ROOK_VALUE; temp_score+=PopCnt(WhiteQueens)*QUEEN_VALUE; temp_score-=PopCnt(BlackQueens)*QUEEN_VALUE; if(temp_score != Material) { Print(1,"ERROR material_evaluation is wrong, good=%d, bad=%d\n", temp_score,Material); error=1; } temp_score=PopCnt(WhiteKnights)*knight_v; temp_score+=PopCnt(WhiteBishops)*bishop_v; temp_score+=PopCnt(WhiteRooks)*rook_v; temp_score+=PopCnt(WhiteQueens)*queen_v; if(temp_score != TotalWhitePieces) { Print(1,"ERROR white_pieces is wrong, good=%d, bad=%d\n", temp_score,TotalWhitePieces); error=1; } temp_score=PopCnt(WhitePawns); if(temp_score != TotalWhitePawns) { Print(1,"ERROR white_pawns is wrong, good=%d, bad=%d\n", temp_score,TotalWhitePawns); error=1; } temp_score=PopCnt(BlackKnights)*knight_v; temp_score+=PopCnt(BlackBishops)*bishop_v; temp_score+=PopCnt(BlackRooks)*rook_v; temp_score+=PopCnt(BlackQueens)*queen_v; if(temp_score != TotalBlackPieces) { Print(1,"ERROR black_pieces is wrong, good=%d, bad=%d\n", temp_score,TotalBlackPieces); error=1; } temp_score=PopCnt(BlackPawns); if(temp_score != TotalBlackPawns) { Print(1,"ERROR black_pawns is wrong, good=%d, bad=%d\n", temp_score,TotalBlackPawns); error=1; } /* now test the board[...] to make sure piece values are correct. */ /* test pawn locations */ temp=WhitePawns; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != pawn) { Print(1,"ERROR! board[%d]=%d, should be 1\n",square, PieceOnSquare(square)); error=1; } Clear(square,temp); } temp=BlackPawns; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != -pawn) { Print(1,"ERROR! board[%d]=%d, should be -1\n",square, PieceOnSquare(square)); error=1; } Clear(square,temp); } /* test knight locations */ temp=WhiteKnights; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != knight) { Print(1,"ERROR! board[%d]=%d, should be 2\n",square, PieceOnSquare(square)); error=1; } Clear(square,temp); } temp=BlackKnights; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != -knight) { Print(1,"ERROR! board[%d]=%d, should be -2\n",square, PieceOnSquare(square)); error=1; } Clear(square,temp); } /* test bishop locations */ temp=WhiteBishops; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != bishop) { Print(1,"ERROR! board[%d]=%d, should be 3\n",square, PieceOnSquare(square)); error=1; } rattacks=AttacksBishop(square); cattacks=ValidateComputeBishopAttacks(square); if (rattacks != cattacks) { Print(1,"ERROR! bishop attacks wrong, square=%d\n",square); Display2BitBoards(rattacks,cattacks); error=1; } Clear(square,temp); } temp=BlackBishops; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != -bishop) { Print(1,"ERROR! board[%d]=%d, should be -3\n",square, PieceOnSquare(square)); error=1; } rattacks=AttacksBishop(square); cattacks=ValidateComputeBishopAttacks(square); if (rattacks != cattacks) { Print(1,"ERROR! bishop attacks wrong, square=%d\n",square); Display2BitBoards(rattacks,cattacks); error=1; } Clear(square,temp); } /* test rook locations */ temp=WhiteRooks; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != rook) { Print(1,"ERROR! board[%d]=%d, should be 4\n",square, PieceOnSquare(square)); error=1; } rattacks=AttacksRook(square); cattacks=ValidateComputeRookAttacks(square); if (rattacks != cattacks) { Print(1,"ERROR! Rook attacks wrong, square=%d\n",square); Display2BitBoards(rattacks,cattacks); error=1; } Clear(square,temp); } temp=BlackRooks; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != -rook) { Print(1,"ERROR! board[%d]=%d, should be -4\n",square, PieceOnSquare(square)); error=1; } rattacks=AttacksRook(square); cattacks=ValidateComputeRookAttacks(square); if (rattacks != cattacks) { Print(1,"ERROR! Rook attacks wrong, square=%d\n",square); Display2BitBoards(rattacks,cattacks); error=1; } Clear(square,temp); } /* test queen locations */ temp=WhiteQueens; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != queen) { Print(1,"ERROR! board[%d]=%d, should be 5\n",square, PieceOnSquare(square)); error=1; } rattacks=AttacksQueen(square); cattacks=Or(ValidateComputeRookAttacks(square),ValidateComputeBishopAttacks(square)); if (rattacks != cattacks) { Print(1,"ERROR! queen attacks wrong, square=%d\n",square); Display2BitBoards(rattacks,cattacks); error=1; } Clear(square,temp); } temp=BlackQueens; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != -queen) { Print(1,"ERROR! board[%d]=%d, should be -5\n",square, PieceOnSquare(square)); error=1; } rattacks=AttacksQueen(square); cattacks=Or(ValidateComputeRookAttacks(square),ValidateComputeBishopAttacks(square)); if (rattacks != cattacks) { Print(1,"ERROR! queen attacks wrong, square=%d\n",square); Display2BitBoards(rattacks,cattacks); error=1; } Clear(square,temp); } /* test king locations */ temp=WhiteKing; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != king) { Print(1,"ERROR! board[%d]=%d, should be 6\n",square, PieceOnSquare(square)); error=1; } if (WhiteKingSQ != square) { Print(1,"ERROR! white_king is %d, should be %d\n", WhiteKingSQ,square); error=1; } Clear(square,temp); } temp=BlackKing; while(temp) { square=FirstOne(temp); if (PieceOnSquare(square) != -king) { Print(1,"ERROR! board[%d]=%d, should be -6\n",square, PieceOnSquare(square)); error=1; } if (BlackKingSQ != square) { Print(1,"ERROR! black_king is %d, should be %d\n", BlackKingSQ,square); error=1; } Clear(square,temp); } /* test board[i] fully now. */ for (i=0;i<64;i++) switch (PieceOnSquare(i)) { case -king: if (!And(BlackKing,set_mask[i])) { Print(1,"ERROR! b_king/board[%d] don't agree!\n",i); error=1; } break; case -queen: if (!And(BlackQueens,set_mask[i])) { Print(1,"ERROR! b_queen/board[%d] don't agree!\n",i); error=1; } break; case -rook: if (!And(BlackRooks,set_mask[i])) { Print(1,"ERROR! b_rook/board[%d] don't agree!\n",i); error=1; } break; case -bishop: if (!And(BlackBishops,set_mask[i])) { Print(1,"ERROR! b_bishop/board[%d] don't agree!\n",i); error=1; } break; case -knight: if (!And(BlackKnights,set_mask[i])) { Print(1,"ERROR! b_knight/board[%d] don't agree!\n",i); error=1; } break; case -pawn: if (!And(BlackPawns,set_mask[i])) { Print(1,"ERROR! b_pawn/board[%d] don't agree!\n",i); error=1; } break; case king: if (!And(WhiteKing,set_mask[i])) { Print(1,"ERROR! w_king/board[%d] don't agree!\n",i); error=1; } break; case queen: if (!And(WhiteQueens,set_mask[i])) { Print(1,"ERROR! w_queen/board[%d] don't agree!\n",i); error=1; } break; case rook: if (!And(WhiteRooks,set_mask[i])) { Print(1,"ERROR! w_rook/board[%d] don't agree!\n",i); error=1; } break; case bishop: if (!And(WhiteBishops,set_mask[i])) { Print(1,"ERROR! w_bishop/board[%d] don't agree!\n",i); error=1; } break; case knight: if (!And(WhiteKnights,set_mask[i])) { Print(1,"ERROR! w_knight/board[%d] don't agree!\n",i); error=1; } break; case pawn: if (!And(WhitePawns,set_mask[i])) { Print(1,"ERROR! w_pawn/board[%d] don't agree!\n",i); error=1; } break; } /* test empty squares now */ temp=Compl(Or(temp_occ,temp_occx)); while(temp) { square=FirstOne(temp); if (PieceOnSquare(square)) { Print(1,"ERROR! board[%d]=%d, should be 0\n",square, PieceOnSquare(square)); error=1; } Clear(square,temp); } /* test total piece count now */ temp=PopCnt(Occupied); if (temp != TotalPieces) { Print(1,"ERROR! TotalPieces is wrong, correct=%d bad=%d\n", temp,TotalPieces); error=1; } /* test hash key */ temp=0; temp1=0; for (i=0;i<64;i++) { switch (PieceOnSquare(i)) { case king: temp=Xor(temp,w_king_random[i]); break; case queen: temp=Xor(temp,w_queen_random[i]); break; case rook: temp=Xor(temp,w_rook_random[i]); break; case bishop: temp=Xor(temp,w_bishop_random[i]); break; case knight: temp=Xor(temp,w_knight_random[i]); break; case pawn: temp=Xor(temp,w_pawn_random[i]); temp1=Xor(temp1,w_pawn_random[i]); break; case -pawn: temp=Xor(temp,b_pawn_random[i]); temp1=Xor(temp1,b_pawn_random[i]); break; case -knight: temp=Xor(temp,b_knight_random[i]); break; case -bishop: temp=Xor(temp,b_bishop_random[i]); break; case -rook: temp=Xor(temp,b_rook_random[i]); break; case -queen: temp=Xor(temp,b_queen_random[i]); break; case -king: temp=Xor(temp,b_king_random[i]); break; default: break; } } if (EnPassant(ply)) HashEP(EnPassant(ply),temp); if (!(WhiteCastle(ply)&1)) HashCastleW(0,temp); if (!(WhiteCastle(ply)&2)) HashCastleW(1,temp); if (!(BlackCastle(ply)&1)) HashCastleB(0,temp); if (!(BlackCastle(ply)&2)) HashCastleB(1,temp); if(Xor(temp,HashKey)) { Print(1,"ERROR! hash_key is bad.\n"); error=1; } if(Xor(temp1,PawnHashKey)) { Print(1,"ERROR! pawn_hash_key is bad.\n"); error=1; } if (error) { /* Print(0,"active path:\n"); for (i=1;i<=ply;i++) DisplayChessMove("move=",move); */ Print(0,"current move:\n"); DisplayChessMove("move=",move); DisplayChessBoard(stdout,search); Print(0,"called from %s, ply=%d\n",caller,ply); Print(0,"node=%d\n",nodes_searched+q_nodes_searched); exit(1); } }
int main() { int a = FirstOne(12345678); return 0; }
/* ******************************************************************************** * * * Search() is the recursive routine used to implement the alpha/beta * * negamax search (similar to minimax but simpler to code.) Search() is * * called whenever there is "depth" remaining so that all moves are subject * * to searching, or when the side to move is in check, to make sure that this * * side isn't mated. Search() recursively calls itself until depth is ex- * * hausted, at which time it calls Quiesce() instead. * * * ******************************************************************************** */ int Search(int alpha, int beta, int wtm, int depth, int ply, int do_null) { register int first_move=1; register BITBOARD save_hash_key; register int initial_alpha, value; register int extensions; /* ---------------------------------------------------------- | | | check to see if we have searched enough nodes that it | | is time to peek at how much time has been used, or if | | is time to check for operator keyboard input. this is | | usually enough nodes to force a time/input check about | | once per second, except when the target time per move | | is very small, in which case we try to check the time | | at least 10 times during the search. | | | ---------------------------------------------------------- */ if (ply >= MAXPLY-2) return(beta); nodes_searched++; if (--next_time_check <= 0) { next_time_check=nodes_between_time_checks; if (CheckInput()) Interrupt(ply); time_abort+=TimeCheck(0); if (time_abort) { abort_search=1; return(0); } } /* ---------------------------------------------------------- | | | check for draw by repetition. | | | ---------------------------------------------------------- */ if (RepetitionCheck(ply,wtm)) { value=(wtm==root_wtm) ? DrawScore() : -DrawScore(); if (value < beta) SavePV(ply,value,0); #if !defined(FAST) if(ply <= trace_level) printf("draw by repetition detected, ply=%d.\n",ply); #endif return(value); } /* ---------------------------------------------------------- | | | now call LookUp() to see if this position has been | | searched before. if so, we may get a real score, | | produce a cutoff, or get nothing more than a good move | | to try first. there are four cases to handle: | | | | 1. LookUp() returned "EXACT_SCORE" if this score is | | greater than beta, return beta. otherwise, return the | | score. In either case, no further searching is needed | | from this position. note that lookup verified that | | the table position has sufficient "draft" to meet the | | requirements of the current search depth remaining. | | | | 2. LookUp() returned "LOWER_BOUND" which means that | | when this position was searched previously, every move | | was "refuted" by one of its descendents. as a result, | | when the search was completed, we returned alpha at | | that point. we simply return alpha here as well. | | | | 3. LookUp() returned "UPPER_BOUND" which means that | | when we encountered this position before, we searched | | one branch (probably) which promptly refuted the move | | at the previous ply. | | | | 4. LookUp() returned "AVOID_NULL_MOVE" which means | | the hashed score/bound was no good, but it indicated | | that trying a null-move in this position will be a | | waste of time. | | | ---------------------------------------------------------- */ switch (LookUp(ply,depth,wtm,&alpha,beta)) { case EXACT_SCORE: if(alpha >= beta) return(beta); else { SavePV(ply,alpha,1); return(alpha); } case LOWER_BOUND: return(alpha); case UPPER_BOUND: return(beta); case AVOID_NULL_MOVE: do_null=0; } /* ---------------------------------------------------------- | | | now it's time to try a probe into the endgame table- | | base files. this is done if (a) the previous move was | | a capture or promotion, unless we are at very shallow | | plies (<4) in the search; (b) there are less than 5 | | pieces left (currently all interesting 4 piece endings | | are available.) | | | ---------------------------------------------------------- */ #if defined(TABLEBASES) if (TotalPieces < 5) do { register int wpawn, bpawn; int tb_value; if (TotalWhitePawns && TotalBlackPawns) { wpawn=FirstOne(WhitePawns); bpawn=FirstOne(BlackPawns); if (FileDistance(wpawn,bpawn) == 1) { if(((Rank(wpawn)==1) && (Rank(bpawn)>2)) || ((Rank(bpawn)==6) && (Rank(wpawn)<5)) || EnPassant(ply)) break; } } tb_probes++; if (EGTBScore(ply, wtm, &tb_value)) { tb_probes_successful++; alpha=tb_value; if (abs(alpha) > MATE-100) alpha+=(alpha > 0) ? -(ply-1) : +(ply-1); else if (alpha == 0) alpha=(wtm==root_wtm) ? DrawScore() : -DrawScore(); if(alpha >= beta) return(beta); else { SavePV(ply,alpha,2); return(alpha); } } } while(0); # endif /* ---------------------------------------------------------- | | | initialize. | | | ---------------------------------------------------------- */ in_check[ply+1]=0; extended_reason[ply+1]=no_extension; initial_alpha=alpha; last[ply]=last[ply-1]; killer_count1[ply+1]=0; killer_count2[ply+1]=0; /* ---------------------------------------------------------- | | | first, we try a null move to see if we can get a quick | | cutoff with only a little work. this operates as | | follows. instead of making a legal move, the side on | | move 'passes' and does nothing. the resulting position | | is searched to a shallower depth than normal (usually | | one ply less but settable by the operator) this should | | result in a cutoff or at least should set the lower | | bound better since anything should be better than not | | doing anything. | | | | this is skipped for any of the following reasons: | | | | 1. the side on move is in check. the null move | | results in an illegal position. | | 2. no more than one null move can appear in succession | | or else the search will degenerate into nothing. | | 3. the side on move has little material left making | | zugzwang positions more likely. | | | ---------------------------------------------------------- */ # if defined(NULL_MOVE_DEPTH) if (do_null && !in_check[ply] && ((wtm) ? TotalWhitePieces : TotalBlackPieces)>2) { current_move[ply]=0; current_phase[ply]=NULL_MOVE; #if !defined(FAST) if (ply <= trace_level) SearchTrace(ply,depth,wtm,alpha,beta,"Search",0); #endif position[ply+1]=position[ply]; Rule50Moves(ply+1)++; save_hash_key=HashKey; if (EnPassant(ply)) { HashEP(EnPassant(ply+1),HashKey); EnPassant(ply+1)=0; } if ((depth-NULL_MOVE_DEPTH-INCREMENT_PLY) >= INCREMENT_PLY) value=-Search(-beta,-alpha,ChangeSide(wtm),depth-NULL_MOVE_DEPTH-INCREMENT_PLY,ply+1,NO_NULL); else value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1); HashKey=save_hash_key; if (abort_search) return(0); if (value >= beta) { StoreRefutation(ply,depth,wtm,beta); return(beta); } } # endif /* ---------------------------------------------------------- | | | if there is no best move from the hash table, and this | | is a PV node, then we need a good move to search | | first. while killers and history moves are good, they | | are not "good enough". the simplest action is to try | | a shallow search (depth-2) to get a move. note that | | when we call Search() with depth-2, it, too, will | | not have a hash move, and will therefore recursively | | continue this process, hence the name "internal | | iterative deepening." | | | ---------------------------------------------------------- */ next_status[ply].phase=FIRST_PHASE; if (hash_move[ply]==0 && (depth > 2*INCREMENT_PLY) && (((ply & 1) && alpha == root_alpha && beta == root_beta) || (!(ply & 1) && alpha == -root_beta && beta == -root_alpha))) { current_move[ply]=0; value=Search(alpha,beta,wtm,depth-2*INCREMENT_PLY,ply,DO_NULL); if (abort_search) return(0); if (value <= alpha) { value=Search(-MATE,beta,wtm,depth-2*INCREMENT_PLY,ply,DO_NULL); if (abort_search) return(0); } else if (value < beta) { if ((int) pv[ply-1].path_length >= ply) hash_move[ply]=pv[ply-1].path[ply]; } else hash_move[ply]=current_move[ply]; last[ply]=last[ply-1]; next_status[ply].phase=FIRST_PHASE; } /* ---------------------------------------------------------- | | | now iterate through the move list and search the | | resulting positions. note that Search() culls any | | move that is not legal by using Check(). the special | | case is that we must find one legal move to search to | | confirm that it's not a mate or draw. | | | ---------------------------------------------------------- */ while ((current_phase[ply]=(in_check[ply]) ? NextEvasion(ply,wtm) : NextMove(depth,ply,wtm))) { extended_reason[ply]&=check_extension; #if !defined(FAST) if (ply <= trace_level) SearchTrace(ply,depth,wtm,alpha,beta,"Search",current_phase[ply]); #endif /* ---------------------------------------------------------- | | | if two successive moves are capture / re-capture so | | that the material score is restored, extend the search | | by one ply on the re-capture since it is pretty much | | forced and easy to analyze. | | | ---------------------------------------------------------- */ extensions=-INCREMENT_PLY; if (Captured(current_move[ply]) && Captured(current_move[ply-1]) && To(current_move[ply-1]) == To(current_move[ply]) && (p_values[Captured(current_move[ply-1])+7] == p_values[Captured(current_move[ply])+7] || Promote(current_move[ply-1])) && !(extended_reason[ply-1]&recapture_extension)) { extended_reason[ply]|=recapture_extension; recapture_extensions_done++; extensions+=RECAPTURE; } /* ---------------------------------------------------------- | | | if we push a passed pawn, we need to look deeper to | | see if it is a legitimate threat. | | | ---------------------------------------------------------- */ if (Piece(current_move[ply])==pawn && !FutileAhead(wtm) && ((wtm && To(current_move[ply])>H5 && TotalBlackPieces<16 && !And(mask_pawn_passed_w[To(current_move[ply])],BlackPawns)) || (!wtm && To(current_move[ply])<A4 && TotalWhitePieces<16 && !And(mask_pawn_passed_b[To(current_move[ply])],WhitePawns)) || push_extensions[To(current_move[ply])]) && Swap(From(current_move[ply]),To(current_move[ply]),wtm) >= 0) { extended_reason[ply]|=passed_pawn_extension; passed_pawn_extensions_done++; extensions+=PASSED_PAWN_PUSH; } /* ---------------------------------------------------------- | | | now make the move and search the resulting position. | | if we are in check, the current move must be legal | | since NextEvasion ensures this, otherwise we have to | | make sure the side-on-move is not in check after the | | move to weed out illegal moves and save time. | | | ---------------------------------------------------------- */ MakeMove(ply,current_move[ply],wtm); if (in_check[ply] || !Check(wtm)) { /* ---------------------------------------------------------- | | | if the move to be made checks the opponent, then we | | need to remember that he's in check and also extend | | the depth by one ply for him to get out. | | | ---------------------------------------------------------- */ if (Check(ChangeSide(wtm))) { in_check[ply+1]=1; extended_reason[ply+1]=check_extension; check_extensions_done++; extensions+=IN_CHECK; } else { in_check[ply+1]=0; extended_reason[ply+1]=no_extension; } /* ---------------------------------------------------------- | | | now we toss in the "razoring" trick, which simply says | | if we are doing fairly badly, we can reduce the depth | | an additional ply, if there was nothing at the current | | ply that caused an extension. | | | ---------------------------------------------------------- */ if (depth < 3*INCREMENT_PLY && !in_check[ply] && extensions == -INCREMENT_PLY) { register int val=(wtm) ? Material : -Material; if (val+1500 < alpha) extensions-=INCREMENT_PLY; } /* ---------------------------------------------------------- | | | if there's only one legal move, extend the search one | | additional ply since this node is very easy to search. | | | ---------------------------------------------------------- */ if (first_move) { if (last[ply]-last[ply-1] == 1) { extended_reason[ply]|=one_reply_extension; one_reply_extensions_done++; extensions+=ONE_REPLY_TO_CHECK; } if (depth+MaxExtensions(extensions) >= INCREMENT_PLY) value=-Search(-beta,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL); else { value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1); } if (abort_search) { UnMakeMove(ply,current_move[ply],wtm); return(0); } first_move=0; } else { if (depth+MaxExtensions(extensions) >= INCREMENT_PLY) value=-Search(-alpha-1,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL); else { value=-Quiesce(-alpha-1,-alpha,ChangeSide(wtm),ply+1); } if (abort_search) { UnMakeMove(ply,current_move[ply],wtm); return(0); } if (value>alpha && value<beta) { if (depth+MaxExtensions(extensions) >= INCREMENT_PLY) value=-Search(-beta,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL); else value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1); if (abort_search) { UnMakeMove(ply,current_move[ply],wtm); return(0); } } } if (value > alpha) { if(value >= beta) { HistoryRefutation(ply,depth,wtm); UnMakeMove(ply,current_move[ply],wtm); StoreRefutation(ply,depth,wtm,beta); return(beta); } alpha=value; } } UnMakeMove(ply,current_move[ply],wtm); } /* ---------------------------------------------------------- | | | all moves have been searched. if none were legal, | | return either MATE or DRAW depending on whether the | | side to move is in check or not. | | | ---------------------------------------------------------- */ if (first_move == 1) { value=(Check(wtm)) ? -(MATE-ply) : ((wtm==root_wtm) ? DrawScore() : -DrawScore()); if(value > beta) value=beta; else if (value < alpha) value=alpha; if (value >=alpha && value <beta) { SavePV(ply,value,0); #if !defined(FAST) if (ply <= trace_level) printf("Search() no moves! ply=%d\n",ply); #endif } return(value); } else { if (alpha != initial_alpha) { memcpy(&pv[ply-1].path[ply],&pv[ply].path[ply],(pv[ply].path_length-ply+1)*4); memcpy(&pv[ply-1].path_hashed,&pv[ply].path_hashed,3); pv[ply-1].path[ply-1]=current_move[ply-1]; HistoryBest(ply,depth,wtm); } StoreBest(ply,depth,wtm,alpha,initial_alpha); /* ---------------------------------------------------------- | | | if the 50-move rule is drawing close, then adjust the | | score to reflect the impending draw. | | | ---------------------------------------------------------- */ if (Rule50Moves(ply) > 99) { value=(wtm==root_wtm) ? DrawScore() : -DrawScore(); if (value < beta) SavePV(ply,value,0); #if !defined(FAST) if(ply <= trace_level) printf("draw by 50-move rule detected, ply=%d.\n",ply); #endif return(value); } return(alpha); } }
void preprocessEvalInformation(ChessBoard * board) { // store the positions of the chess pieces into the eval info BITBOARD occupied = board->occupied; while (occupied != 0) { short nextOffset = FirstOne(occupied); occupied ^= offset_to_mask(nextOffset); switch (board->boardContents[nextOffset]) { case PAWN_WHITE: board->eval->whitePawns[board->eval->whitePawnsNum] = nextOffset; ++board->eval->whitePawnsNum; break; case KNIGHT_WHITE: board->eval->whiteKnights[board->eval->whiteKnightsNum] = nextOffset; ++board->eval->whiteKnightsNum; break; case BISHOP_WHITE: board->eval->whiteBishops[board->eval->whiteBishopsNum] = nextOffset; ++board->eval->whiteBishopsNum; break; case ROOK_WHITE: board->eval->whiteRooks[board->eval->whiteRooksNum] = nextOffset; ++board->eval->whiteRooksNum; break; case QUEEN_WHITE: board->eval->whiteQueens[board->eval->whiteQueensNum] = nextOffset; ++board->eval->whiteQueensNum; break; case PAWN_BLACK: board->eval->blackPawns[board->eval->blackPawnsNum] = nextOffset; ++board->eval->blackPawnsNum; break; case KNIGHT_BLACK: board->eval->blackKnights[board->eval->blackKnightsNum] = nextOffset; ++board->eval->blackKnightsNum; break; case BISHOP_BLACK: board->eval->blackBishops[board->eval->blackBishopsNum] = nextOffset; ++board->eval->blackBishopsNum; break; case ROOK_BLACK: board->eval->blackRooks[board->eval->blackRooksNum] = nextOffset; ++board->eval->blackRooksNum; break; case QUEEN_BLACK: board->eval->blackQueens[board->eval->blackQueensNum] = nextOffset; ++board->eval->blackQueensNum; break; } } board->eval->pieceWhiteMaterialScore = board->eval->whiteKnightsNum * EvalParameters::KnightScore + board->eval->whiteBishopsNum * EvalParameters::BishopScore + board->eval->whiteRooksNum * EvalParameters::RookScore + board->eval->whiteQueensNum * EvalParameters::QueenScore ; board->eval->rawWhiteMaterialScore = board->eval->pieceWhiteMaterialScore + board->eval->whitePawnsNum * EvalParameters::PawnScore ; board->eval->pieceBlackMaterialScore = board->eval->blackKnightsNum * EvalParameters::KnightScore + board->eval->blackBishopsNum * EvalParameters::BishopScore + board->eval->blackRooksNum * EvalParameters::RookScore + board->eval->blackQueensNum * EvalParameters::QueenScore ; board->eval->rawBlackMaterialScore = board->eval->pieceBlackMaterialScore + board->eval->blackPawnsNum * EvalParameters::PawnScore ; setGamePhase(board); }
static int probe_tb_capts(struct Player *player, struct Player *opp, bitboard player_occ, bitboard opp_occ, int alpha, int beta, int *capts) { int i, j; *capts = 0; if (opp->num > 1) { for (i = 0; i < player->num; i++) { int from = player->pos[i]; bitboard bb = PieceRange(from, player->type[i], player_occ | opp_occ) & opp_occ; if (bb) { *capts = 1; opp->num--; bitboard occ2 = player_occ ^ bit[from]; do { int to = FirstOne(bb); player->pos[i] = to; for (j = 0; opp->pos[j] != to; j++); int tmp_type = opp->type[j]; opp->type[j] = opp->type[opp->num]; opp->pos[j] = opp->pos[opp->num]; #ifdef HAS_PAWNS // FIXME: optimise if ((player->type[i] & 0x07) == PAWN && ((to + 0x08) & 0x30) == 0) { int t = player->type[i]; int m; for (m = KING - PAWN; m >= KNIGHT - PAWN; m--) { player->type[i] = t + m; int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha); if (v > alpha) { alpha = v; if (alpha >= beta) break; } } player->type[i] = t; } else { #endif int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha); if (v > alpha) alpha = v; #ifdef HAS_PAWNS } #endif opp->type[j] = tmp_type; opp->pos[j] = to; if (alpha >= beta) { player->pos[i] = from; opp->num++; return alpha; } ClearFirst(bb); } while (bb); player->pos[i] = from; opp->num++; } } } else { for (i = 0; i < player->num; i++) { bitboard bb = PieceRange(player->pos[i], player->type[i], player_occ) & opp_occ; if (bb) { *capts = 1; return -2; } } } return alpha; }
void InitializeAttackBoards(void) { int i, j, frank, ffile, trank, tfile; int sq, lastsq; int knightsq[8]={-17,-15,-10,-6,6,10,15,17}; int bishopsq[4]={-9,-7,7,9}; int rooksq[4]={-8,-1,1,8}; BITBOARD sqs; /* initialize pawn attack boards */ for(i=0;i<64;i++) { w_pawn_attacks[i]=0; if (i < 56) for(j=2;j<4;j++) { sq=i+bishopsq[j]; if((abs(sq/8-i/8)==1) && (abs((sq&7) - (i&7))==1) && (sq < 64) && (sq > -1)) w_pawn_attacks[i]=Or(w_pawn_attacks[i],Shiftr(mask_1,sq)); } b_pawn_attacks[i]=0; if (i > 7) for(j=0;j<2;j++) { sq=i+bishopsq[j]; if((abs(sq/8-i/8)==1) && (abs((sq&7)-(i&7))==1) && (sq < 64) && (sq > -1)) b_pawn_attacks[i]=Or(b_pawn_attacks[i],Shiftr(mask_1,sq)); } } /* initialize knight attack board */ for(i=0;i<64;i++) { knight_attacks[i]=0; frank=i/8; ffile=i&7; for(j=0;j<8;j++) { sq=i+knightsq[j]; if((sq < 0) || (sq > 63)) continue; trank=sq/8; tfile=sq&7; if((abs(frank-trank) > 2) || (abs(ffile-tfile) > 2)) continue; knight_attacks[i]=Or(knight_attacks[i],Shiftr(mask_1,sq)); } } /* initialize bishop/queen attack boards and masks */ for(i=0;i<64;i++) { bishop_attacks[i]=0; for(j=0;j<4;j++) { sq=i; lastsq=sq; sq=sq+bishopsq[j]; while((abs(sq/8-lastsq/8)==1) && (abs((sq&7)-(lastsq&7))==1) && (sq < 64) && (sq > -1)) { bishop_attacks[i]=Or(bishop_attacks[i],Shiftr(mask_1,sq)); queen_attacks[i]=Or(queen_attacks[i],Shiftr(mask_1,sq)); if(bishopsq[j]==7) plus7dir[i]=Or(plus7dir[i],Shiftr(mask_1,sq)); else if(bishopsq[j]==9) plus9dir[i]=Or(plus9dir[i],Shiftr(mask_1,sq)); else if(bishopsq[j]==-7) minus7dir[i]=Or(minus7dir[i],Shiftr(mask_1,sq)); else minus9dir[i]=Or(minus9dir[i],Shiftr(mask_1,sq)); lastsq=sq; sq=sq+bishopsq[j]; } } } plus1dir[64]=0; plus7dir[64]=0; plus8dir[64]=0; plus9dir[64]=0; minus1dir[64]=0; minus7dir[64]=0; minus8dir[64]=0; minus9dir[64]=0; /* initialize rook/queen attack boards */ for(i=0;i<64;i++) { rook_attacks[i]=0; for(j=0;j<4;j++) { sq=i; lastsq=sq; sq=sq+rooksq[j]; while((((abs(sq/8-lastsq/8)==1) && (abs((sq&7)-(lastsq&7))==0)) || ((abs(sq/8-lastsq/8)==0) && (abs((sq&7)-(lastsq&7))==1))) && (sq < 64) && (sq > -1)) { rook_attacks[i]=Or(rook_attacks[i],Shiftr(mask_1,sq)); queen_attacks[i]=Or(queen_attacks[i],Shiftr(mask_1,sq)); if(rooksq[j]==1) plus1dir[i]=Or(plus1dir[i],Shiftr(mask_1,sq)); else if(rooksq[j]==8) plus8dir[i]=Or(plus8dir[i],Shiftr(mask_1,sq)); else if(rooksq[j]==-1) minus1dir[i]=Or(minus1dir[i],Shiftr(mask_1,sq)); else minus8dir[i]=Or(minus8dir[i],Shiftr(mask_1,sq)); lastsq=sq; sq=sq+rooksq[j]; } } } /* initialize king attack board */ for(i=0;i<64;i++) { king_attacks[i]=0; king_attacks_1[i]=0; king_attacks_2[i]=0; for (j=0;j<64;j++) { if (Distance(i,j) == 1) king_attacks[i]=Or(king_attacks[i],set_mask[j]); if (Distance(i,j) <= 1) king_attacks_1[i]=Or(king_attacks_1[i],set_mask[j]); if (Distance(i,j) <= 2) king_attacks_2[i]=Or(king_attacks_2[i],set_mask[j]); } } /* direction[sq1][sq2] gives the "move direction" to move from sq1 to sq2. obstructed[sq1][sq2] gives a bit vector that indicates which squares must be unoccupied in order for <sq1> to attack <sq2>, assuming a sliding piece is involved. to use this, you simply have to Or(obstructed[sq1][sq2],occupied_squares) and if the result is "0" then a sliding piece on sq1 would attack sq2 and vice-versa. */ for (i=0;i<64;i++) { for (j=0;j<64;j++) obstructed[i][j]=(BITBOARD) -1; sqs=plus1dir[i]; while (sqs) { j=FirstOne(sqs); directions[i][j]=1; obstructed[i][j]=Xor(plus1dir[i],plus1dir[j-1]); Clear(j,sqs); } sqs=plus7dir[i]; while (sqs) { j=FirstOne(sqs); directions[i][j]=7; obstructed[i][j]=Xor(plus7dir[i],plus7dir[j-7]); Clear(j,sqs); } sqs=plus8dir[i]; while (sqs) { j=FirstOne(sqs); directions[i][j]=8; obstructed[i][j]=Xor(plus8dir[i],plus8dir[j-8]); Clear(j,sqs); } sqs=plus9dir[i]; while (sqs) { j=FirstOne(sqs); directions[i][j]=9; obstructed[i][j]=Xor(plus9dir[i],plus9dir[j-9]); Clear(j,sqs); } sqs=minus1dir[i]; while (sqs) { j=FirstOne(sqs); directions[i][j]=-1; obstructed[i][j]=Xor(minus1dir[i],minus1dir[j+1]); Clear(j,sqs); } sqs=minus7dir[i]; while (sqs) { j=FirstOne(sqs); directions[i][j]=-7; obstructed[i][j]=Xor(minus7dir[i],minus7dir[j+7]); Clear(j,sqs); } sqs=minus8dir[i]; while (sqs) { j=FirstOne(sqs); directions[i][j]=-8; obstructed[i][j]=Xor(minus8dir[i],minus8dir[j+8]); Clear(j,sqs); } sqs=minus9dir[i]; while (sqs) { j=FirstOne(sqs); directions[i][j]=-9; obstructed[i][j]=Xor(minus9dir[i],minus9dir[j+9]); Clear(j,sqs); } } { int diag_sq[64] = { 0, 1, 0, 2, 1, 0, 3, 2, 1, 0, 4, 3, 2, 1, 0, 5, 4, 3, 2, 1, 0, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0, 6, 5, 4, 3, 2, 1, 0, 5, 4, 3, 2, 1, 0, 4, 3, 2, 1, 0, 3, 2, 1, 0, 2, 1, 0, 1, 0, 0 }; int bias_rl45[64] = { 0, 1, 1, 3, 3, 3, 6, 6, 6, 6, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 15, 21, 21, 21, 21, 21, 21, 21, 28, 28, 28, 28, 28, 28, 28, 28, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 49, 49, 49, 49, 49, 54, 54, 54, 54, 58, 58, 58, 61, 61, 63 }; int square, pcs, attacks; int rsq, tsq; int mask; /* initialize the rotated attack board that is based on the normal chess */ for (square=0;square<64;square++) { for (i=0;i<256;i++) { rook_attacks_r0[square][i]=0; rook_mobility_r0[square][i]=0; } for (pcs=0;pcs<256;pcs++) { attacks=InitializeFindAttacks(7-File(square),pcs,8); while (attacks) { sq=first_ones_8bit[attacks]; rook_attacks_r0[square][pcs]= Or(rook_attacks_r0[square][pcs],set_mask[(square&56)+sq]); attacks=attacks&(~(1<<(7-sq))); } rook_mobility_r0[square][pcs]=PopCnt(rook_attacks_r0[square][pcs]); } } /* initialize the rotated attack board that is based on one that rotated left 90 degrees (which lines up a file horizontally, rather than its normal vertical orientation.) */ for (square=0;square<64;square++) { for (i=0;i<256;i++) { rook_attacks_rl90[square][i]=0; rook_mobility_rl90[square][i]=0; } for (pcs=0;pcs<256;pcs++) { attacks=InitializeFindAttacks(Rank(square),pcs,8); while (attacks) { sq=first_ones_8bit[attacks]; rook_attacks_rl90[square][pcs]= Or(rook_attacks_rl90[square][pcs], set_mask[init_r90[((square&7)<<3)+sq]]); attacks=attacks&(~(1<<(7-sq))); } rook_mobility_rl90[square][pcs]=PopCnt(rook_attacks_rl90[square][pcs]); } } /* initialize the rotated attack board that is based on one that is rotated left 45 degrees (which lines up the (a8-h1) diagonal horizontally. */ for (square=0;square<64;square++) { for (i=0;i<256;i++) { bishop_attacks_rl45[square][i]=0; bishop_mobility_rl45[square][i]=0; } for (pcs=0;pcs<(1<<diagonal_length[init_l45[square]]);pcs++) { rsq=init_l45[square]; tsq=diag_sq[rsq]; attacks=InitializeFindAttacks(tsq,pcs,diagonal_length[rsq])<< (8-diagonal_length[rsq]); while (attacks) { sq=first_ones_8bit[attacks]; bishop_attacks_rl45[square][pcs]= Or(bishop_attacks_rl45[square][pcs], set_mask[init_ul45[sq+bias_rl45[rsq]]]); attacks=attacks&(~(1<<(7-sq))); } } mask=(1<<diagonal_length[init_l45[square]])-1; for (pcs=0;pcs<256;pcs++) { if ((pcs&mask) != pcs) bishop_attacks_rl45[square][pcs]= bishop_attacks_rl45[square][pcs&mask]; bishop_mobility_rl45[square][pcs]= PopCnt(bishop_attacks_rl45[square][pcs]); } } /* initialize the rotated attack board that is based on one that is rotated right 45 degrees (which lines up the (a1-h8) diagonal horizontally, */ for (square=0;square<64;square++) { for (i=0;i<256;i++) { bishop_attacks_rr45[square][i]=0; bishop_mobility_rr45[square][i]=0; } for (pcs=0;pcs<(1<<diagonal_length[init_r45[square]]);pcs++) { rsq=init_r45[square]; tsq=diag_sq[rsq]; attacks=InitializeFindAttacks(tsq,pcs,diagonal_length[rsq])<< (8-diagonal_length[rsq]); while (attacks) { sq=first_ones_8bit[attacks]; bishop_attacks_rr45[square][pcs]= Or(bishop_attacks_rr45[square][pcs], set_mask[init_ur45[sq+bias_rl45[rsq]]]); attacks=attacks&(~(1<<(7-sq))); } } mask=(1<<diagonal_length[init_r45[square]])-1; for (pcs=0;pcs<256;pcs++) { if ((pcs&mask) != pcs) bishop_attacks_rr45[square][pcs]= bishop_attacks_rr45[square][pcs&mask]; bishop_mobility_rr45[square][pcs]= PopCnt(bishop_attacks_rr45[square][pcs]); } } } }
/* ******************************************************************************** * * * Swap() is used to analyze capture moves to see whether or not they appear * * to be profitable. the basic algorithm is extremely fast since it uses the * * bitmaps to determine which squares are attacking the [target] square. * * * * the algorithm is quite simple. using the attack bitmaps, we enumerate all * * the pieces that are attacking [target] for either side. then we simply * * use the lowest piece (value) for the correct side to capture on [target]. * * we continually "flip" sides taking the lowest piece each time. * * * * as a piece is used, if it is a sliding piece (pawn, bishop, rook or queen) * * we "peek" behind it to see if it is attacked by a sliding piece in the * * direction away from the piece being captured. if so, and that sliding * * piece moves in this direction, then it is added to the list of attackers * * since its attack has been "uncovered" by moving the capturing piece. * * * ******************************************************************************** */ int Swap(int source, int target, int wtm) { register BITBOARD attacks; register int attacked_piece; register int square, direction; register int sign, color, next_capture=1; int swap_list[32]; /* ---------------------------------------------------------- | | | determine which squares attack <target> for each side. | | | ---------------------------------------------------------- */ attacks=AttacksTo(target); /* ---------------------------------------------------------- | | | initialize by placing the piece on <target> first in | | the list as it is being captured to start things off. | | | ---------------------------------------------------------- */ attacked_piece=p_values[PieceOnSquare(target)+7]; /* ---------------------------------------------------------- | | | the first piece to capture on <target> is the piece | | standing on <source>. | | | ---------------------------------------------------------- */ color=ChangeSide(wtm); swap_list[0]=attacked_piece; sign=-1; attacked_piece=p_values[PieceOnSquare(source)+7]; Clear(source,attacks); direction=directions[target][source]; if (direction) attacks=SwapXray(attacks,source,direction); /* ---------------------------------------------------------- | | | now pick out the least valuable piece for the correct | | side that is bearing on <target>. as we find one, we | | call SwapXray() to add the piece behind this piece | | that is indirectly bearing on <target> (if any). | | | ---------------------------------------------------------- */ while (attacks) { if (color) { if (And(WhitePawns,attacks)) square=FirstOne(And(WhitePawns,attacks)); else if (And(WhiteKnights,attacks)) square=FirstOne(And(WhiteKnights,attacks)); else if (And(WhiteBishops,attacks)) square=FirstOne(And(WhiteBishops,attacks)); else if (And(WhiteRooks,attacks)) square=FirstOne(And(WhiteRooks,attacks)); else if (And(WhiteQueens,attacks)) square=FirstOne(And(WhiteQueens,attacks)); else if (And(WhiteKing,attacks)) square=WhiteKingSQ; else break; } else { if (And(BlackPawns,attacks)) square=FirstOne(And(BlackPawns,attacks)); else if (And(BlackKnights,attacks)) square=FirstOne(And(BlackKnights,attacks)); else if (And(BlackBishops,attacks)) square=FirstOne(And(BlackBishops,attacks)); else if (And(BlackRooks,attacks)) square=FirstOne(And(BlackRooks,attacks)); else if (And(BlackQueens,attacks)) square=FirstOne(And(BlackQueens,attacks)); else if (And(BlackKing,attacks)) square=BlackKingSQ; else break; } /* ------------------------------------------------ | | | located the least valuable piece bearing on | | <target>. remove it from the list and then | | find out if a sliding piece behind it attacks | | through this piece. | | | ------------------------------------------------ */ swap_list[next_capture]=swap_list[next_capture-1]+sign*attacked_piece; attacked_piece=p_values[PieceOnSquare(square)+7]; Clear(square,attacks); direction=directions[target][square]; if (direction) attacks=SwapXray(attacks,square,direction); next_capture++; sign=-sign; color=ChangeSide(color); } /* ---------------------------------------------------------- | | | starting at the end of the sequence of values, use a | | "minimax" like procedure to decide where the captures | | will stop. | | | ---------------------------------------------------------- */ next_capture--; if(next_capture&1) sign=-1; else sign=1; while (next_capture) { if (sign < 0) { if(swap_list[next_capture] <= swap_list[next_capture-1]) swap_list[next_capture-1]=swap_list[next_capture]; } else { if(swap_list[next_capture] >= swap_list[next_capture-1]) swap_list[next_capture-1]=swap_list[next_capture]; } next_capture--; sign=-sign; } return (swap_list[0]); }
void FindGoodCatRules(Node *n,int VarI, int *RuleInd,int &firstone) // finds out which categorical rule using VarI are good. // a good rule is one that does not result in logically empty bottom nodes //n: the node at which the rule is to be set //VarI: the variable ~ the rule //RuleInd: integer vector whose length is the number of possible rules 2^(NR-1) - 1 // on exit 1 if rule ok 0 otherwise, already allocated //firstone: first category still "alive" at node n, depends on tree above n { int i,j; int NR = RuleNum[VarI]; int *sel = new int [NR+1]; int numrul = (int)pow(2.0,NR-1)-1; for(i=1;i<=numrul;i++) RuleInd[i]=0; int *cats = new int [NR+1]; GetSetCats(n,VarI,cats); firstone = FirstOne(NR,cats); if(!firstone) { Rprintf("error in FindGoodCatRule: no availble cats\n"); } else { sel[firstone]=1; } int *sel1 = new int [NR-1+1]; NodeP *lbotvec; int lnbot; MakeBotVec(n->LeftC,&lbotvec,&lnbot); //note lbotvec allocated here int *lfcount=new int [lnbot+1]; //allocation NodeP *rbotvec; int rnbot; MakeBotVec(n->RightC,&rbotvec,&rnbot); //note rbotvec allocated here int *rfcount=new int [rnbot+1]; //allocation // for eachrule see if it is any good // you do this be sending the categories left or right according to the rule // and checking to make sure that no bottom nodes are empty for(i=0;i<numrul;i++) { indtd(NR-1,i,sel1); for(j=1;j<firstone;j++) sel[j]=sel1[j]; for(j=(firstone+1);j<=NR;j++) sel[j] = sel1[j-1]; for(j=1;j<=lnbot;j++) lfcount[j]=0; for(j=1;j<=rnbot;j++) rfcount[j]=0; for(j=1;j<=NR;j++) { if(cats[j]) { if(sel[j]) { CatFindBots(n->RightC,VarI,j,rbotvec,rfcount); } else { CatFindBots(n->LeftC,VarI,j,lbotvec,lfcount); } } if((NoZero(lnbot,lfcount)) && (NoZero(rnbot,rfcount))) { RuleInd[i+1]=1; break; } } } delete [] sel; delete [] sel1; delete [] cats; delete [] lbotvec; delete [] rbotvec; delete [] lfcount; delete [] rfcount; }