Skip to content

Commit

Permalink
- 角歩の不成を含む詰みが読めない #257 問題を修正
Browse files Browse the repository at this point in the history
 - #257
 - 以前のcommitで壊していた。rollbackした。
   - GenerateAllLegalMovesオプションをオンにした時に「駒を取る手 + 歩の成り」と「駒を取らない手 + 歩の不成」を分けて生成したいのだが、これが現状の指し手生成ルーチンでは難しい。templateの特殊化を頑張ればできるのだが、ここをそんなに頑張っても仕方ないので(ふだん使う機能ではないし、バグらないように書くのむずいし、どうせ指し手オーダリングがきちんとしていればほとんど効率落ちないし)いまのままにしておく。
  • Loading branch information
yaneurao committed Jun 21, 2023
1 parent cd9b684 commit b40959f
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 50 deletions.
21 changes: 12 additions & 9 deletions source/movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -909,8 +909,8 @@ ExtMove* generateMoves(const Position& pos, ExtMove* mlist, Square recapSq)
// 歩の不成などを含め、すべての指し手を生成するのか。
// GenTypeの末尾に"ALL"とついているものがその対象。
const bool All = (GenType == EVASIONS_ALL) || (GenType == CHECKS_ALL) || (GenType == LEGAL_ALL)
|| (GenType == NON_EVASIONS_ALL) || (GenType == RECAPTURES_ALL) || (GenType == QUIET_CHECKS_ALL);
//|| (GenType == CAPTURES_PRO_PLUS_ALL) || (GenType == NON_CAPTURES_PRO_MINUS_ALL);
|| (GenType == NON_EVASIONS_ALL) || (GenType == RECAPTURES_ALL) || (GenType == QUIET_CHECKS_ALL)
|| (GenType == CAPTURES_PRO_PLUS_ALL) || (GenType == NON_CAPTURES_PRO_MINUS_ALL);

if (GenType == LEGAL || GenType == LEGAL_ALL)
{
Expand Down Expand Up @@ -956,11 +956,11 @@ ExtMove* generateMoves(const Position& pos, ExtMove* mlist, Square recapSq)
// ただし、NON_EVASIONS_ALL , RECAPTURES_ALLは、ALLではないほうを呼び出す必要がある。
// EVASIONS_ALLは上で呼び出されているが、実際はここでも実体化されたあと、最適化によって削除されるので、ここでも書く必要がある。
const auto GenType2 =
GenType == NON_EVASIONS_ALL ? NON_EVASIONS :
GenType == RECAPTURES_ALL ? RECAPTURES :
GenType == EVASIONS_ALL ? EVASIONS :
//GenType == CAPTURES_PRO_PLUS_ALL ? CAPTURES_PRO_PLUS :
//GenType == NON_CAPTURES_PRO_MINUS_ALL ? NON_CAPTURES_PRO_MINUS :
GenType == NON_EVASIONS_ALL ? NON_EVASIONS :
GenType == RECAPTURES_ALL ? RECAPTURES :
GenType == EVASIONS_ALL ? EVASIONS :
GenType == CAPTURES_PRO_PLUS_ALL ? CAPTURES_PRO_PLUS :
GenType == NON_CAPTURES_PRO_MINUS_ALL ? NON_CAPTURES_PRO_MINUS :
GenType; // さもなくば元のまま。
return generateMoves<GenType2, All>(pos, mlist, recapSq);
}
Expand All @@ -979,8 +979,11 @@ ExtMove* generateMoves(const Position& pos, ExtMove* mlist)
template ExtMove* generateMoves<NON_CAPTURES >(const Position& pos, ExtMove* mlist);
template ExtMove* generateMoves<CAPTURES >(const Position& pos, ExtMove* mlist);

template ExtMove* generateMoves<NON_CAPTURES_PRO_MINUS>(const Position& pos, ExtMove* mlist);
template ExtMove* generateMoves<CAPTURES_PRO_PLUS >(const Position& pos, ExtMove* mlist);
template ExtMove* generateMoves<NON_CAPTURES_PRO_MINUS >(const Position& pos, ExtMove* mlist);
template ExtMove* generateMoves<NON_CAPTURES_PRO_MINUS_ALL>(const Position& pos, ExtMove* mlist);

template ExtMove* generateMoves<CAPTURES_PRO_PLUS >(const Position& pos, ExtMove* mlist);
template ExtMove* generateMoves<CAPTURES_PRO_PLUS_ALL >(const Position& pos, ExtMove* mlist);

