MoveSelector: add another heuristic

This commit is contained in:
Olivier Teulière 2013-01-17 19:52:49 +01:00
parent 075dbaa2fb
commit a53d99a8d3
3 changed files with 55 additions and 4 deletions

View file

@ -18,10 +18,13 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include <boost/foreach.hpp>
#include "move_selector.h"
#include "round.h"
#include "results.h"
#include "bag.h"
#include "rack.h"
#include "dic.h"
#include "debug.h"
@ -30,11 +33,16 @@
INIT_LOGGER(game, MoveSelector);
#define PLAYED_JOKER (-1000)
#define LETTER_REPEATED_3_TIMES (-3)
#define LETTER_REPEATED_4_TIMES (-12)
#define LETTER_REPEATED_5_TIMES (-40)
#define LETTER_REPEATED_6_TIMES (-100)
#define EXTENSION_1 50
MoveSelector::MoveSelector(const Bag &iBag, const Dictionary &iDic)
: m_bag(iBag), m_dic(iDic)
MoveSelector::MoveSelector(const Bag &iBag, const Dictionary &iDic,
const Board &iBoard, const Rack &iRack)
: m_bag(iBag), m_dic(iDic), m_board(iBoard), m_rack(iRack)
{
}
@ -69,6 +77,7 @@ int MoveSelector::evalScore(const Round &iRound) const
{
int score = 0;
score += evalForJokersInRack(iRound);
score += evalForRemainingLetters(iRound);
// Deactivated for now, as it breaks a few non-regression tests,
// and I don't have time to fix them at the moment... :)
#if 0
@ -85,6 +94,42 @@ int MoveSelector::evalForJokersInRack(const Round &iRound) const
}
int MoveSelector::evalForRemainingLetters(const Round &iRound) const
{
// Compute the rack remaining after playing the round
Rack remaining = m_rack;
for (unsigned i = 0; i < iRound.getWordLen(); ++i)
{
if (iRound.isPlayedFromRack(i))
{
remaining.remove(iRound.isJoker(i) ? Tile::Joker() : iRound.getTile(i));
}
}
// If a letter is present at least 3 times in the rack, consider it bad
// Note: the repetitions are only relevant if the rack is not rejected for
// lack of vowels and/or consonants...
int score = 0;
BOOST_FOREACH(const Tile &t, m_dic.getAllTiles())
{
const int count = remaining.count(t);
if (count >= 3)
{
if (count == 3)
score += LETTER_REPEATED_3_TIMES;
else if (count == 4)
score += LETTER_REPEATED_4_TIMES;
else if (count == 5)
score += LETTER_REPEATED_5_TIMES;
else if (count == 6)
score += LETTER_REPEATED_6_TIMES;
}
}
return score;
}
int MoveSelector::evalForExtensions(const Round &iRound) const
{
// Find front and back extensions to the given round

View file

@ -27,6 +27,8 @@ class Round;
class BestResults;
class Bag;
class Dictionary;
class Board;
class Rack;
/**
@ -40,7 +42,8 @@ class MoveSelector
DEFINE_LOGGER();
public:
MoveSelector(const Bag &iBag, const Dictionary &iDic);
MoveSelector(const Bag &iBag, const Dictionary &iDic,
const Board &iBoard, const Rack &iRack);
/**
* Return a move to be used as "master move" in a duplicate game.
@ -58,9 +61,12 @@ public:
private:
const Bag &m_bag;
const Dictionary &m_dic;
const Board &m_board;
const Rack &m_rack;
int evalScore(const Round &iRound) const;
int evalForJokersInRack(const Round &iRound) const;
int evalForRemainingLetters(const Round &iRound) const;
int evalForExtensions(const Round &iRound) const;
};

View file

@ -326,7 +326,7 @@ void MasterResults::search(const Dictionary &iDic, const Board &iBoard,
return;
// Find the best round, according to the heuristics in MoveSelector
MoveSelector selector(m_bag, iDic);
MoveSelector selector(m_bag, iDic, iBoard, iRack);
const Round &round = selector.selectMaster(m_bestResults);
m_rounds.push_back(round);
}