From 5b065a06d42141b058fdd4dc45fb756ed4fc6f31 Mon Sep 17 00:00:00 2001 From: Calcitem Date: Sun, 24 Dec 2023 20:27:48 +0800 Subject: [PATCH] perfect: Support move randomly This commit introduces significant changes to the allMaxBy function in perfect_player.cpp. The updated logic now prioritizes moves based on their expected outcomes, specifically focusing on "Win" ('W'), "Draw" ('D'), and "Loss" ('L') scenarios. Key changes include: - Added conditions to check the first character of the string returned by the toString method of each evaluated move. - The function now first looks for moves leading to a win ('W'). If any are found, only these moves are considered. - If no winning moves ('W') are found, the function then looks for draws ('D'). Only draw moves are considered in this case. - If neither winning nor drawing moves are found, the function defaults to considering loss ('L') moves. - The previous implementation based on comparing values has been retained under an else clause, ensuring backward compatibility when shuffling is not enabled. This enhancement aligns the move selection process more closely with strategic gameplay considerations, improving the PerfectPlayer's decision-making capabilities. Change-Id: Iad135da3856a0b5acc3a16c35e1c22dcfb5c21ed --- src/perfect/perfect_player.cpp | 73 +++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/src/perfect/perfect_player.cpp b/src/perfect/perfect_player.cpp index 4e9cb90a1..9006fc236 100644 --- a/src/perfect/perfect_player.cpp +++ b/src/perfect/perfect_player.cpp @@ -43,6 +43,8 @@ #include #include +#include "option.h" + class GameState; std::map Sectors::sectors; @@ -345,20 +347,49 @@ std::vector PerfectPlayer::allMaxBy(std::function f, const std::vector &l, K minValue) { std::vector r; - K ma = minValue; - for (auto &m : l) { - K e = f(m); - if (e > ma) { - ma = e; - r.clear(); - r.push_back(m); - } else if (e == ma) { - r.push_back(m); + + if (gameOptions.getShufflingEnabled()) { + bool foundW = false; + bool foundD = false; + + for (auto &m : l) { + K e = f(m); + std::string eStr = e.toString(); + + if (eStr[0] == 'W') { + if (!foundW) { + r.clear(); + foundW = true; + } + r.push_back(m); + } else if (!foundW && eStr[0] != 'L') { + if (!foundD) { + r.clear(); + foundD = true; + } + r.push_back(m); + } else if (!foundW && !foundD && eStr[0] == 'L') { + r.push_back(m); + } + } + } else { + K ma = minValue; + for (auto &m : l) { + K e = f(m); + if (e > ma) { + ma = e; + r.clear(); + r.push_back(m); + } else if (e == ma) { + r.push_back(m); + } } } + return r; } +#if 1 // Assuming the definition of gui_eval_elem2::min_value function std::vector PerfectPlayer::goodMoves(const GameState &s) { @@ -367,6 +398,30 @@ std::vector PerfectPlayer::goodMoves(const GameState &s) getMoveList(s), Wrappers::gui_eval_elem2::min_value(getSec(s))); } +#else +std::vector PerfectPlayer::goodMoves(const GameState &s) +{ + auto moveList = getMoveList(s); + std::cout << "Move list size: " << moveList.size() + << std::endl; + + std::function evalFunction = + [this, &s](AdvancedMove m) { + auto value = moveValue(s, m); + std::cout << "Evaluating move from " << m.from << " to " << m.to + << " with score: " << value.toString() + << std::endl; + return value; + }; + + auto bestMoves = allMaxBy(evalFunction, moveList, + Wrappers::gui_eval_elem2::min_value(getSec(s))); + + std::cout << "Number of best moves: " << bestMoves.size() << std::endl; + + return bestMoves; +} +#endif int PerfectPlayer::NGMAfterMove(const GameState &s, AdvancedMove &m) {