MoveAndScoreIndex Book::GetProbe(const Position& position, const std::string& fName, const bool pickBest) { BookEntry entry; u16 best = 0; u32 sum = 0; Move move = g_MOVE_NONE;//該当なしのときに使う値☆ const Key key = this->GetBookKey(position); const ScoreIndex min_book_score = static_cast<ScoreIndex>(static_cast<int>(position.GetRucksack()->m_engineOptions["Min_Book_Score"])); ScoreIndex score = ScoreZero; if (this->m_fileName_ != fName && !this->OpenBook(fName.c_str())) { // 定跡ファイルが開けなかった場合☆ return MoveAndScoreIndex(g_MOVE_NONE, ScoreNone); } Binary_search(key); // 現在の局面における定跡手の数だけループする。 while (read(reinterpret_cast<char*>(&entry), sizeof(entry)), entry.m_key == key && good()) { best = std::max(best, entry.m_count); sum += entry.m_count; // 指された確率に従って手が選択される。 // count が大きい順に並んでいる必要はない。 if (min_book_score <= entry.m_score && ((m_random_.GetRandom() % sum < entry.m_count) || (pickBest && entry.m_count == best))) { const Move tmp = Move(entry.m_fromToPro); const Square to = tmp.To(); if (tmp.IsDrop()) { const PieceType ptDropped = tmp.GetPieceTypeDropped(); move = ConvMove::Convert30_MakeDropMove_da(ConvMove::FROM_PIECETYPE_DA10(ptDropped), to); } else { // 定跡の手(持ち駒以外)を、ムーブの書式に変換している??(^q^)? const Square from = tmp.From(); const Move fromMove = ConvMove::FROM_PIECETYPE_ONBOARD10(ConvPiece::TO_PIECE_TYPE10(position.GetPiece(from))); if (tmp.IsPromotion()) { move = UtilMovePos::BUILD_CARD_CAPTURE_PROMOTE(position,fromMove, from, to); } else { move = UtilMovePos::BUILD_CARD_CAPTURE(position, fromMove, from, to); } } score = entry.m_score; } } return MoveAndScoreIndex(move, score); }
// 以下のようなフォーマットが入力される。 // <棋譜番号> <日付> <先手名> <後手名> <0:引き分け, 1:先手勝ち, 2:後手勝ち> <総手数> <棋戦名前> <戦形> // <CSA1行形式の指し手> // // (例) // 1 2003/09/08 羽生善治 谷川浩司 2 126 王位戦 その他の戦型 // 7776FU3334FU2726FU4132KI // // 勝った方の手だけを定跡として使うこととする。 // 出現回数がそのまま定跡として使う確率となる。 // 基本的には棋譜を丁寧に選別した上で定跡を作る必要がある。 // MAKE_SEARCHED_BOOK を on にしていると、定跡生成に非常に時間が掛かる。 void MakeBook(Position& pos, std::istringstream& ssCmd) { std::string fileName; ssCmd >> fileName; std::ifstream ifs(fileName.c_str(), std::ios::binary); if (!ifs) { std::cout << "I cannot open " << fileName << std::endl; return; } std::string line; std::map<Key, std::vector<BookEntry> > bookMap; while (std::getline(ifs, line)) { std::string elem; std::stringstream ss(line); ss >> elem; // 棋譜番号を飛ばす。 ss >> elem; // 対局日を飛ばす。 ss >> elem; // 先手 const std::string sente = elem; ss >> elem; // 後手 const std::string gote = elem; ss >> elem; // (0:引き分け,1:先手の勝ち,2:後手の勝ち) const Color winner = (elem == "1" ? Black : elem == "2" ? White : Color::Null); // 勝った方の指し手を記録していく。 // 又は稲庭戦法側を記録していく。 const Color saveColor = winner; if (!std::getline(ifs, line)) { std::cout << "!!! header only !!!" << std::endl; return; } pos.Set(g_DefaultStartPositionSFEN, pos.GetRucksack()->m_ownerHerosPub.GetFirstCaptain()); StateStackPtr SetUpStates = StateStackPtr(new std::stack<StateInfo>()); UsiOperation usiOperation; while (!line.empty()) { const std::string moveStrCSA = line.substr(0, 6); const Move move = usiOperation.CsaToMove(pos, moveStrCSA); if (move.IsNone()) { pos.Print(); std::cout << "!!! Illegal move = " << moveStrCSA << " !!!" << std::endl; break; } line.erase(0, 6); // 先頭から6文字削除 if (pos.GetTurn() == saveColor) { // 先手、後手の内、片方だけを記録する。 const Key key = Book::GetBookKey(pos); bool isFind = false; if (bookMap.find(key) != bookMap.end()) { for (std::vector<BookEntry>::iterator it = bookMap[key].begin(); it != bookMap[key].end(); ++it) { if (it->m_fromToPro == move.ProFromAndTo()) { ++it->m_count; if (it->m_count < 1) { // 数えられる数の上限を超えたので元に戻す。 --it->m_count; } isFind = true; } } } if (isFind == false) { #if defined MAKE_SEARCHED_BOOK SetUpStates->push(StateInfo()); pos.GetTurn()==Color::Black ? pos.DoMove<Color::Black,Color::White>(move, SetUpStates->top()) : pos.DoMove<Color::White,Color::Black>(move, SetUpStates->top()) ; std::istringstream ssCmd("byoyomi 1000"); UsiOperation usiOperation; usiOperation.Go(pos, ssCmd); pos.GetRucksack()->m_ownerHerosPub.WaitForThinkFinished(); pos.UndoMove(move); SetUpStates->pop(); // doMove してから search してるので点数が反転しているので直す。 const ScoreIndex score = -pos.GetConstRucksack()->m_rootMoves[0].m_score_; #else const ScoreIndex GetScore = ScoreZero; #endif // 未登録の手 BookEntry be; be.m_score = score; be.m_key = key; be.m_fromToPro = static_cast<u16>(move.ProFromAndTo()); be.m_count = 1; bookMap[key].push_back(be); } } SetUpStates->push(StateInfo()); pos.GetTurn() == Color::Black ? pos.DoMove<Color::Black,Color::White>(move, SetUpStates->top()) : pos.DoMove<Color::White,Color::Black>(move, SetUpStates->top()) ; } } // BookEntry::count の値で降順にソート for (auto& elem : bookMap) { std::sort(elem.second.rbegin(), elem.second.rend(), countCompare); } #if 0 // 2 回以上棋譜に出現していない手は削除する。 for (auto& elem : bookMap) { auto& second = elem.second; auto erase_it = std::find_if(second.begin(), second.IsEnd(), [](decltype(*second.begin())& second_elem) { return second_elem.m_count < 2; }); second.erase(erase_it, second.IsEnd()); } #endif #if 0 // narrow book for (auto& elem : bookMap) { auto& second = elem.second; auto erase_it = std::find_if(second.begin(), second.IsEnd(), [&](decltype(*second.begin())& second_elem) { return second_elem.m_count < second[0].m_count / 2; }); second.erase(erase_it, second.IsEnd()); } #endif std::ofstream ofs("book.bin", std::ios::binary); for (auto& elem : bookMap) { for (auto& elel : elem.second) { ofs.write(reinterpret_cast<char*>(&(elel)), sizeof(BookEntry)); } } std::cout << "book making was done" << std::endl; }