template ExtMove* generateMoves<EVASIONS >(const Position& pos, ExtMove* mlist);
template ExtMove* generateMoves<EVASIONS_ALL >(const Position& pos, ExtMove* mlist);
Expand Down
7 changes: 2 additions & 5 deletions source/movepick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,7 @@ Move MovePicker::next_move(bool skipQuiets) {
case QCAPTURE_INIT:
cur = endBadCaptures = moves;

//endMoves = Search::Limits.generate_all_legal_moves ? generateMoves<CAPTURES_PRO_PLUS_ALL>(pos, cur) : generateMoves<CAPTURES_PRO_PLUS>(pos, cur);
// → Probcutとかでしか使わないから、CAPTURES_PRO_PLUS_ALLは廃止する。
endMoves = generateMoves<CAPTURES_PRO_PLUS>(pos, cur);
endMoves = Search::Limits.generate_all_legal_moves ? generateMoves<CAPTURES_PRO_PLUS_ALL>(pos, cur) : generateMoves<CAPTURES_PRO_PLUS>(pos, cur);

// 駒を捕獲する指し手に対してオーダリングのためのスコアをつける
score<CAPTURES>();
Expand Down Expand Up @@ -441,8 +439,7 @@ Move MovePicker::next_move(bool skipQuiets) {
cur = (ExtMove*)Math::align((size_t)cur, 32);
#endif

//endMoves = Search::Limits.generate_all_legal_moves ? generateMoves<NON_CAPTURES_PRO_MINUS_ALL>(pos, cur) : generateMoves<NON_CAPTURES_PRO_MINUS>(pos, cur);
endMoves = generateMoves<NON_CAPTURES_PRO_MINUS>(pos, cur);
endMoves = Search::Limits.generate_all_legal_moves ? generateMoves<NON_CAPTURES_PRO_MINUS_ALL>(pos, cur) : generateMoves<NON_CAPTURES_PRO_MINUS>(pos, cur);

// 駒を捕獲しない指し手に対してオーダリングのためのスコアをつける
score<QUIETS>();
Expand Down
111 changes: 76 additions & 35 deletions source/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2541,47 +2541,14 @@ void Position::UnitTest(Test::UnitTester& tester)
}
}

{
// 深いdepthのperftのテストが通っていれば、利きの計算、指し手生成はおおよそ間違っていないと言える。

auto section2 = tester.section("Perft");

{
auto section3 = tester.section("hirate");
hirate_init();
const s64 p_nodes[] = { 0 , 30 , 900, 25470, 719731, 19861490, 547581517 };

for (Depth d = 1; d <= 6; ++d)
{
u64 nodes = perft(pos, d);
u64 pn = p_nodes[d];
tester.test("depth " + to_string(d) + " = " + to_string(pn), nodes == pn);
}
}

{
auto section3 = tester.section("matsuri");
matsuri_init();

const s64 p_nodes[] = { 0 , 207 , 28684, 4809015, 516925165};

for (Depth d = 1; d <= 4; ++d)
{
u64 nodes = perft(pos, d);
u64 pn = p_nodes[d];
tester.test("depth " + to_string(d) + " = " + to_string(nodes), nodes == pn);
}
}
}

{
// 指し手生成のテスト
auto section2 = tester.section("GenMove");

{
// 23歩不成ができ、かつ、23歩不成では駒の捕獲にはならない局面。
pos_init("lnsgk1snl/1r4g2/p1ppppb1p/6pP1/7R1/2P6/P2PPPP1P/1SG6/LN2KGSNL b BP2p 21");
Move move1 = make_move(SQ_24, SQ_23,B_PAWN);
Move move1 = make_move (SQ_24, SQ_23,B_PAWN);
Move move2 = make_move_promote(SQ_24, SQ_23,B_PAWN);

ExtMove move_buf[MAX_MOVES] , *move_last;
Expand Down Expand Up @@ -2619,18 +2586,92 @@ void Position::UnitTest(Test::UnitTester& tester)
all &= !find_move(move1);
all &= find_move(move2);

move_last = generateMoves<CAPTURES_PRO_PLUS_ALL>(pos, move_buf);
all &= find_move(move1); // 歩の不成はこちらに含めることになった。(movegenの実装の修正が難しいので)
all &= find_move(move2);

move_last = generateMoves<NON_CAPTURES_PRO_MINUS>(pos, move_buf);
all &= !find_move(move1);
all &= !find_move(move2);

move_last = generateMoves<NON_CAPTURES_PRO_MINUS_ALL>(pos, move_buf);
all &= !find_move(move1); // 歩の不成はこちらには含まれていないので注意。
all &= !find_move(move2);

tester.test("pawn's unpromoted move", all);

// 23角不成で5手詰め
// https://github.com/yaneurao/YaneuraOu/issues/257
pos_init("5B1n1/8k/6Rpp/9/9/9/1+p7/9/K8 b rb4g4s3n4l15p 1");
// 23角不成(41)と23角成(41)
move1 = make_move (SQ_41, SQ_23, B_BISHOP);
move2 = make_move_promote(SQ_41, SQ_23, B_BISHOP);
all = true;

move_last = generateMoves<LEGAL_ALL>(pos, move_buf);
all &= find_move(move1);
all &= find_move(move2);

move_last = generateMoves<CAPTURES_PRO_PLUS>(pos, move_buf);
all &= !find_move(move1);
all &= find_move(move2);

move_last = generateMoves<NON_CAPTURES_PRO_MINUS>(pos, move_buf);
all &= !find_move(move1);
all &= !find_move(move2);

move_last = generateMoves<CAPTURES_PRO_PLUS>(pos, move_buf);
all &= !find_move(move1);
all &= find_move(move2);

move_last = generateMoves<NON_CAPTURES_PRO_MINUS_ALL>(pos, move_buf);
all &= !find_move(move1);
all &= !find_move(move2);

move_last = generateMoves<CAPTURES_PRO_PLUS_ALL>(pos, move_buf);
all &= find_move(move1);
all &= find_move(move2);

tester.test("bishop's unpromoted move",all);
}
}

