diff --git a/game/duplicate.cpp b/game/duplicate.cpp index 3f44289..24a238a 100644 --- a/game/duplicate.cpp +++ b/game/duplicate.cpp @@ -38,7 +38,6 @@ #include "move.h" #include "pldrack.h" #include "results.h" -#include "move_selector.h" #include "player.h" #include "cmd/player_move_cmd.h" #include "cmd/player_rack_cmd.h" @@ -276,7 +275,7 @@ void Duplicate::endTurn() { // If nobody played a valid round, we are forced to play a valid move. // So let's take the best one... - BestResults results; + MasterResults results(getBag()); // Take the first player's rack const Rack &rack = m_players[REF_PLAYER_ID]->getLastRack().getRack(); @@ -288,9 +287,7 @@ void Duplicate::endTurn() throw EndGameException(_("No possible move")); } - // Select a clever master move if possible - MoveSelector selector; - setMasterMove(Move(selector.selectMaster(results))); + setMasterMove(Move(results.get(0))); } } diff --git a/game/game.cpp b/game/game.cpp index 28142f0..7864e62 100644 --- a/game/game.cpp +++ b/game/game.cpp @@ -37,7 +37,6 @@ #include "round.h" #include "pldrack.h" #include "results.h" -#include "move_selector.h" #include "player.h" #include "game.h" #include "turn_data.h" @@ -452,15 +451,14 @@ PlayedRack Game::helperSetRackRandom(const PlayedRack &iPld, { const Rack &rack = pld.getRack(); - BestResults res; + MasterResults res(getBag()); res.search(getDic(), getBoard(), rack, getHistory().beforeFirstRound()); if (!res.isEmpty()) { PlayedRack pldCopy = pld; // Get the best word - MoveSelector selector; - const Round & bestRound = selector.selectMaster(res); + const Round & bestRound = res.get(0); LOG_DEBUG("helperSetRackRandom(): initial rack: " << lfw(pld.toString()) << " (best word: " << lfw(bestRound.getWord()) << ")"); diff --git a/game/results.cpp b/game/results.cpp index a468138..4d0fb21 100644 --- a/game/results.cpp +++ b/game/results.cpp @@ -25,10 +25,11 @@ #include #include +#include "results.h" #include "tile.h" #include "round.h" #include "board.h" -#include "results.h" +#include "move_selector.h" #include "debug.h" @@ -306,3 +307,41 @@ void LimitResults::clear() m_total = 0; } + + +MasterResults::MasterResults(const Bag &iBag) + : m_bag(iBag) +{ +} + + +void MasterResults::search(const Dictionary &iDic, const Board &iBoard, + const Rack &iRack, bool iFirstWord) +{ + // Perform the search of the best results + m_bestResults.search(iDic, iBoard, iRack, iFirstWord); + + // If the search yields no result, there is nothing else to do + if (m_bestResults.isEmpty()) + return; + + // Find the best round, according to the heuristics in MoveSelector + MoveSelector selector; + const Round &round = selector.selectMaster(m_bestResults); + m_rounds.push_back(round); +} + + +void MasterResults::add(const Round &iRound) +{ + m_bestResults.add(iRound); +} + + +void MasterResults::clear() +{ + m_rounds.clear(); + m_bestResults.clear(); +} + + diff --git a/game/results.h b/game/results.h index e763953..877044f 100644 --- a/game/results.h +++ b/game/results.h @@ -32,6 +32,7 @@ using namespace std; class Dictionary; class Board; class Rack; +class Bag; /** @@ -138,5 +139,27 @@ private: int m_minScore; }; +/** + * This implementation starts with finding the rounds corresponding to the best + * score, like BestResults would do. + * After that, it uses a series of heuristics to identify the round which + * be best as "master move" in a duplicate game. + * All other rounds are discarded, so the size() method will always + * return 0 (if no round can be played at all) or 1. + */ +class MasterResults: public Results +{ +public: + MasterResults(const Bag &iBag); + virtual void search(const Dictionary &iDic, const Board &iBoard, + const Rack &iRack, bool iFirstWord); + virtual void clear(); + virtual void add(const Round &iRound); + +private: + const Bag &m_bag; + BestResults m_bestResults; +}; + #endif diff --git a/game/topping.cpp b/game/topping.cpp index 8d444d4..6d6a5aa 100644 --- a/game/topping.cpp +++ b/game/topping.cpp @@ -34,7 +34,6 @@ #include "settings.h" #include "rack.h" #include "results.h" -#include "move_selector.h" #include "pldrack.h" #include "player.h" #include "turn.h" @@ -221,14 +220,13 @@ void Topping::addPlayer(Player *iPlayer) Move Topping::getTopMove() const { - BestResults results; + // Find the most interesting top + MasterResults results(getBag()); results.search(getDic(), getBoard(), getHistory().getCurrentRack().getRack(), getHistory().beforeFirstRound()); ASSERT(!results.isEmpty(), "No top move found"); - // Find the most interesting top - MoveSelector selector; - return Move(selector.selectMaster(results)); + return Move(results.get(0)); } diff --git a/qt/arbit_assignments.cpp b/qt/arbit_assignments.cpp index d1e60e4..7e4987f 100644 --- a/qt/arbit_assignments.cpp +++ b/qt/arbit_assignments.cpp @@ -31,7 +31,6 @@ #include "prefs_dialog.h" #include "public_game.h" -#include "move_selector.h" #include "player.h" #include "turn_data.h" #include "rack.h" @@ -526,7 +525,7 @@ void ArbitAssignments::setDefaultMasterMove() return; // Search the best moves - BestResults results; + MasterResults results(m_game->getBag()); results.search(m_game->getDic(), m_game->getBoard(), m_game->getCurrentRack().getRack(), m_game->getHistory().beforeFirstRound()); @@ -535,8 +534,7 @@ void ArbitAssignments::setDefaultMasterMove() return; // Find a good default - MoveSelector selector; - Move move = Move(selector.selectMaster(results)); + Move move = Move(results.get(0)); // Assign the master move m_game->duplicateSetMasterMove(move);