int GetDrawFactor(POS *p, int sd) { int op = Opp(sd); // Case 1: KPK with edge pawn (else KBPK recognizer would break) if (PcMatNone(p, sd) && PcMatNone(p, op) && p->cnt[sd][P] == 1 // TODO: all pawns of a stronger side on a rim && p->cnt[op][P] == 0) { // TODO: accept pawns for a weaker side if (p->Pawns(sd) & FILE_H_BB && p->Kings(op) & bbKingBlockH[sd]) return 0; if (p->Pawns(sd) & FILE_A_BB && p->Kings(op) & bbKingBlockA[sd]) return 0; } // Case 2: KBPK(P) draws with edge pawn and wrong bishop if (PcMatB(p, sd) && PcMatNone(p, op) && p->cnt[sd][P] == 1) { // TODO: all pawns of a stronger side on a rim if (p->Pawns(sd) & FILE_H_BB && NotOnBishColor(p, sd, REL_SQ(H8, sd)) && p->Kings(op) & bbKingBlockH[sd]) return 0; if (p->Pawns(sd) & FILE_A_BB && NotOnBishColor(p, sd, REL_SQ(A8, sd)) && p->Kings(op) & bbKingBlockA[sd]) return 0; } // Case 3: KBP vs Km // drawn when defending king stands on pawn's path and can't be driven out // by a bishop (must be dealt with before opposite bishops ending) if (PcMatB(p, sd) && PcMat1Minor(p, op) && p->cnt[sd][P] == 1 && p->cnt[op][P] == 0 && (SqBb(p->king_sq[op]) & BB.GetFrontSpan(p->Pawns(sd), sd)) && NotOnBishColor(p, sd, p->king_sq[op]) ) return 0; // Case 4: Bishops of opposite color if (PcMatB(p, sd) && PcMatB(p, op) && DifferentBishops(p)) { // 4a: single bishop cannot win without pawns if (p->cnt[sd][P] == 0) return 0; // 4b: different bishops with a single pawn on the own half of the board if (p->cnt[sd][P] == 1 && p->cnt[op][P] == 0) { if (bbHomeZone[sd] & p->Pawns(sd)) return 0; // TODO: 4c: distant bishop controls a square on pawn's path } // 4d: halve the score for pure BOC endings return 32; } if (p->cnt[sd][P] == 0) { // Case 5: low and almost equal material with no pawns if (p->cnt[op][P] == 0) { if (PcMatRm(p, sd) && PcMatRm(p, op)) return 8; if (PcMatR (p, sd) && PcMatR (p, op)) return 8; if (PcMatQ (p, sd) && PcMatQ (p, op)) return 8; if (PcMat2Minors(p, sd) && PcMatR(p, op)) return 8; } // Case 6: two knights if (PcMatNN(p, sd)) { if (p->cnt[op][P] == 0) return 0; else return 4; } // Case 7: K(m) vs K(m) or Km vs Kp(p) if (p->cnt[sd][Q] + p->cnt[sd][R] == 0 && p->cnt[sd][B] + p->cnt[sd][N] < 2 ) return 0; // Case 8: KR vs Km(p) if (PcMatR(p, sd) && PcMat1Minor(p, op) ) return 16; // Case 9: KRm vs KR(p) if (p->cnt[sd][R] == 1 && p->cnt[sd][Q] == 0 && p->cnt[sd][B] + p->cnt[sd][N] == 1 && PcMatR(p, op) ) return 16; // Case 10: KQm vs KQ(p) if (p->cnt[sd][Q] == 1 && p->cnt[sd][R] == 0 && p->cnt[sd][B] + p->cnt[sd][N] == 1 && PcMatQ(p, op) ) return 32; // Case 11: Kmm vs KB(p) if (PcMat2Minors(p,sd) && PcMatB(p, op) ) return 16; // Case 12: KBN vs Km(p) if (PcMatBN(p, sd) && PcMat1Minor(p, op) ) return 16; // Case 13: KRR vs KRm(p) if (PcMatRR(p, sd) && PcMatRm(p, op)) return 16; // Case 14: KRRm vs KRR(p) if (p->cnt[sd][R] == 2 && p->cnt[sd][Q] == 0 && p->cnt[sd][B] + p->cnt[sd][N] == 1 && PcMatRR(p, op)) return 16; } // Case 15: KRP vs KR if (PcMatR(p, sd) && PcMatR(p, op) && p->cnt[sd][P] == 1 && p->cnt[op][P] == 0) { // 15a: good defensive position with a king on pawn's path increases drawing chances if ((SqBb(p->king_sq[op]) & BB.GetFrontSpan(p->Pawns(sd), sd))) return 32; // 1/2 // 15b: draw code for rook endgame with edge pawn if ((RelSqBb(A7, sd) & p->Pawns(sd)) && ( RelSqBb(A8, sd) & p->Rooks(sd)) && ( FILE_A_BB & p->Rooks(op)) && ((RelSqBb(H7, sd) & p->Kings(op)) || (RelSqBb(G7, sd) & p->Kings(op))) ) return 0; // dead draw if ((RelSqBb(H7, sd) & p->Pawns(sd)) && ( RelSqBb(H8, sd) & p->Rooks(sd)) && ( FILE_H_BB & p->Rooks(op)) && ((RelSqBb(A7, sd) & p->Kings(op)) || (RelSqBb(B7, sd) & p->Kings(op))) ) return 0; // dead draw } return 64; }
void cParam::DynamicInit(void) { Eval.prog_side = NO_CL; ResetEngine(); // Init piece/square values together with material value of the pieces. for (int sq = 0; sq < 64; sq++) { for (int sd = 0; sd < 2; sd++) { mg_pst[sd][P][REL_SQ(sq, sd)] = SCALE(pc_value[P], mat_perc) + SCALE(pstPawnMg[pst_style][sq], pst_perc); eg_pst[sd][P][REL_SQ(sq, sd)] = SCALE(pc_value[P], mat_perc) + SCALE(pstPawnEg[pst_style][sq], pst_perc); mg_pst[sd][N][REL_SQ(sq, sd)] = SCALE(pc_value[N], mat_perc) + SCALE(pstKnightMg[pst_style][sq], pst_perc); eg_pst[sd][N][REL_SQ(sq, sd)] = SCALE(pc_value[N], mat_perc) + SCALE(pstKnightEg[pst_style][sq], pst_perc); mg_pst[sd][B][REL_SQ(sq, sd)] = SCALE(pc_value[B], mat_perc) + SCALE(pstBishopMg[pst_style][sq], pst_perc); eg_pst[sd][B][REL_SQ(sq, sd)] = SCALE(pc_value[B], mat_perc) + SCALE(pstBishopEg[pst_style][sq], pst_perc); mg_pst[sd][R][REL_SQ(sq, sd)] = SCALE(pc_value[R], mat_perc) + SCALE(pstRookMg[pst_style][sq], pst_perc); eg_pst[sd][R][REL_SQ(sq, sd)] = SCALE(pc_value[R], mat_perc) + SCALE(pstRookEg[pst_style][sq], pst_perc); mg_pst[sd][Q][REL_SQ(sq, sd)] = SCALE(pc_value[Q], mat_perc) + SCALE(pstQueenMg[pst_style][sq], pst_perc); eg_pst[sd][Q][REL_SQ(sq, sd)] = SCALE(pc_value[Q], mat_perc) + SCALE(pstQueenEg[pst_style][sq], pst_perc); mg_pst[sd][K][REL_SQ(sq, sd)] = pstKingMg[pst_style][sq]; eg_pst[sd][K][REL_SQ(sq, sd)] = pstKingEg[pst_style][sq]; phalanx[sd][REL_SQ(sq, sd)] = pstPhalanxPawn[sq]; defended[sd][REL_SQ(sq, sd)] = pstDefendedPawn[sq]; sp_pst_data[sd][N][REL_SQ(sq, sd)] = pstKnightOutpost[sq]; sp_pst_data[sd][B][REL_SQ(sq, sd)] = pstBishopOutpost[sq]; } } // Init tables for adjusting piece values // according to the number of own pawns for (int i = 0; i < 9; i++) { np_table[i] = adj[i] * np_bonus; rp_table[i] = adj[i] * rp_malus; } // Init backward pawns table, adding file offset to base value for (int i = 0; i < 8; i++) { backward_malus_mg[i] = backward_malus_base + file_adj[i]; } // Init imbalance table, so that we can expose option for exchange delta for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { // insert original values imbalance[i][j] = imbalance_data[i][j]; // insert value defined by the user if (imbalance[i][j] == Ex) imbalance[i][j] = exchange_imbalance; if (imbalance[i][j] == -Ex) imbalance[i][j] = -exchange_imbalance; } } // Init mobility tables if (mob_style == 0) { for (int i = 0; i < 9; i++) { n_mob_mg[i] = 4 * (i-4); n_mob_eg[i] = 4 * (i-4); } for (int i = 0; i < 14; i++) { b_mob_mg[i] = 5 * (i-7); b_mob_eg[i] = 5 * (i-7); } for (int i = 0; i < 15; i++) { r_mob_mg[i] = 2 * (i-7); r_mob_eg[i] = 4 * (i-7); } for (int i = 0; i < 28; i++) { q_mob_mg[i] = 1 * (i-14); q_mob_eg[i] = 2 * (i-14); } } if (mob_style == 1) { for (int i = 0; i < 9; i++) { n_mob_mg[i] = n_mob_mg_decreasing[i]; n_mob_eg[i] = n_mob_eg_decreasing[i]; } for (int i = 0; i < 14; i++) { b_mob_mg[i] = b_mob_mg_decreasing[i]; b_mob_eg[i] = b_mob_eg_decreasing[i]; } for (int i = 0; i < 15; i++) { r_mob_mg[i] = r_mob_mg_decreasing[i]; r_mob_eg[i] = r_mob_eg_decreasing[i]; } for (int i = 0; i < 28; i++) { q_mob_mg[i] = q_mob_mg_decreasing[i]; q_mob_eg[i] = q_mob_eg_decreasing[i]; } } // Init king attack table for (int t = 0, i = 1; i < 512; ++i) { t = Min(maxAttScore, Min(int(attCurveMult * i * i), t + maxAttStep)); danger[i] = (t * 100) / 256; // rescale to centipawns // TODO: init separately for Black and White in SetAsymmetricEval() to gain some speed } }