mirror of
git://git.savannah.nongnu.org/eliot.git
synced 2025-01-18 10:26:15 +01:00
Arbitration: new option to handle solos automatically.
The option is not yet accessible from the interface.
This commit is contained in:
parent
4d38c99336
commit
19a93988ad
4 changed files with 109 additions and 32 deletions
|
@ -221,6 +221,15 @@ void Arbitration::assignMove(unsigned int iPlayerId, const Move &iMove)
|
||||||
{
|
{
|
||||||
ASSERT(iPlayerId < getNPlayers(), "Wrong player number");
|
ASSERT(iPlayerId < getNPlayers(), "Wrong player number");
|
||||||
recordPlayerMove(*m_players[iPlayerId], iMove);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "ai_player.h"
|
#include "ai_player.h"
|
||||||
#include "navigation.h"
|
#include "navigation.h"
|
||||||
#include "turn.h"
|
#include "turn.h"
|
||||||
|
#include "turn_data.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "encoding.h"
|
#include "encoding.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
@ -288,37 +289,21 @@ void Duplicate::endTurn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle solo bonus (not in arbitration mode, because we may not have all
|
// Handle solo bonus
|
||||||
// the moves to decide whether a solo can be attributed).
|
|
||||||
if (!isArbitrationGame())
|
if (!isArbitrationGame())
|
||||||
{
|
{
|
||||||
// First check whether there are enough players in the game for the
|
unsigned minNbPlayers = Settings::Instance().getInt("duplicate.solo-players");
|
||||||
// bonus to apply
|
int soloValue = Settings::Instance().getInt("duplicate.solo-value");
|
||||||
unsigned int minNbPlayers = Settings::Instance().getInt("duplicate.solo-players");
|
setSoloAuto(minNbPlayers, soloValue);
|
||||||
// Find the player with the best score
|
|
||||||
Player *bestPlayer = findBestPlayer();
|
|
||||||
if (getNPlayers() >= minNbPlayers && 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;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
if (!otherWithSameScore)
|
|
||||||
{
|
{
|
||||||
// Give the bonus to the player of the best move
|
bool useSoloAuto = Settings::Instance().getBool("arbitration.solo-auto");
|
||||||
int bonus = Settings::Instance().getInt("duplicate.solo-value");
|
if (useSoloAuto)
|
||||||
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
|
/// Predicate to help retrieving commands
|
||||||
struct MatchingPlayerAndEventType : public unary_function<PlayerEventCmd, bool>
|
struct MatchingPlayerAndEventType : public unary_function<PlayerEventCmd, bool>
|
||||||
{
|
{
|
||||||
|
|
|
@ -141,6 +141,16 @@ protected:
|
||||||
const PlayerEventCmd * getPlayerEvent(unsigned iPlayerId,
|
const PlayerEventCmd * getPlayerEvent(unsigned iPlayerId,
|
||||||
int iEventType) const;
|
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
|
private: // Used by friend classes
|
||||||
void innerSetMasterMove(const Move &iMove);
|
void innerSetMasterMove(const Move &iMove);
|
||||||
bool isArbitrationGame() const;
|
bool isArbitrationGame() const;
|
||||||
|
|
|
@ -233,8 +233,12 @@ Settings::Settings()
|
||||||
// If true, a random rack is defined, otherwise the rack is left untouched
|
// If true, a random rack is defined, otherwise the rack is left untouched
|
||||||
arbitration.add("fill-rack", Setting::TypeBoolean) = true;
|
arbitration.add("fill-rack", Setting::TypeBoolean) = true;
|
||||||
|
|
||||||
// Number of search results kept in a search
|
// If true, solos are automatically given when appropriate
|
||||||
arbitration.add("search-limit", Setting::TypeInt) = 100;
|
// 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)
|
// Number of points granted for a solo (10 is the ODS value)
|
||||||
arbitration.add("solo-value", Setting::TypeInt) = 10;
|
arbitration.add("solo-value", Setting::TypeInt) = 10;
|
||||||
|
@ -245,6 +249,9 @@ Settings::Settings()
|
||||||
// Maximum number of warnings before getting penalties
|
// Maximum number of warnings before getting penalties
|
||||||
arbitration.add("warnings-limit", Setting::TypeInt) = 3;
|
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 to read the values from the configuration file
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -260,13 +267,16 @@ Settings::Settings()
|
||||||
copySetting<bool>(tmpConf, *m_conf, "freegame.reject-invalid");
|
copySetting<bool>(tmpConf, *m_conf, "freegame.reject-invalid");
|
||||||
copySetting<bool>(tmpConf, *m_conf, "arbitration.fill-rack");
|
copySetting<bool>(tmpConf, *m_conf, "arbitration.fill-rack");
|
||||||
copySetting<int>(tmpConf, *m_conf, "arbitration.search-limit");
|
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.solo-value");
|
||||||
copySetting<int>(tmpConf, *m_conf, "arbitration.penalty-value");
|
copySetting<int>(tmpConf, *m_conf, "arbitration.penalty-value");
|
||||||
copySetting<int>(tmpConf, *m_conf, "arbitration.warnings-limit");
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -347,6 +357,8 @@ int Settings::getInt(const string &iName) const
|
||||||
return 10;
|
return 10;
|
||||||
else if (iName == "arbitration.search-limit")
|
else if (iName == "arbitration.search-limit")
|
||||||
return 100;
|
return 100;
|
||||||
|
else if (iName == "arbitration.solo-players")
|
||||||
|
return 16;
|
||||||
else if (iName == "arbitration.solo-value")
|
else if (iName == "arbitration.solo-value")
|
||||||
return 5;
|
return 5;
|
||||||
else if (iName == "arbitration.penalty-value")
|
else if (iName == "arbitration.penalty-value")
|
||||||
|
|
Loading…
Reference in a new issue