{
// 深いdepthのperftのテストが通っていれば、利きの計算、指し手生成はおおよそ間違っていないと言える。

auto section2 = tester.section("Perft");

{
auto section3 = tester.section("hirate");
hirate_init();
const s64 p_nodes[] = { 0 , 30 , 900, 25470, 719731, 19861490, 547581517 };

for (Depth d = 1; d <= 6; ++d)
{
u64 nodes = perft(pos, d);
u64 pn = p_nodes[d];
tester.test("depth " + to_string(d) + " = " + to_string(pn), nodes == pn);
}
}

{
auto section3 = tester.section("matsuri");
matsuri_init();

const s64 p_nodes[] = { 0 , 207 , 28684, 4809015, 516925165};

for (Depth d = 1; d <= 4; ++d)
{
u64 nodes = perft(pos, d);
u64 pn = p_nodes[d];
tester.test("depth " + to_string(d) + " = " + to_string(nodes), nodes == pn);
}
}
}

{
// それ以外のテスト
auto section = tester.section("misc");

{
// 盤面の反転

Expand Down
10 changes: 9 additions & 1 deletion source/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -909,13 +909,21 @@ enum MOVE_GEN_TYPE
CAPTURES_PRO_PLUS, // CAPTURES + 価値のかなりあると思われる成り(歩だけ)
NON_CAPTURES_PRO_MINUS, // NON_CAPTURES - 価値のかなりあると思われる成り(歩だけ)

CAPTURES_PRO_PLUS_ALL, // CAPTURES_PRO_PLUS + 歩の不成、大駒の不成で駒を取る手も含む
NON_CAPTURES_PRO_MINUS_ALL, // NON_CAPTURES_PRO_MINUS + 大駒の不成で駒を取らない手も含む
// note : 歩の不成で駒を取らない指し手は後者に含まれるべきだが、指し手生成の実装が難しくなるので前者に含めることにした。
// オーダリング(movepicker)でなんとかするだろうからそこまで悪くはならないだろうし、普段は
// GenerateAllLegalMovesがオンにして動かさないから良しとする。

// BonanzaではCAPTURESに銀以外の成りを含めていたが、Aperyでは歩の成り以外は含めない。
// あまり変な成りまで入れるとオーダリングを阻害する。
// 本ソースコードでは、NON_CAPTURESとCAPTURESは使わず、CAPTURES_PRO_PLUSとNON_CAPTURES_PRO_MINUSを使う。

// note : NON_CAPTURESとCAPTURESとの生成される指し手の集合は被覆していない。
// note : CAPTURES_PRO_PLUSとNON_CAPTURES_PRO_MINUSとの生成される指し手の集合も被覆していない。
// note : CAPTURES_PRO_PLUS_ALLとNON_CAPTURES_PRO_MINUS_ALLとの生成される指し手の集合も被覆していない。
// → 被覆させないことで、二段階に指し手生成を分解することが出来る。

EVASIONS, // 王手の回避(指し手生成元で王手されている局面であることがわかっているときはこちらを呼び出す)
EVASIONS_ALL, // EVASIONS + 歩の不成なども含む。

Expand Down

0 comments on commit b40959f

Please sign in to comment.