/* ******************************************************************************* * * * SetBoard() is used to set up the board in any position desired. It uses * * a forsythe-like string of characters to describe the board position. * * * * The standard piece codes p,n,b,r,q,k are used to denote the type of piece * * on a square, upper/lower case are used to indicate the side (program/opp.)* * of the piece. * * * * The pieces are entered with square a8 first, then b8, ... until the full * * 8th rank is completed. A "/" terminates that rank. This is repeated for * * each of the 8 ranks, with the last (1st) rank not needing a terminating * * "/". For empty squares, a number between 1 and 8 can be used to indicate * * the number of adjacent empty squares. * * * * That board description must be followed by a "b" or "w" to indicate which * * side is on move. * * * * Next, up to 4 characters are used to indicate which side can castle and * * to which side. An uppercase K means white can castle kingside, while a * * lowercase q means black can castle queenside. * * * * Finally, if there is an enpassant capture possible (the last move was a * * double pawn move and there was an enemy pawn that could capture it. The * * square is the square the capturing pawn ends up on. * * * * K2R/PPP////q/5ppp/7k/ b - - * * * * this assumes that k represents a white king and -q represents a black * * queen. * * * * k * * r * * * * * * p p p * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -q * * * * * * * * * * * * * * -p -p -p * * * * * * * * * -k * * * ******************************************************************************* */ void SetBoard(TREE * tree, int nargs, char *args[], int special) { int twtm, i, match, num, pos, square, tboard[64]; int bcastle, ep, wcastle, error = 0; char input[80]; static const char bdinfo[] = { 'k', 'q', 'r', 'b', 'n', 'p', '*', 'P', 'N', 'B', 'R', 'Q', 'K', '*', '1', '2', '3', '4', '5', '6', '7', '8', '/' }; static const char status[13] = { 'K', 'Q', 'k', 'q', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', ' ' }; int whichsq; static const int firstsq[8] = { 56, 48, 40, 32, 24, 16, 8, 0 }; if (special) strcpy(input, initial_position); else strcpy(input, args[0]); for (i = 0; i < 64; i++) tboard[i] = 0; /* ************************************************************ * * * Scan the input string searching for pieces, numbers * * [empty squares], slashes [end-of-rank] and a blank * * [end of board, start of castle status]. * * * ************************************************************ */ whichsq = 0; square = firstsq[whichsq]; num = 0; for (pos = 0; pos < (int) strlen(args[0]); pos++) { for (match = 0; match < 23 && args[0][pos] != bdinfo[match]; match++); if (match > 22) break; /* "/" -> end of this rank. */ else if (match == 22) { num = 0; if (whichsq > 6) break; square = firstsq[++whichsq]; } /* "1-8" -> empty squares. */ else if (match >= 14) { num += match - 13; square += match - 13; if (num > 8) { printf("more than 8 squares on one rank\n"); error = 1; break; } continue; } /* piece codes. */ else { if (++num > 8) { printf("more than 8 squares on one rank\n"); error = 1; break; } tboard[square++] = match - 6; } } /* ************************************************************ * * * Now extract (a) side to move [w/b], (b) castle status * * [KkQq for white/black king-side ok, white/black queen- * * side ok], (c) enpassant target square. * * * ************************************************************ */ twtm = 0; ep = 0; wcastle = 0; bcastle = 0; /* ************************************************************ * * * Side to move. * * * ************************************************************ */ if (args[1][0] == 'w') twtm = 1; else if (args[1][0] == 'b') twtm = 0; else { printf("side to move is bad\n"); error = 1; } /* ************************************************************ * * * Castling/enpassant status. * * * ************************************************************ */ if (nargs > 2 && strlen(args[2])) { if (strcmp(args[2], "-")) { for (pos = 0; pos < (int) strlen(args[2]); pos++) { for (match = 0; (match < 13) && (args[2][pos] != status[match]); match++); if (match == 0) wcastle += 1; else if (match == 1) wcastle += 2; else if (match == 2) bcastle += 1; else if (match == 3) bcastle += 2; else if (args[2][0] != '-') { printf("castling status is bad.\n"); error = 1; } } } } if (nargs > 3 && strlen(args[3])) { if (strcmp(args[3], "-")) { if (args[3][0] >= 'a' && args[3][0] <= 'h' && args[3][1] > '0' && args[3][1] < '9') { ep = (args[3][1] - '1') * 8 + args[3][0] - 'a'; } else if (args[3][0] != '-') { printf("enpassant status is bad.\n"); error = 1; } } } for (i = 0; i < 64; i++) PcOnSq(i) = tboard[i]; Castle(0, white) = wcastle; Castle(0, black) = bcastle; EnPassant(0) = 0; if (ep) { if (Rank(ep) == RANK6) { if (PcOnSq(ep - 8) != -pawn) ep = 0; } else if (Rank(ep) == RANK3) { if (PcOnSq(ep + 8) != pawn) ep = 0; } else ep = 0; if (!ep) { printf("enpassant status is bad (must be on 3rd/6th rank only.\n"); ep = 0; error = 1; } EnPassant(0) = ep; } Rule50Moves(0) = 0; /* ************************************************************ * * * Now check the castling status and enpassant status to * * make sure that the board is in a state that matches * * these. * * * ************************************************************ */ if (((Castle(0, white) & 2) && (PcOnSq(A1) != rook)) || ((Castle(0, white) & 1) && (PcOnSq(H1) != rook)) || ((Castle(0, black) & 2) && (PcOnSq(A8) != -rook)) || ((Castle(0, black) & 1) && (PcOnSq(H8) != -rook))) { printf("ERROR-- castling status does not match board position\n"); error = 1; } /* ************************************************************ * * * Now set the bitboards so that error tests can be done. * * * ************************************************************ */ if ((twtm && EnPassant(0) && (PcOnSq(EnPassant(0) + 8) != -pawn) && (PcOnSq(EnPassant(0) - 7) != pawn) && (PcOnSq(EnPassant(0) - 9) != pawn)) || (Flip(twtm) && EnPassant(0) && (PcOnSq(EnPassant(0) - 8) != pawn) && (PcOnSq(EnPassant(0) + 7) != -pawn) && (PcOnSq(EnPassant(0) + 9) != -pawn))) { EnPassant(0) = 0; } SetChessBitBoards(tree); /* ************************************************************ * * * Now check the position for a sane position, which * * means no more than 8 pawns, no more than 10 knights, * * bishops or rooks, no more than 9 queens, no pawns on * * 1st or 8th rank, etc. * * * ************************************************************ */ wtm = twtm; error += InvalidPosition(tree); if (!error) { if (log_file) DisplayChessBoard(log_file, tree->pos); tree->rep_index[white] = 0; tree->rep_index[black] = 0; Rule50Moves(0) = 0; if (!special) { last_mate_score = 0; InitializeKillers(); last_pv.pathd = 0; last_pv.pathl = 0; tree->pv[0].pathd = 0; tree->pv[0].pathl = 0; moves_out_of_book = 0; } } else { if (special) Print(4095, "bad string = \"%s\"\n", initial_position); else Print(4095, "bad string = \"%s\"\n", args[0]); InitializeChessBoard(tree); Print(4095, "Illegal position, using normal initial chess position\n"); } }
// 評価関数を38回固定ループにする為に、持ち駒0枚の評価値を他の評価値に足しこみ、持ち駒複数枚の評価値を差分化する。 void convertFV() { // K : 玉 // B : 盤上の駒 // 0 : 持ち駒 0 枚 // N, M : 持ち駒 0 枚以外 // K0, K00 を全て足し込んだテーブルを作成 for (Square ksqb = A9; ksqb < nsquare; ++ksqb) { for (Square ksqw = A9; ksqw < nsquare; ++ksqw) { int score = 0; for (int i = 0; i < 14; ++i) { const int k0 = Hand0FVIndex[i]; for (int j = 0; j <= i; ++j) { const int l0 = Hand0FVIndex[j]; score += PcPcOnSqAny(ksqb, k0, l0); // 本当は list0, list1 という風にした方が良いけど、 // 全部足すので何でも良い。 score -= PcPcOnSqAny(Inv(ksqw), k0, l0); } } mid_kk[ksqb][ksqw] = score; } } // KK0 も全て足し込む for (Square ksqB = A9; ksqB < nsquare; ++ksqB) { for (Square ksqW = A9; ksqW < nsquare; ++ksqW) { for (FVIndex elem : Hand0KKPFVIndex) { mid_kk[ksqB][ksqW] += kkp[ksqB ][ksqW ][elem]; mid_kk[ksqB][ksqW] -= kkp[Inv(ksqW)][Inv(ksqB)][elem]; } } } // K0B を KB に足し込む。 // 持ち駒 0 枚以外のとき、KB に余分な値が足し込まれているので、KNB で余分を引く。 for (Square ksq = A9; ksq < nsquare; ++ksq) { for (FVIndex ihand = f_hand_pawn; ihand < fe_hand_end; ++ihand) { for (FVIndex iboard = fe_hand_end; iboard < fe_end; ++iboard) { if (handIs0(ihand)) { MidPcOnSq(ksq, iboard) += PcPcOnSqAny(ksq, ihand, iboard); } else { const FVIndex ihand0 = hand0Index(ihand); MidPcPcOnSqAny(ksq, ihand, iboard) -= PcPcOnSqAny(ksq, ihand0, iboard); } } } } // K0N を KN に足し込む。 // K00 を KN から引く。 for (Square ksq = A9; ksq < nsquare; ++ksq) { for (FVIndex ihand0 : Hand0FVIndex) { for (FVIndex jhand = f_hand_pawn; jhand < fe_hand_end; ++jhand) { if (handIs0(jhand) ) { continue; } const FVIndex jhand0 = hand0Index(jhand); if (ihand0 == jhand0) { continue; // 同じ種類の持ち駒の 0 枚と それ以外の枚数は共存しない。 } MidPcOnSq(ksq, jhand) += PcPcOnSqAny(ksq, ihand0, jhand); MidPcOnSq(ksq, jhand) -= PcPcOnSqAny(ksq, ihand0, jhand0); } } } // KN に K0N が足し込まれている。 // KM に K0M が足し込まれている。 // よって、KNM から K0N, K0M を引く。 // 更に KN, KM から K00 を 2重に引いたので、K00 を KNM に足す。 for (Square ksq = A9; ksq < nsquare; ++ksq) { for (FVIndex ihand = f_hand_pawn; ihand < fe_hand_end; ++ihand) { if (handIs0(ihand)) { continue; } const FVIndex ihand0 = hand0Index(ihand); for (FVIndex jhand = f_hand_pawn; jhand < ihand0; ++jhand) { if (handIs0(jhand)) { continue; } const FVIndex jhand0 = hand0Index(jhand); MidPcPcOnSqAny(ksq, ihand, jhand) -= PcPcOnSqAny(ksq, ihand, jhand0) + PcPcOnSqAny(ksq, ihand0, jhand); MidPcPcOnSqAny(ksq, ihand, jhand) += PcPcOnSqAny(ksq, ihand0, jhand0); } } } // K0 を mid_kk テーブルに足しこんでいるので、KN から K0 を引く。 for (Square ksq = A9; ksq < nsquare; ++ksq) { for (FVIndex ihand0 : Hand0FVIndex) { for (int i = 18; 0 < i; --i) { if (4 < i && f_hand_lance <= ihand0) continue; if (2 < i && f_hand_bishop <= ihand0) continue; MidPcOnSq(ksq, ihand0 + i) -= PcOnSq(ksq, ihand0); } } } // 味方の同じ種類の駒の枚数違いは、本来無い組み合わせなので、0 にしないといけない。 for (Square ksq = A9; ksq < nsquare; ++ksq) { for (FVIndex ihand = f_hand_pawn; ihand < fe_hand_end; ++ihand) { const FVIndex ihand0 = hand0Index(ihand); for (FVIndex jhand = f_hand_pawn; jhand < ihand; ++jhand) { const FVIndex jhand0 = hand0Index(jhand); // 同じ種類の持ち駒のときかつ、駒の枚数が違うとき、0 にする。 if (ihand0 == jhand0 && ihand != jhand) { MidPcPcOnSq(ksq, ihand, jhand) = 0; } } } } // KPP 差分値化 // KBN を KB(N-1) との差分値にする。(1 < N のとき) for (Square ksq = A9; ksq < nsquare; ++ksq) { for (FVIndex iboard = fe_hand_end; iboard < fe_end; ++iboard) { for (FVIndex jhand0 : Hand0FVIndex) { for (int j = 18; 1 < j; --j) { if (4 < j && f_hand_lance <= jhand0) continue; if (2 < j && f_hand_bishop <= jhand0) continue; const FVIndex jhand = jhand0 + j; MidPcPcOnSq(ksq, iboard, jhand) -= MidPcPcOnSq(ksq, iboard, jhand - 1); } } } } // KP 差分値化 for (Square ksq = A9; ksq < nsquare; ++ksq) { for (FVIndex ihand0 : Hand0FVIndex) { for (int i = 18; 1 < i; --i) { if (4 < i && f_hand_lance <= ihand0) continue; if (2 < i && f_hand_bishop <= ihand0) continue; MidPcOnSq(ksq, ihand0 + i) -= MidPcOnSq(ksq, ihand0 + i - 1); } } } // KP を KP 用の配列に格納 for (Square ksq = A9; ksq < nsquare; ++ksq) { for (FVIndex i = f_hand_pawn; i < fe_end; ++i) { mid_kp[ksq][i] = MidPcOnSq(ksq, i); } } // KMN を差分化する。 for (Square ksq = A9; ksq < nsquare; ++ksq) { for (FVIndex ihand0 : Hand0FVIndex) { for (int i = 18; 0 < i; --i) { if (4 < i && f_hand_lance <= ihand0) continue; if (2 < i && f_hand_bishop <= ihand0) continue; const FVIndex ihand = ihand0 + i; for (FVIndex jhand0 : Hand0FVIndex) { if (ihand0 <= jhand0) continue; for (int j = 18; 0 < j; --j) { if (4 < j && f_hand_lance <= jhand0) continue; if (2 < j && f_hand_bishop <= jhand0) continue; const FVIndex jhand = jhand0 + j; if (1 < i && 1 < j) MidPcPcOnSq(ksq, ihand, jhand) += -MidPcPcOnSq(ksq, ihand - 1, jhand) - MidPcPcOnSq(ksq, ihand, jhand - 1) + MidPcPcOnSq(ksq, ihand - 1, jhand - 1); else if (1 < i ) MidPcPcOnSq(ksq, ihand, jhand) += -MidPcPcOnSq(ksq, ihand - 1, jhand); else if (1 < j ) MidPcPcOnSq(ksq, ihand, jhand) += -MidPcPcOnSq(ksq, ihand, jhand - 1); } } } } } // KP を評価関数で参照しなくて済むように、 // KP を KKP に足しこむ。 // 更に、KK に KK0 を押し込んだので、KKN から KK0 を引いておく。 for (Square ksqB = A9; ksqB < nsquare; ++ksqB) { for (Square ksqW = A9; ksqW < nsquare; ++ksqW) { auto handcopy = [&](const int handnum, const FVIndex kkp_hand_index) { for (int i = 0; i < handnum; ++i) { if (i != 0) { mid_kkp[ksqB][ksqW][kkp_hand_index + i] -= kkp[ksqB][ksqW][kkp_hand_index]; } } }; handcopy(19, kkp_hand_pawn ); handcopy( 5, kkp_hand_lance ); handcopy( 5, kkp_hand_knight); handcopy( 5, kkp_hand_silver); handcopy( 5, kkp_hand_gold ); handcopy( 3, kkp_hand_bishop); handcopy( 3, kkp_hand_rook ); } } // KP = 0 // 評価値の差分計算時に KP が邪魔にならないように 0 にしておく。 // 対局時は KP は KKP に足し込んでおけば良いが、 // 学習に使う際に KP と KKP それぞれの値を知りたい場合もあるので、 // KP を KKP に足し込まず、別途ファイルに出力しておく。 for (Square ksq = A9; ksq < nsquare; ++ksq) { for (FVIndex i = f_hand_pawn; i < fe_end; ++i) { MidPcOnSq(ksq, i) = 0; } } // KK0 = 0 // 特に必要ではないが、一応やっておく。 for (Square ksqB = A9; ksqB < nsquare; ++ksqB) { for (Square ksqW = A9; ksqW < nsquare; ++ksqW) { for (FVIndex elem : Hand0KKPFVIndex) { mid_kkp[ksqB][ksqW][elem] = 0; } } } // KKP 差分値化 for (Square ksqB = A9; ksqB < nsquare; ++ksqB) { for (Square ksqW = A9; ksqW < nsquare; ++ksqW) { for (FVIndex elem : Hand0KKPFVIndex) { for (int i = 18; 1 < i; --i) { if (4 < i && kkp_hand_lance <= elem) continue; if (2 < i && kkp_hand_bishop <= elem) continue; mid_kkp[ksqB][ksqW][elem + i] -= mid_kkp[ksqB][ksqW][elem + i - 1]; } } } } // KKP を KPP と同じインデックスで参照するようにする。 // 持ち駒について。 for (Square ksqB = A9; ksqB < nsquare; ++ksqB) { for (Square ksqW = A9; ksqW < nsquare; ++ksqW) { for (FVIndex elem : Hand0KKPFVIndex) { const auto fe_pair = g_kkpToKP[elem]; for (int i = 0; i < 19; ++i) { if (4 < i && kkp_hand_lance <= elem) continue; if (2 < i && kkp_hand_bishop <= elem) continue; mid_new_kkp[ksqB][ksqW][fe_pair.first + i] = mid_kkp[ksqB ][ksqW ][elem + i]; mid_new_kkp[ksqB][ksqW][fe_pair.second + i] = -mid_kkp[Inv(ksqW)][Inv(ksqB)][elem + i]; } } } } // 盤上の駒について。 for (Square ksqB = A9; ksqB < nsquare; ++ksqB) { for (Square ksqW = A9; ksqW < nsquare; ++ksqW) { for (FVIndex elem : BoardKKPFVIndex) { const auto fe_pair = g_kkpToKP[elem]; for (Square sq = A9; sq < nsquare; ++sq) { if (!(((elem == kkp_pawn || elem == kkp_lance) && sq < A8) || (elem == kkp_knight && sq < A7))) mid_new_kkp[ksqB][ksqW][fe_pair.first + sq] = mid_kkp[ksqB ][ksqW ][elem + sq ]; if (!(((elem == kkp_pawn || elem == kkp_lance) && Inv(sq) < A8) || (elem == kkp_knight && Inv(sq) < A7))) mid_new_kkp[ksqB][ksqW][fe_pair.second + sq] = -mid_kkp[Inv(ksqW)][Inv(ksqB)][elem + Inv(sq)]; } } } } }