Results: new MasterResults implementation, using the MoveSelector class.

This avoids calling MoveSelector everywhere in the code.
This commit is contained in:
Olivier Teulière 2013-01-17 18:39:03 +01:00
parent adc60c868f
commit 30385abe30
6 changed files with 72 additions and 19 deletions

View file

@ -38,7 +38,6 @@
#include "move.h" #include "move.h"
#include "pldrack.h" #include "pldrack.h"
#include "results.h" #include "results.h"
#include "move_selector.h"
#include "player.h" #include "player.h"
#include "cmd/player_move_cmd.h" #include "cmd/player_move_cmd.h"
#include "cmd/player_rack_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. // If nobody played a valid round, we are forced to play a valid move.
// So let's take the best one... // So let's take the best one...
BestResults results; MasterResults results(getBag());
// Take the first player's rack // Take the first player's rack
const Rack &rack = const Rack &rack =
m_players[REF_PLAYER_ID]->getLastRack().getRack(); m_players[REF_PLAYER_ID]->getLastRack().getRack();
@ -288,9 +287,7 @@ void Duplicate::endTurn()
throw EndGameException(_("No possible move")); throw EndGameException(_("No possible move"));
} }
// Select a clever master move if possible setMasterMove(Move(results.get(0)));
MoveSelector selector;
setMasterMove(Move(selector.selectMaster(results)));
} }
} }

View file

@ -37,7 +37,6 @@
#include "round.h" #include "round.h"
#include "pldrack.h" #include "pldrack.h"
#include "results.h" #include "results.h"
#include "move_selector.h"
#include "player.h" #include "player.h"
#include "game.h" #include "game.h"
#include "turn_data.h" #include "turn_data.h"
@ -452,15 +451,14 @@ PlayedRack Game::helperSetRackRandom(const PlayedRack &iPld,
{ {
const Rack &rack = pld.getRack(); const Rack &rack = pld.getRack();
BestResults res; MasterResults res(getBag());
res.search(getDic(), getBoard(), rack, getHistory().beforeFirstRound()); res.search(getDic(), getBoard(), rack, getHistory().beforeFirstRound());
if (!res.isEmpty()) if (!res.isEmpty())
{ {
PlayedRack pldCopy = pld; PlayedRack pldCopy = pld;
// Get the best word // Get the best word
MoveSelector selector; const Round & bestRound = res.get(0);
const Round & bestRound = selector.selectMaster(res);
LOG_DEBUG("helperSetRackRandom(): initial rack: " LOG_DEBUG("helperSetRackRandom(): initial rack: "
<< lfw(pld.toString()) << " (best word: " << lfw(pld.toString()) << " (best word: "
<< lfw(bestRound.getWord()) << ")"); << lfw(bestRound.getWord()) << ")");

View file

@ -25,10 +25,11 @@
#include <cwctype> #include <cwctype>
#include <cmath> #include <cmath>
#include "results.h"
#include "tile.h" #include "tile.h"
#include "round.h" #include "round.h"
#include "board.h" #include "board.h"
#include "results.h" #include "move_selector.h"
#include "debug.h" #include "debug.h"
@ -306,3 +307,41 @@ void LimitResults::clear()
m_total = 0; 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();
}

View file

@ -32,6 +32,7 @@ using namespace std;
class Dictionary; class Dictionary;
class Board; class Board;
class Rack; class Rack;
class Bag;
/** /**
@ -138,5 +139,27 @@ private:
int m_minScore; 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 #endif

View file

@ -34,7 +34,6 @@
#include "settings.h" #include "settings.h"
#include "rack.h" #include "rack.h"
#include "results.h" #include "results.h"
#include "move_selector.h"
#include "pldrack.h" #include "pldrack.h"
#include "player.h" #include "player.h"
#include "turn.h" #include "turn.h"
@ -221,14 +220,13 @@ void Topping::addPlayer(Player *iPlayer)
Move Topping::getTopMove() const Move Topping::getTopMove() const
{ {
BestResults results; // Find the most interesting top
MasterResults results(getBag());
results.search(getDic(), getBoard(), getHistory().getCurrentRack().getRack(), results.search(getDic(), getBoard(), getHistory().getCurrentRack().getRack(),
getHistory().beforeFirstRound()); getHistory().beforeFirstRound());
ASSERT(!results.isEmpty(), "No top move found"); ASSERT(!results.isEmpty(), "No top move found");
// Find the most interesting top return Move(results.get(0));
MoveSelector selector;
return Move(selector.selectMaster(results));
} }

View file

@ -31,7 +31,6 @@
#include "prefs_dialog.h" #include "prefs_dialog.h"
#include "public_game.h" #include "public_game.h"
#include "move_selector.h"
#include "player.h" #include "player.h"
#include "turn_data.h" #include "turn_data.h"
#include "rack.h" #include "rack.h"
@ -526,7 +525,7 @@ void ArbitAssignments::setDefaultMasterMove()
return; return;
// Search the best moves // Search the best moves
BestResults results; MasterResults results(m_game->getBag());
results.search(m_game->getDic(), m_game->getBoard(), results.search(m_game->getDic(), m_game->getBoard(),
m_game->getCurrentRack().getRack(), m_game->getCurrentRack().getRack(),
m_game->getHistory().beforeFirstRound()); m_game->getHistory().beforeFirstRound());
@ -535,8 +534,7 @@ void ArbitAssignments::setDefaultMasterMove()
return; return;
// Find a good default // Find a good default
MoveSelector selector; Move move = Move(results.get(0));
Move move = Move(selector.selectMaster(results));
// Assign the master move // Assign the master move
m_game->duplicateSetMasterMove(move); m_game->duplicateSetMasterMove(move);