Arbitration: new option to handle solos automatically.

The option is not yet accessible from the interface.
This commit is contained in:
Olivier Teulière 2012-12-05 23:02:12 +01:00
parent 4d38c99336
commit 19a93988ad
4 changed files with 109 additions and 32 deletions

View file

@ -221,6 +221,15 @@ void Arbitration::assignMove(unsigned int iPlayerId, const Move &iMove)
{
ASSERT(iPlayerId < getNPlayers(), "Wrong player number");
recordPlayerMove(*m_players[iPlayerId], iMove);
// Automatically update the solos if requested
bool useSoloAuto = Settings::Instance().getBool("arbitration.solo-auto");
if (useSoloAuto)
{
unsigned minNbPlayers = Settings::Instance().getInt("arbitration.solo-players");
int soloValue = Settings::Instance().getInt("arbitration.solo-value");
setSoloAuto(minNbPlayers, soloValue);
}
}

View file

@ -48,6 +48,7 @@
#include "ai_player.h"
#include "navigation.h"
#include "turn.h"
#include "turn_data.h"
#include "settings.h"
#include "encoding.h"
#include "debug.h"
@ -288,37 +289,21 @@ void Duplicate::endTurn()
}
}
// Handle solo bonus (not in arbitration mode, because we may not have all
// the moves to decide whether a solo can be attributed).
// Handle solo bonus
if (!isArbitrationGame())
{
// First check whether there are enough players in the game for the
// bonus to apply
unsigned int minNbPlayers = Settings::Instance().getInt("duplicate.solo-players");
// Find the player with the best score
Player *bestPlayer = findBestPlayer();
if (getNPlayers() >= minNbPlayers && bestPlayer != NULL)
unsigned minNbPlayers = Settings::Instance().getInt("duplicate.solo-players");
int soloValue = Settings::Instance().getInt("duplicate.solo-value");
setSoloAuto(minNbPlayers, soloValue);
}
else
{
bool useSoloAuto = Settings::Instance().getBool("arbitration.solo-auto");
if (useSoloAuto)
{
int bestScore = bestPlayer->getLastMove().getScore();
// Find whether other players than imax have the same score
bool otherWithSameScore = false;
BOOST_FOREACH(const Player *player, m_players)
{
if (player != bestPlayer &&
player->getLastMove().getScore() >= bestScore &&
player->getLastMove().isValid())
{
otherWithSameScore = true;
break;
}
}
if (!otherWithSameScore)
{
// Give the bonus to the player of the best move
int bonus = Settings::Instance().getInt("duplicate.solo-value");
Command *pCmd = new PlayerEventCmd(*bestPlayer, PlayerEventCmd::SOLO, bonus);
accessNavigation().addAndExecute(pCmd);
}
unsigned minNbPlayers = Settings::Instance().getInt("arbitration.solo-players");
int soloValue = Settings::Instance().getInt("arbitration.solo-value");
setSoloAuto(minNbPlayers, soloValue);
}
}
@ -435,6 +420,67 @@ void Duplicate::setGameAndPlayersRack(const PlayedRack &iRack)
}
void Duplicate::setSoloAuto(unsigned int minNbPlayers, int iSoloValue)
{
// Remove all existing solos
BOOST_FOREACH(const Player *player, m_players)
{
const PlayerEventCmd *cmd = getPlayerEvent(player->getId(), PlayerEventCmd::SOLO);
if (cmd != 0)
{
accessNavigation().dropCommand(*cmd);
}
}
// Check whether there are enough players in the game for the
// solo to apply. We count only the "active" players, i.e. the ones
// which have played at least one word during the game, even if they
// have left the game since then, or have arrived after the beginning.
unsigned countActive = 0;
BOOST_FOREACH(const Player *player, m_players)
{
for (unsigned i = 0; i < player->getHistory().getSize(); ++i)
{
if (!player->getHistory().getTurn(i).getMove().isNull())
{
++countActive;
break;
}
}
}
if (countActive < minNbPlayers)
return;
// Find the player with the best score
Player *bestPlayer = findBestPlayer();
if (bestPlayer != NULL)
{
int bestScore = bestPlayer->getLastMove().getScore();
// Find whether other players than imax have the same score
bool otherWithSameScore = false;
BOOST_FOREACH(const Player *player, m_players)
{
if (player != bestPlayer &&
player->getLastMove().getScore() >= bestScore &&
player->getLastMove().isValid())
{
otherWithSameScore = true;
break;
}
}
if (!otherWithSameScore)
{
// Give the bonus to the player of the best move
LOG_INFO("Giving a solo of " << iSoloValue << " to player " << bestPlayer->getId());
Command *pCmd = new PlayerEventCmd(*bestPlayer, PlayerEventCmd::SOLO, iSoloValue);
accessNavigation().insertCommand(pCmd);
}
}
}
/// Predicate to help retrieving commands
struct MatchingPlayerAndEventType : public unary_function<PlayerEventCmd, bool>
{

View file

@ -141,6 +141,16 @@ protected:
const PlayerEventCmd * getPlayerEvent(unsigned iPlayerId,
int iEventType) const;
/**
* Automatically set the solo for the current turn.
* First, all the existing solos (there could be several, in arbitration
* mode with a crazy arbitrator...) are removed. Then, a solo is given to
* the player deserving it, if any.
* Note that the minimum number of players specified in the preferences
* must be reached for the solo to be applicable.
*/
void setSoloAuto(unsigned int minNbPlayers, int iSoloValue);
private: // Used by friend classes
void innerSetMasterMove(const Move &iMove);
bool isArbitrationGame() const;

View file

@ -233,8 +233,12 @@ Settings::Settings()
// If true, a random rack is defined, otherwise the rack is left untouched
arbitration.add("fill-rack", Setting::TypeBoolean) = true;
// Number of search results kept in a search
arbitration.add("search-limit", Setting::TypeInt) = 100;
// If true, solos are automatically given when appropriate
// If false, the arbitrator has full control (but must do everything manually)
arbitration.add("solo-auto", Setting::TypeBoolean) = true;
// Minimum number of players in a duplicate game needed to apply a "solo" bonus
// (16 is the ODS value)
arbitration.add("solo-players", Setting::TypeInt) = 16;
// Number of points granted for a solo (10 is the ODS value)
arbitration.add("solo-value", Setting::TypeInt) = 10;
@ -245,6 +249,9 @@ Settings::Settings()
// Maximum number of warnings before getting penalties
arbitration.add("warnings-limit", Setting::TypeInt) = 3;
// Number of search results kept in a search
arbitration.add("search-limit", Setting::TypeInt) = 100;
// Try to read the values from the configuration file
try
{
@ -260,13 +267,16 @@ Settings::Settings()
copySetting<bool>(tmpConf, *m_conf, "freegame.reject-invalid");
copySetting<bool>(tmpConf, *m_conf, "arbitration.fill-rack");
copySetting<int>(tmpConf, *m_conf, "arbitration.search-limit");
copySetting<bool>(tmpConf, *m_conf, "arbitration.solo-auto");
copySetting<int>(tmpConf, *m_conf, "arbitration.solo-players");
copySetting<int>(tmpConf, *m_conf, "arbitration.solo-value");
copySetting<int>(tmpConf, *m_conf, "arbitration.penalty-value");
copySetting<int>(tmpConf, *m_conf, "arbitration.warnings-limit");
}
catch (...)
catch (const std::exception &e)
{
// Ignore the exception
// Only log the exception
LOG_ERROR("Error reading config file: " << e.what());
}
#endif
}
@ -347,6 +357,8 @@ int Settings::getInt(const string &iName) const
return 10;
else if (iName == "arbitration.search-limit")
return 100;
else if (iName == "arbitration.solo-players")
return 16;
else if (iName == "arbitration.solo-value")
return 5;
else if (iName == "arbitration.penalty-value")