// recursive function which does all search logic void DFBB(StarcraftStateType & s, int depth) { // increase the node expansion count nodesExpanded++; //graphVizOutput(s, false); // the time at which the last thing in the queue will finish int finishTime = s.getLastFinishTime(); if (finishTime >= upperBound) { return; } int lookupVal = TT.lookup(s.hashAllUnits(1), s.hashAllUnits(2)); if (lookupVal != -1 && lookupVal < finishTime) { ttcuts++; return; } TT.save(s.hashAllUnits(1), s.hashAllUnits(2), finishTime); int bucket = getBucket(finishTime); int armyValue = s.getArmyValue(); if (armyValue > armyValues[bucket]) { armyValues[bucket] = armyValue; buildOrders[bucket] = getBuildOrder(s); } // if we are using search timeout and we are over the limit if (params.searchTimeLimit && (nodesExpanded % 1000 == 0) && (searchTimer.getElapsedTimeInMilliSec() > params.searchTimeLimit)) { // throw an exception to unroll the recursion throw 1; } // get the legal action set ActionSet legalActions = s.getLegalActionsMonteCarlo(params.goal); // if we have children, update the counter if (!legalActions.isEmpty()) { numGenerations += 1; numChildren += legalActions.numActions(); } // while there are still legal actions to perform while (!legalActions.isEmpty()) { // get the next action Action nextAction = legalActions.popAction(); bool stillLegal = true; StarcraftStateType child(s); // set the repetitions if we are using repetitions, otherwise set to 1 int repeat = params.useRepetitions ? params.getRepetitions(nextAction) : 1; // for each repetition of this action for (int r = 0; r < repeat; ++r) { // if the action is still legal if (child.isLegalMonteCarlo(nextAction, params.goal)) { int readyTime = child.resourcesReady(nextAction); child.doAction(nextAction, readyTime); } // if it's not legal, break the chain else { stillLegal = false; break; } } //if (stillLegal) //{ child.setParent(&s); child.setActionPerformedK((UnitCountType)repeat); DFBB(child, depth+1); //} } }
// 協力詰め // depth = 残り探索深さ // no_mate_depth = この局面は、この深さの残り探索深さがあっても詰まない(あるいは詰みを発見して出力済み) void search(Position& pos, uint32_t depth, int& no_mate_depth) { // 強制停止 if (Signals.stop || mate_found) { no_mate_depth = MAX_PLY; return; } Key128 key = pos.state()->long_key(); Move tt_move; // 置換表がヒットするか if (TT.probe(key, depth, tt_move)) { no_mate_depth = depth; // foundのときにdepthはTTEntry.depth()で書き換わっている。 return; // このnodeに関しては現在の残り探索深さ以上の深さにおいて //不詰めが証明されているのでもう帰ってよい。(枝刈り) } StateInfo si; pos.check_info_update(); // legal()とgives_check()とCHECKSの指し手生成に先だって呼び出されている必要がある。 MovePicker mp(pos, tt_move); Move m; int replyCount = 0; // 確定局面以外の応手の数 Move oneReply = MOVE_NONE; no_mate_depth = MAX_PLY; // 有効な指し手が一つもなければこのnodeはいくらdepthがあろうと詰まない。 while ((m = mp.next_move()) && !Signals.stop && !mate_found) { if (!pos.legal(m)) continue; pos.do_move(m, si, pos.gives_check(m)); if (pos.is_mated()) { // 後手の詰みなら手順を表示する。先手の詰みは必要ない。 if (pos.side_to_move() == WHITE) { // 現在詰まないことが判明している探索深さ(search_depth)+2の長さの詰みを発見したときのみ。 while (!Signals.stop && !mate_found) // 他のスレッドが見つけるかも知れないのでそれを待ちながら…。 { if (search_depth + 2 >= id_depth_thread /*- depth + 1*/) { mate_found = true; sync_cout << "checkmate " << pos.moves_from_start() << sync_endl; // 開始局面からそこまでの手順 break; } sleep(100); } } } else if (depth > 1) { // 残り探索深さがあるなら再帰的に探索する。 int child_no_mate_depth; search(pos, depth - 1, child_no_mate_depth); no_mate_depth = min(child_no_mate_depth + 1, no_mate_depth); if (child_no_mate_depth != MAX_PLY) { replyCount++; oneReply = m; } } else { no_mate_depth = 1; // frontier node。この先、まだ探索すれば詰むかも知れないので.. replyCount++; oneReply = m; } pos.undo_move(m); } // このnodeに関して残り探索深さdepthについては詰みを調べきったので不詰めとして扱い、置換表に記録しておく。 // また、確定局面以外の子が1つしかなればそれを置換表に書き出しておく。(次回の指し手生成をはしょるため) if (replyCount != 1) oneReply = MOVE_NONE; TT.save(key, no_mate_depth, oneReply); }