// 駒割り以外の全計算 // pos.st->BKPP,WKPP,KPPを初期化する。Position::set()で一度だけ呼び出される。(以降は差分計算) // 手番側から見た評価値を返すので注意。(他の評価関数とは設計がこの点において異なる) Value compute_eval(const Position& pos) { Square sq_bk = pos.king_square(BLACK); Square sq_wk = pos.king_square(WHITE); const auto* ppkppb = kpp[sq_bk]; const auto* ppkppw = kpp[Inv(sq_wk)]; auto& pos_ = *const_cast<Position*>(&pos); auto list_fb = pos_.eval_list()->piece_list_fb(); auto list_fw = pos_.eval_list()->piece_list_fw(); int i, j; BonaPiece k0, k1,l0,l1; // 評価値の合計 EvalSum sum; // SSE2は少なくとも有るという前提で。 // sum.p[0](BKPP)とsum.p[1](WKPP)をゼロクリア sum.m[0] = _mm_setzero_si128(); // KK sum.p[2] = kk[sq_bk][sq_wk]; for (i = 0; i < PIECE_NO_KING; ++i) { k0 = list_fb[i]; k1 = list_fw[i]; const auto* pkppb = ppkppb[k0]; const auto* pkppw = ppkppw[k1]; for (j = 0; j < i; ++j) { l0 = list_fb[j]; l1 = list_fw[j]; #if 0 sum.p[0] += pkppb[l0]; sum.p[1] += pkppw[l1]; #else // SSEによる実装 // pkppw[l1][0],pkppw[l1][1],pkppb[l0][0],pkppb[l0][1]の16bit変数4つを整数拡張で32bit化して足し合わせる __m128i tmp; tmp = _mm_set_epi32(0, 0, *reinterpret_cast<const int32_t*>(&pkppw[l1][0]), *reinterpret_cast<const int32_t*>(&pkppb[l0][0])); tmp = _mm_cvtepi16_epi32(tmp); sum.m[0] = _mm_add_epi32(sum.m[0], tmp); #endif } sum.p[2] += kkp[sq_bk][sq_wk][k0]; } auto& info = *pos.state(); info.sum = sum; sum.p[2][0] += pos.state()->materialValue * FV_SCALE; return Value(sum.sum(pos.side_to_move()) / FV_SCALE); }
// 評価関数が正しいかどうかを判定するのに使う Value Position::evaluate_correct(const Color us) const { int list0[PIECENUMBER_MAX + 1]; //駒番号numのlist0 int list1[PIECENUMBER_MAX + 1]; //駒番号numのlist1 int nlist = make_list_correct(list0, list1); const int sq_bk = SQ_BKING; const int sq_wk = SQ_WKING; const auto* ppkppb = Evaluater::KPP[sq_bk]; const auto* ppkppw = Evaluater::KPP[Inv(sq_wk)]; EvalSum score; score.p[2] = Evaluater::KK[sq_bk][sq_wk]; #if defined USE_AVX2_EVAL || defined USE_SSE_EVAL score.m[0] = _mm_setzero_si128(); for (int i = 0; i < nlist; ++i) { const int k0 = list0[i]; const int k1 = list1[i]; const auto* pkppb = ppkppb[k0]; const auto* pkppw = ppkppw[k1]; for (int j = 0; j < i; ++j) { const int l0 = list0[j]; const int l1 = list1[j]; __m128i tmp; tmp = _mm_set_epi32(0, 0, *reinterpret_cast<const int32_t*>(&pkppw[l1][0]), *reinterpret_cast<const int32_t*>(&pkppb[l0][0])); tmp = _mm_cvtepi16_epi32(tmp); score.m[0] = _mm_add_epi32(score.m[0], tmp); } score.p[2] += Evaluater::KKP[sq_bk][sq_wk][k0]; } #else score.p[0][0] = 0; score.p[0][1] = 0; score.p[1][0] = 0; score.p[1][1] = 0; for (int i = 0; i < nlist; i++ ) { const int k0 = list0[i]; const int k1 = list1[i]; assert(0 <= k0 && k0 < fe_end); assert(0 <= k1 && k1 < fe_end); const auto* pkppb = ppkppb[k0]; const auto* pkppw = ppkppw[k1]; for (int j = 0; j < i; j++ ) { const int l0 = list0[j]; const int l1 = list1[j]; assert(0 <= l0 && l0 < fe_end); assert(0 <= l1 && l1 < fe_end); score.p[0] += pkppb[l0]; score.p[1] += pkppw[l1]; } score.p[2] += Evaluater::KKP[sq_bk][sq_wk][k0]; } #endif score.p[2][0] += MATERIAL * FV_SCALE; return Value(score.sum(us) / FV_SCALE); }
Value Position::evaluate(const Color us, SearchStack* ss) { const int sq_bk = SQ_BKING; const int sq_wk = SQ_WKING; assert(0 <= sq_bk && sq_bk < nsquare); assert(0 <= sq_wk && sq_wk < nsquare); const auto* ppkppb = Evaluater::KPP[sq_bk ]; const auto* ppkppw = Evaluater::KPP[Inv(sq_wk)]; EvalSum score; score.p[2] = Evaluater::KK[sq_bk][sq_wk]; #if defined USE_AVX2_EVAL || defined USE_SSE_EVAL score.m[0] = _mm_setzero_si128(); for (int kn = PIECENUMBER_MIN; kn <= PIECENUMBER_MAX; kn++) { const int k0 = list0[kn]; const int k1 = list1[kn]; const auto* pkppb = ppkppb[k0]; const auto* pkppw = ppkppw[k1]; for (int j = PIECENUMBER_MIN; j < kn; j++) { const int l0 = list0[j]; const int l1 = list1[j]; __m128i tmp; tmp = _mm_set_epi32(0, 0, *reinterpret_cast<const int32_t*>(&pkppw[l1][0]), *reinterpret_cast<const int32_t*>(&pkppb[l0][0])); tmp = _mm_cvtepi16_epi32(tmp); score.m[0] = _mm_add_epi32(score.m[0], tmp); } score.p[2] += Evaluater::KKP[sq_bk][sq_wk][k0]; } #else score.p[0][0] = 0; score.p[0][1] = 0; score.p[1][0] = 0; score.p[1][1] = 0; for (int i = 0; i < nlist; i++ ) { const int k0 = list0[i]; const int k1 = list1[i]; assert(0 <= k0 && k0 < fe_end); assert(0 <= k1 && k1 < fe_end); const auto* pkppb = ppkppb[k0]; const auto* pkppw = ppkppw[k1]; for (int j = 0; j < i; j++ ) { const int l0 = list0[j]; const int l1 = list1[j]; assert(0 <= l0 && l0 < fe_end); assert(0 <= l1 && l1 < fe_end); score.p[0] += pkppb[l0]; score.p[1] += pkppw[l1]; } score.p[2] += Evaluater::KKP[sq_bk][sq_wk][k0]; } #endif score.p[2][0] += MATERIAL * FV_SCALE; return Value(score.sum(us) / FV_SCALE); }
Value calc_diff_kpp(const Position& pos) { // 過去に遡って差分を計算していく。 auto st = pos.state(); // すでに計算されている。rootか? EvalSum sum; if (st->sum.p[2][0] != INT_MAX) { sum = st->sum; goto CALC_DIFF_END; } // 遡るのは一つだけ // ひとつずつ遡りながらsumKPPがVALUE_NONEでないところまで探してそこからの差分を計算することは出来るが // レアケースだし、StateInfoにEvalListを持たせる必要が出てきて、あまり得しない。 auto now = st; auto prev = st->previous; if (prev->sum.p[2][0] == INT_MAX) { // 全計算 return compute_eval(pos); } // この差分を求める { sum = prev->sum; int k0, k1, k2, k3; auto sq_bk0 = pos.king_square(BLACK); auto sq_wk0 = pos.king_square(WHITE); auto sq_wk1 = Inv(pos.king_square(WHITE)); auto now_list_fb = pos.eval_list()->piece_list_fb(); auto now_list_fw = pos.eval_list()->piece_list_fw(); int i, j; auto& dp = now->dirtyPiece; // 移動させた駒は最大2つある。その数 int k = dp.dirty_num; auto dirty = dp.pieceNo[0]; if (dirty >= PIECE_NO_KING) // 王と王でないかで場合分け { if (dirty == PIECE_NO_BKING) { // ---------------------------- // 先手玉が移動したときの計算 // ---------------------------- // 現在の玉の位置に移動させて計算する。 // 先手玉に関するKKP,KPPは全計算なので一つ前の値は関係ない。 // BKPP sum.p[0][0] = 0; sum.p[0][1] = 0; // このときKKPは差分で済まない。 sum.p[2] = Eval::kk[sq_bk0][sq_wk0]; // 片側まるごと計算 for (i = 0; i < PIECE_NO_KING; i++) { k0 = now_list_fb[i]; sum.p[2] += Eval::kkp[sq_bk0][sq_wk0][k0]; for (j = 0; j < i; j++) sum.p[0] += Eval::kpp[sq_bk0][k0][now_list_fb[j]]; } // もうひとつの駒がないならこれで計算終わりなのだが。 if (k == 2) { // この駒についての差分計算をしないといけない。 k1 = dp.piecePrevious[1].fw; k3 = dp.pieceNow[1].fw; dirty = dp.pieceNo[1]; // BKPPはすでに計算済みなのでWKPPのみ。 // WKは移動していないのでこれは前のままでいい。 for (i = 0; i < dirty; ++i) { sum.p[1] -= Eval::kpp[sq_wk1][k1][now_list_fw[i]]; sum.p[1] += Eval::kpp[sq_wk1][k3][now_list_fw[i]]; } for (++i; i < PIECE_NO_KING; ++i) { sum.p[1] -= Eval::kpp[sq_wk1][k1][now_list_fw[i]]; sum.p[1] += Eval::kpp[sq_wk1][k3][now_list_fw[i]]; } } } else { // ---------------------------- // 後手玉が移動したときの計算 // ---------------------------- ASSERT_LV3(dirty == PIECE_NO_WKING); // WKPP sum.p[1][0] = 0; sum.p[1][1] = 0; sum.p[2] = Eval::kk[sq_bk0][sq_wk0]; for (i = 0; i < PIECE_NO_KING; i++) { k0 = now_list_fb[i]; // これ、KKPテーブルにk1側も入れておいて欲しい気はするが.. k1 = now_list_fw[i]; sum.p[2] += Eval::kkp[sq_bk0][sq_wk0][k0]; for (j = 0; j < i; j++) sum.p[1] += Eval::kpp[sq_wk1][k1][now_list_fw[j]]; } if (k == 2) { k0 = dp.piecePrevious[1].fb; k2 = dp.pieceNow[1].fb; dirty = dp.pieceNo[1]; for (i = 0; i < dirty; ++i) { sum.p[0] -= Eval::kpp[sq_bk0][k0][now_list_fb[i]]; sum.p[0] += Eval::kpp[sq_bk0][k2][now_list_fb[i]]; } for (++i; i < PIECE_NO_KING; ++i) { sum.p[0] -= Eval::kpp[sq_bk0][k0][now_list_fb[i]]; sum.p[0] += Eval::kpp[sq_bk0][k2][now_list_fb[i]]; } } } } else { // ---------------------------- // 玉以外が移動したときの計算 // ---------------------------- #define ADD_BWKPP(W0,W1,W2,W3) { \ sum.p[0] -= Eval::kpp[sq_bk0][W0][now_list_fb[i]]; \ sum.p[1] -= Eval::kpp[sq_wk1][W1][now_list_fw[i]]; \ sum.p[0] += Eval::kpp[sq_bk0][W2][now_list_fb[i]]; \ sum.p[1] += Eval::kpp[sq_wk1][W3][now_list_fw[i]]; \ } if (k == 1) { // 移動した駒が一つ。 k0 = dp.piecePrevious[0].fb; k1 = dp.piecePrevious[0].fw; k2 = dp.pieceNow[0].fb; k3 = dp.pieceNow[0].fw; // KKP差分 sum.p[2] -= Eval::kkp[sq_bk0][sq_wk0][k0]; sum.p[2] += Eval::kkp[sq_bk0][sq_wk0][k2]; // KP値、要らんのでi==dirtyを除く for (i = 0; i < dirty; ++i) ADD_BWKPP(k0, k1, k2, k3); for (++i; i < PIECE_NO_KING; ++i) ADD_BWKPP(k0, k1, k2, k3); } else if (k == 2) { // 移動する駒が王以外の2つ。 PieceNo dirty2 = dp.pieceNo[1]; if (dirty > dirty2) swap(dirty, dirty2); // PIECE_NO_ZERO <= dirty < dirty2 < PIECE_NO_KING // にしておく。 k0 = dp.piecePrevious[0].fb; k1 = dp.piecePrevious[0].fw; k2 = dp.pieceNow[0].fb; k3 = dp.pieceNow[0].fw; int m0, m1, m2, m3; m0 = dp.piecePrevious[1].fb; m1 = dp.piecePrevious[1].fw; m2 = dp.pieceNow[1].fb; m3 = dp.pieceNow[1].fw; // KKP差分 sum.p[2] -= Eval::kkp[sq_bk0][sq_wk0][k0]; sum.p[2] += Eval::kkp[sq_bk0][sq_wk0][k2]; sum.p[2] -= Eval::kkp[sq_bk0][sq_wk0][m0]; sum.p[2] += Eval::kkp[sq_bk0][sq_wk0][m2]; // KPP差分 for (i = 0; i < dirty; ++i) { ADD_BWKPP(k0, k1, k2, k3); ADD_BWKPP(m0, m1, m2, m3); } for (++i; i < dirty2; ++i) { ADD_BWKPP(k0, k1, k2, k3); ADD_BWKPP(m0, m1, m2, m3); } for (++i; i < PIECE_NO_KING; ++i) { ADD_BWKPP(k0, k1, k2, k3); ADD_BWKPP(m0, m1, m2, m3); } sum.p[0] -= Eval::kpp[sq_bk0][k0][m0]; sum.p[1] -= Eval::kpp[sq_wk1][k1][m1]; sum.p[0] += Eval::kpp[sq_bk0][k2][m2]; sum.p[1] += Eval::kpp[sq_wk1][k3][m3]; } } } now->sum = sum; // 差分計算終わり CALC_DIFF_END:; sum.p[2][0] += pos.state()->materialValue * FV_SCALE; return Value(sum.sum(pos.side_to_move()) / FV_SCALE); }
int Position::evaluate(const Color us) const { int list0[NLIST], list1[NLIST]; int sq_bk, sq_wk; #ifndef TWIG int score; #else EvalSum score; #endif static int count=0; count++; int nlist=0; // 持ち駒をリスト化する #define FOO(hand, Piece, list0_index, list1_index) \ for (int i = I2Hand##Piece(hand); i >= 1; --i) { \ list0[nlist] = list0_index + i; \ list1[nlist] = list1_index + i; \ ++nlist; \ } FOO(HAND_B, Pawn , f_hand_pawn , e_hand_pawn ) FOO(HAND_W, Pawn , e_hand_pawn , f_hand_pawn ) FOO(HAND_B, Lance , f_hand_lance , e_hand_lance ) FOO(HAND_W, Lance , e_hand_lance , f_hand_lance ) FOO(HAND_B, Knight, f_hand_knight, e_hand_knight) FOO(HAND_W, Knight, e_hand_knight, f_hand_knight) FOO(HAND_B, Silver, f_hand_silver, e_hand_silver) FOO(HAND_W, Silver, e_hand_silver, f_hand_silver) FOO(HAND_B, Gold , f_hand_gold , e_hand_gold ) FOO(HAND_W, Gold , e_hand_gold , f_hand_gold ) FOO(HAND_B, Bishop, f_hand_bishop, e_hand_bishop) FOO(HAND_W, Bishop, e_hand_bishop, f_hand_bishop) FOO(HAND_B, Rook , f_hand_rook , e_hand_rook ) FOO(HAND_W, Rook , e_hand_rook , f_hand_rook ) #undef FOO nlist = make_list_apery(list0, list1, nlist); sq_bk = SQ_BKING; sq_wk = SQ_WKING; assert(0 <= sq_bk && sq_bk < nsquare); assert(0 <= sq_wk && sq_wk < nsquare); const auto* ppkppb = KPP[sq_bk ]; const auto* ppkppw = KPP[Inv(sq_wk)]; #ifndef TWIG score = fv_kk[sq_bk][sq_wk]; for (int i = 0; i < nlist; i++ ) { const int k0 = list0[i]; const int k1 = list1[i]; assert(0 <= k0 && k0 < fe_end); assert(0 <= k1 && k1 < fe_end); const auto* pkppb = ppkppb[k0]; const auto* pkppw = ppkppw[k1]; for (int j = 0; j < i; j++ ) { const int l0 = list0[j]; const int l1 = list1[j]; assert(0 <= l0 && l0 < fe_end); assert(0 <= l1 && l1 < fe_end); score += pkppb[l0]; score -= pkppw[l1]; } score += fv_kkp[sq_bk][sq_wk][k0]; } score += MATERIAL * FV_SCALE; score /= FV_SCALE; score = (us == BLACK) ? score : -score; return score; #else EvalSum sum; sum.p[2] = KK[sq_bk][sq_wk]; #if defined USE_AVX2_EVAL || defined USE_SSE_EVAL sum.m[0] = _mm_setzero_si128(); for (int i = 0; i < nlist; ++i) { const int k0 = list0[i]; const int k1 = list1[i]; const auto* pkppb = ppkppb[k0]; const auto* pkppw = ppkppw[k1]; for (int j = 0; j < i; ++j) { const int l0 = list0[j]; const int l1 = list1[j]; __m128i tmp; tmp = _mm_set_epi32(0, 0, *reinterpret_cast<const int32_t*>(&pkppw[l1][0]), *reinterpret_cast<const int32_t*>(&pkppb[l0][0])); tmp = _mm_cvtepi16_epi32(tmp); sum.m[0] = _mm_add_epi32(sum.m[0], tmp); } sum.p[2] += KKP[sq_bk][sq_wk][k0]; } sum.p[2][0] += MATERIAL * FV_SCALE; #else // loop 開始を i = 1 からにして、i = 0 の分のKKPを先に足す。 sum.p[2] += KKP[sq_bk][sq_wk][list0[0]]; sum.p[0][0] = 0; sum.p[0][1] = 0; sum.p[1][0] = 0; sum.p[1][1] = 0; for (int i = 1; i < nlist; ++i) { const int k0 = list0[i]; const int k1 = list1[i]; const auto* pkppb = ppkppb[k0]; const auto* pkppw = ppkppw[k1]; for (int j = 0; j < i; ++j) { const int l0 = list0[j]; const int l1 = list1[j]; sum.p[0] += pkppb[l0]; sum.p[1] += pkppw[l1]; } sum.p[2] += KKP[sq_bk][sq_wk][k0]; } sum.p[2][0] += MATERIAL * FV_SCALE; #endif #ifdef _DEBUG score.p[2] = KK[sq_bk][sq_wk]; score.p[0][0] = 0; score.p[0][1] = 0; score.p[1][0] = 0; score.p[1][1] = 0; for (int i = 0; i < nlist; ++i) { const int k0 = list0[i]; const int k1 = list1[i]; const auto* pkppb = ppkppb[k0]; const auto* pkppw = ppkppw[k1]; for (int j = 0; j < i; ++j) { const int l0 = list0[j]; const int l1 = list1[j]; score.p[0][0] += pkppb[l0][0]; score.p[0][1] += pkppb[l0][1]; score.p[1][0] += pkppw[l1][0]; score.p[1][1] += pkppw[l1][1]; } score.p[2][0] += KKP[sq_bk][sq_wk][k0][0]; score.p[2][1] += KKP[sq_bk][sq_wk][k0][1]; } score.p[2][0] += MATERIAL * FV_SCALE; assert(score.sum(us) == sum.sum(us)); #endif return sum.sum(us) / FV_SCALE ; #endif }