void cEval::ScoreUnstoppable(eData *e, POS * p) { U64 bbPieces, bbSpan, bbProm; int w_dist = 8; int b_dist = 8; int sq, ksq, psq, tempo, prom_dist; // White unstoppable passers if (p->cnt[BC][N] + p->cnt[BC][B] + p->cnt[BC][R] + p->cnt[BC][Q] == 0) { ksq = KingSq(p, BC); if (p->side == BC) tempo = 1; else tempo = 0; bbPieces = p->Pawns(WC); while (bbPieces) { sq = BB.PopFirstBit(&bbPieces); if (!(Mask.passed[WC][sq] & p->Pawns(BC))) { bbSpan = BB.GetFrontSpan(SqBb(sq), WC); psq = ((WC - 1) & 56) + (sq & 7); prom_dist = Min(5, Param.chebyshev_dist[sq][psq]); if (prom_dist < (Param.chebyshev_dist[ksq][psq] - tempo)) { if (bbSpan & p->Kings(WC)) prom_dist++; w_dist = Min(w_dist, prom_dist); } } } } // Black unstoppable passers if (p->cnt[WC][N] + p->cnt[WC][B] + p->cnt[WC][R] + p->cnt[WC][Q] == 0) { ksq = KingSq(p, WC); if (p->side == WC) tempo = 1; else tempo = 0; bbPieces = p->Pawns(BC); while (bbPieces) { sq = BB.PopFirstBit(&bbPieces); if (!(Mask.passed[BC][sq] & p->Pawns(WC))) { bbSpan = BB.GetFrontSpan(SqBb(sq), BC); if (bbSpan & p->Kings(WC)) tempo -= 1; psq = ((BC - 1) & 56) + (sq & 7); prom_dist = Min(5, Param.chebyshev_dist[sq][psq]); if (prom_dist < (Param.chebyshev_dist[ksq][psq] - tempo)) { if (bbSpan & p->Kings(BC)) prom_dist++; b_dist = Min(b_dist, prom_dist); } } } } if (w_dist < b_dist-1) Add(e, WC, F_PASSERS, 0, 500); if (b_dist < w_dist-1) Add(e, BC, F_PASSERS, 0, 500); }
void cEval::ScoreKing(POS *p, int sd) { const int startSq[2] = { E1, E8 }; const int qCastle[2] = { B1, B8 }; const int kCastle[2] = { G1, G8 }; U64 bbKingFile, bbNextFile; int result = 0; int sq = KingSq(p, sd); // Normalize king square for pawn shield evaluation, // to discourage shuffling the king between g1 and h1. if (SqBb(sq) & bbKSCastle[sd]) sq = kCastle[sd]; if (SqBb(sq) & bbQSCastle[sd]) sq = qCastle[sd]; // Evaluate shielding and storming pawns on each file. bbKingFile = BB.FillNorthSq(sq) | BB.FillSouthSq(sq); result += ScoreKingFile(p, sd, bbKingFile); bbNextFile = ShiftEast(bbKingFile); if (bbNextFile) result += ScoreKingFile(p, sd, bbNextFile); bbNextFile = ShiftWest(bbKingFile); if (bbNextFile) result += ScoreKingFile(p, sd, bbNextFile); mg[sd][F_PAWNS] += result; mg[sd][F_PAWNS] += ScoreChains(p, sd); }
void cEval::ScorePieces(POS *p, eData *e, int sd) { U64 bbPieces, bbMob, bbAtt, bbFile, bbContact; int op, sq, cnt, tmp, ksq, att = 0, wood = 0; int own_pawn_cnt, opp_pawn_cnt; int r_on_7th = 0; int fwd_weight = 0; int fwd_cnt = 0; // Is color OK? assert(sd == WC || sd == BC); // Init variables op = Opp(sd); ksq = KingSq(p, op); U64 bbExcluded = p->Pawns(sd) /*| p->Kings(sd)*/; // Init enemy king zone for attack evaluation. We mark squares where the king // can move plus two or three more squares facing enemy position. U64 bbZone = Mask.king_zone[sd][ksq]; // Init bitboards to detect check threats U64 bbKnightChk = BB.KnightAttacks(ksq); U64 bbStr8Chk = BB.RookAttacks(OccBb(p), ksq); U64 bbDiagChk = BB.BishAttacks(OccBb(p), ksq); U64 bbQueenChk = bbStr8Chk | bbDiagChk; // Knight bbPieces = p->Knights(sd); while (bbPieces) { sq = BB.PopFirstBit(&bbPieces); // Knight tropism to enemy king Add(e, sd, F_TROPISM, tropism_mg[N] * Param.dist[sq][ksq], tropism_eg[N] * Param.dist[sq][ksq]); // Knight forwardness if (SqBb(sq) & bbAwayZone[sd]) { fwd_weight += 1; fwd_cnt += 1; } // Knight mobility bbMob = BB.KnightAttacks(sq) & ~p->cl_bb[sd]; // knight is tricky, cnt = BB.PopCnt(bbMob &~e->bbPawnTakes[op]); // better to have it mobile than defending stuff Add(e, sd, F_MOB, Param.n_mob_mg[cnt], Param.n_mob_eg[cnt]); // mobility bonus if ((bbMob &~e->bbPawnTakes[op]) & bbKnightChk) att += chk_threat[N]; // check threat bonus e->bbAllAttacks[sd] |= BB.KnightAttacks(sq); e->bbEvAttacks[sd] |= bbMob; // Knight attacks on enemy king zone bbAtt = BB.KnightAttacks(sq); if (bbAtt & bbZone) { wood++; att += king_att[N] * BB.PopCnt(bbAtt & bbZone); } // Knight outpost ScoreOutpost(p, e, sd, N, sq); } // end of knight eval // Bishop bbPieces = p->Bishops(sd); while (bbPieces) { sq = BB.PopFirstBit(&bbPieces); // Bishop tropism to enemy king Add(e, sd, F_TROPISM, tropism_mg[B] * Param.dist[sq][ksq], tropism_eg[B] * Param.dist[sq][ksq]); // Bishop forwardness if (SqBb(sq) & bbAwayZone[sd]) { fwd_weight += 1; fwd_cnt += 1; } // Bishop mobility bbMob = BB.BishAttacks(OccBb(p), sq); if (!(bbMob & bbAwayZone[sd])) // penalty for bishops unable to reach enemy half of the board Add(e, sd, F_MOB, Param.bishConfined); // (idea from Andscacs) cnt = BB.PopCnt(bbMob &~e->bbPawnTakes[op] &~bbExcluded); Add(e, sd, F_MOB, Param.b_mob_mg[cnt], Param.b_mob_eg[cnt]); // mobility bonus if ((bbMob &~e->bbPawnTakes[op]) & ~p->cl_bb[sd] & bbDiagChk) att += chk_threat[B]; // check threat bonus e->bbAllAttacks[sd] |= bbMob; e->bbEvAttacks[sd] |= bbMob; // Bishop attacks on enemy king zone (including attacks through a queen) bbAtt = BB.BishAttacks(OccBb(p) ^ p->Queens(sd) , sq); if (bbAtt & bbZone) { wood++; att += king_att[B] * BB.PopCnt(bbAtt & bbZone); } // Bishop outpost ScoreOutpost(p, e, sd, B, sq); // Bishops side by side if (ShiftNorth(SqBb(sq)) & p->Bishops(sd) ) Add(e, sd, F_OTHERS, 4); if (ShiftEast(SqBb(sq)) & p->Bishops(sd)) Add(e, sd, F_OTHERS, 4); // Pawns on the same square color as our bishop if (bbWhiteSq & SqBb(sq)) { own_pawn_cnt = BB.PopCnt(bbWhiteSq & p->Pawns(sd)) - 4; opp_pawn_cnt = BB.PopCnt(bbWhiteSq & p->Pawns(op)) - 4; } else { own_pawn_cnt = BB.PopCnt(bbBlackSq & p->Pawns(sd)) - 4; opp_pawn_cnt = BB.PopCnt(bbBlackSq & p->Pawns(op)) - 4; } Add(e, sd, F_OTHERS, -3 * own_pawn_cnt - opp_pawn_cnt); } // end of bishop eval // Rook bbPieces = p->Rooks(sd); while (bbPieces) { sq = BB.PopFirstBit(&bbPieces); // Rook tropism to enemy king Add(e, sd, F_TROPISM, tropism_mg[R] * Param.dist[sq][ksq], tropism_eg[R] * Param.dist[sq][ksq]); // Rook forwardness if (SqBb(sq) & bbAwayZone[sd]) { fwd_weight += 2; fwd_cnt += 1; } // Rook mobility bbMob = BB.RookAttacks(OccBb(p), sq); cnt = BB.PopCnt(bbMob &~bbExcluded); Add(e, sd, F_MOB, Param.r_mob_mg[cnt], Param.r_mob_eg[cnt]); // mobility bonus if (((bbMob &~e->bbPawnTakes[op]) & ~p->cl_bb[sd] & bbStr8Chk) // check threat bonus && p->cnt[sd][Q]) { att += chk_threat[R]; bbContact = (bbMob & BB.KingAttacks(ksq)) & bbStr8Chk; while (bbContact) { int contactSq = BB.PopFirstBit(&bbContact); // rook exchanges are accepted as contact checks if (Swap(p, sq, contactSq) >= 0) { att += r_contact_check; break; } } } e->bbAllAttacks[sd] |= bbMob; e->bbEvAttacks[sd] |= bbMob; // Rook attacks on enemy king zone (also through a rook or through a queen) bbAtt = BB.RookAttacks(OccBb(p) ^ p->StraightMovers(sd), sq); if (bbAtt & bbZone) { wood++; att += king_att[R] * BB.PopCnt(bbAtt & bbZone); } // Get rook file bbFile = BB.FillNorthSq(sq) | BB.FillSouthSq(sq); // better this way than using front span // Queen on rook's file (which might be closed) if (bbFile & p->Queens(op)) Add(e, sd, F_LINES, Param.rookOnQueen); // Rook on (half) open file if (!(bbFile & p->Pawns(sd))) { if (!(bbFile & p->Pawns(op))) { Add(e, sd, F_LINES, Param.rookOnOpenMg, Param.rookOnOpenEg); //if (BB.GetFrontSpan(SqBb(sq), sd) & p->Rooks(sd)) Add(e, sd, F_LINES, 4, 2); // equal } else { // score differs depending on whether half-open file is blocked by defended enemy pawn if ((bbFile & p->Pawns(op)) & e->bbPawnTakes[op]) Add(e, sd, F_LINES, Param.rookOnBadHalfOpenMg, Param.rookOnBadHalfOpenEg); else { Add(e, sd, F_LINES, Param.rookOnGoodHalfOpenMg, Param.rookOnGoodHalfOpenEg); } } } // Rook on the 7th rank attacking pawns or cutting off enemy king if (SqBb(sq) & bbRelRank[sd][RANK_7]) { if (p->Pawns(op) & bbRelRank[sd][RANK_7] || p->Kings(op) & bbRelRank[sd][RANK_8]) { Add(e, sd, F_LINES, Param.rookOn7thMg, Param.rookOn7thEg); r_on_7th++; } } } // end of rook eval // Queen bbPieces = p->Queens(sd); while (bbPieces) { sq = BB.PopFirstBit(&bbPieces); // Queen tropism to enemy king Add(e, sd, F_TROPISM, tropism_mg[Q] * Param.dist[sq][ksq], tropism_eg[Q] * Param.dist[sq][ksq]); // Queen forwardness if (SqBb(sq) & bbAwayZone[sd]) { fwd_weight += 4; fwd_cnt += 1; } // Queen mobility bbMob = BB.QueenAttacks(OccBb(p), sq); cnt = BB.PopCnt(bbMob &~bbExcluded); Add(e, sd, F_MOB, Param.q_mob_mg[cnt], Param.q_mob_eg[cnt]); // mobility bonus if ((bbMob &~e->bbPawnTakes[op]) & ~p->cl_bb[sd] & bbQueenChk) { // check threat bonus att += chk_threat[Q]; // Queen contact checks bbContact = bbMob & BB.KingAttacks(ksq); while (bbContact) { int contactSq = BB.PopFirstBit(&bbContact); // queen exchanges are accepted as contact checks if (Swap(p, sq, contactSq) >= 0) { att += q_contact_check; break; } } } e->bbAllAttacks[sd] |= bbMob; // Queen attacks on enemy king zone bbAtt = BB.BishAttacks(OccBb(p) ^ p->DiagMovers(sd), sq); bbAtt |= BB.RookAttacks(OccBb(p) ^ p->StraightMovers(sd), sq); if (bbAtt & bbZone) { wood++; att += king_att[Q] * BB.PopCnt(bbAtt & bbZone); } // Queen on 7th rank if (SqBb(sq) & bbRelRank[sd][RANK_7]) { if (p->Pawns(op) & bbRelRank[sd][RANK_7] || p->Kings(op) & bbRelRank[sd][RANK_8]) { Add(e, sd, F_LINES, Param.queenOn7thMg, Param.queenOn7thEg); } } } // end of queen eval // Score terms using information gathered during piece eval if (r_on_7th > 1) // two rooks on 7th rank Add(e, sd, F_LINES, Param.twoRooksOn7thMg, Param.twoRooksOn7thEg); // forwardness (from Toga II 3.0) Add(e, sd, (fwd_bonus[fwd_cnt] * fwd_weight * Param.forwardness) / 100, 0); // Score king attacks if own queen is present and there are at least 2 attackers if (wood > 1 && p->cnt[sd][Q]) { if (att > 399) att = 399; Add(e, sd, F_ATT, Param.danger[att]); } }