From a800863c1f2d2aed20b13434697576e9320d3d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Teuli=C3=A8re?= Date: Fri, 5 Oct 2012 12:52:42 +0200 Subject: [PATCH] Arbitration: do not handle solos automatically. The arbitrator has to specify them manually. Otherwise, we cannot know when a turn is complete and thus we cannot determine if solos can/should be applied. --- game/arbitration.cpp | 47 +++++++++++++++++++++++++++++++++++- game/arbitration.h | 4 ++++ game/duplicate.cpp | 52 +++++++++++++++++++++------------------- game/player.cpp | 2 +- game/public_game.cpp | 16 +++++++++++++ game/public_game.h | 3 +++ game/settings.cpp | 20 +++++++--------- qt/arbit_assignments.cpp | 36 ++++++++++++++++++++++++---- qt/arbit_assignments.h | 1 + qt/prefs_dialog.cpp | 9 +++---- qt/stats_widget.cpp | 30 +++++++++++------------ qt/ui/prefs_dialog.ui | 51 +++++++++++++-------------------------- 12 files changed, 174 insertions(+), 97 deletions(-) diff --git a/game/arbitration.cpp b/game/arbitration.cpp index 8499d4a..64a4021 100644 --- a/game/arbitration.cpp +++ b/game/arbitration.cpp @@ -109,6 +109,51 @@ struct MatchingPlayerAndEventType : public unary_function }; +void Arbitration::setSolo(unsigned iPlayerId, int iPoints) +{ + ASSERT(iPlayerId < getNPlayers(), "Wrong player number"); + ASSERT(iPoints >= 0, "Expected a positive value for the solo"); + + if (iPoints == 0) + { + // Retrieve the default value of the solo + iPoints = Settings::Instance().getInt("arbitration.solo-value"); + } + LOG_INFO("Giving a solo of " << iPoints << " to player " << iPlayerId); + + // If an existing solo exists, get rid of it + const PlayerEventCmd *cmd = getPlayerEvent(iPlayerId, PlayerEventCmd::SOLO); + if (cmd != 0) + { + accessNavigation().dropCommand(*cmd); + } + + Command *pCmd = new PlayerEventCmd(*m_players[iPlayerId], + PlayerEventCmd::SOLO, iPoints); + accessNavigation().insertCommand(pCmd); +} + + +void Arbitration::removeSolo(unsigned iPlayerId) +{ + ASSERT(iPlayerId < getNPlayers(), "Wrong player number"); + const PlayerEventCmd *cmd = getPlayerEvent(iPlayerId, PlayerEventCmd::SOLO); + ASSERT(cmd != 0, "No matching PlayerEventCmd found"); + + accessNavigation().dropCommand(*cmd); +} + + +int Arbitration::getSolo(unsigned iPlayerId) const +{ + ASSERT(iPlayerId < getNPlayers(), "Wrong player number"); + const PlayerEventCmd *cmd = getPlayerEvent(iPlayerId, PlayerEventCmd::SOLO); + if (cmd == 0) + return 0; + return cmd->getPoints(); +} + + void Arbitration::addWarning(unsigned iPlayerId) { ASSERT(iPlayerId < getNPlayers(), "Wrong player number"); @@ -144,7 +189,7 @@ void Arbitration::addPenalty(unsigned iPlayerId, int iPoints) if (iPoints == 0) { // Retrieve the default value of the penalty - iPoints = Settings::Instance().getInt("arbitration.default-penalty"); + iPoints = Settings::Instance().getInt("arbitration.penalty-value"); // By convention, use negative values to indicate a penalty iPoints = -iPoints; diff --git a/game/arbitration.h b/game/arbitration.h index 832afc8..3247de2 100644 --- a/game/arbitration.h +++ b/game/arbitration.h @@ -56,6 +56,10 @@ public: Move checkWord(const wstring &iWord, const wstring &iCoords) const; + void setSolo(unsigned iPlayerId, int iPoints = 0); + void removeSolo(unsigned iPlayerId); + int getSolo(unsigned iPlayerId) const; + void addWarning(unsigned iPlayerId); void removeWarning(unsigned iPlayerId); bool hasWarning(unsigned iPlayerId) const; diff --git a/game/duplicate.cpp b/game/duplicate.cpp index a257044..c8e1166 100644 --- a/game/duplicate.cpp +++ b/game/duplicate.cpp @@ -288,35 +288,37 @@ void Duplicate::endTurn() } } - // Handle solo bonus - // First check whether there are enough players in the game for the - // bonus to apply - unsigned int minNbPlayers = Settings::Instance().getInt( - isArbitrationGame() ? "arbitration.solo-players" : "duplicate.solo-players"); - // Find the player with the best score - Player *bestPlayer = findBestPlayer(); - if (getNPlayers() >= minNbPlayers && bestPlayer != NULL) + // Handle solo bonus (not in arbitration mode, because we may not have all + // the moves to decide whether a solo can be attributed). + if (!isArbitrationGame()) { - 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) + // 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) { - if (player != bestPlayer && - player->getLastMove().getScore() >= bestScore && - player->getLastMove().isValid()) + 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) { - otherWithSameScore = true; - break; + 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); } - } - if (!otherWithSameScore) - { - // Give the bonus to the player of the best move - int bonus = Settings::Instance().getInt( - isArbitrationGame() ? "arbitration.solo-value" : "duplicate.solo-value"); - Command *pCmd = new PlayerEventCmd(*bestPlayer, PlayerEventCmd::SOLO, bonus); - accessNavigation().addAndExecute(pCmd); } } diff --git a/game/player.cpp b/game/player.cpp index 62c1e21..d3f012a 100644 --- a/game/player.cpp +++ b/game/player.cpp @@ -109,7 +109,7 @@ int Player::getPenaltyPoints() const if ((int)warningsNb > limit) { int penaltiesPoints = - Settings::Instance().getInt("arbitration.default-penalty"); + Settings::Instance().getInt("arbitration.penalty-value"); total -= penaltiesPoints * (warningsNb - limit); } return total; diff --git a/game/public_game.cpp b/game/public_game.cpp index a191bd3..9a814ea 100644 --- a/game/public_game.cpp +++ b/game/public_game.cpp @@ -284,6 +284,22 @@ Move PublicGame::arbitrationCheckWord(const wstring &iWord, } +void PublicGame::arbitrationToggleSolo(unsigned iPlayerId) +{ + Arbitration &game = getTypedGame(m_game); + if (game.getSolo(iPlayerId) != 0) + game.removeSolo(iPlayerId); + else + game.setSolo(iPlayerId); +} + + +int PublicGame::arbitrationGetSolo(unsigned iPlayerId) const +{ + return getTypedGame(m_game).getSolo(iPlayerId); +} + + void PublicGame::arbitrationToggleWarning(unsigned iPlayerId) { Arbitration &game = getTypedGame(m_game); diff --git a/game/public_game.h b/game/public_game.h index 1fd4634..6d49f14 100644 --- a/game/public_game.h +++ b/game/public_game.h @@ -268,6 +268,9 @@ public: Move arbitrationCheckWord(const wstring &iWord, const wstring &iCoords) const; + void arbitrationToggleSolo(unsigned iPlayerId); + int arbitrationGetSolo(unsigned iPlayerId) const; + void arbitrationToggleWarning(unsigned iPlayerId); bool arbitrationHasWarning(unsigned iPlayerId) const; diff --git a/game/settings.cpp b/game/settings.cpp index f3e121a..cd5dfb8 100644 --- a/game/settings.cpp +++ b/game/settings.cpp @@ -236,18 +236,15 @@ Settings::Settings() // Number of search results kept in a search arbitration.add("search-limit", Setting::TypeInt) = 100; + // Number of points granted for a solo (10 is the ODS value) + arbitration.add("solo-value", Setting::TypeInt) = 10; + // Default value of a penalty - arbitration.add("default-penalty", Setting::TypeInt) = 5; + arbitration.add("penalty-value", Setting::TypeInt) = 5; // Maximum number of warnings before getting penalties arbitration.add("warnings-limit", Setting::TypeInt) = 3; - // Minimum number of players in an arbitration 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; - // Try to read the values from the configuration file try { @@ -263,10 +260,9 @@ Settings::Settings() copySetting(tmpConf, *m_conf, "freegame.reject-invalid"); copySetting(tmpConf, *m_conf, "arbitration.fill-rack"); copySetting(tmpConf, *m_conf, "arbitration.search-limit"); - copySetting(tmpConf, *m_conf, "arbitration.default-penalty"); - copySetting(tmpConf, *m_conf, "arbitration.warnings-limit"); - copySetting(tmpConf, *m_conf, "arbitration.solo-players"); copySetting(tmpConf, *m_conf, "arbitration.solo-value"); + copySetting(tmpConf, *m_conf, "arbitration.penalty-value"); + copySetting(tmpConf, *m_conf, "arbitration.warnings-limit"); } catch (...) { @@ -351,7 +347,9 @@ int Settings::getInt(const string &iName) const return 10; else if (iName == "arbitration.search-limit") return 100; - else if (iName == "arbitration.default-penalty") + else if (iName == "arbitration.solo-value") + return 5; + else if (iName == "arbitration.penalty-value") return 5; else if (iName == "arbitration.warnings-limit") return 3; diff --git a/qt/arbit_assignments.cpp b/qt/arbit_assignments.cpp index aae7aeb..305f395 100644 --- a/qt/arbit_assignments.cpp +++ b/qt/arbit_assignments.cpp @@ -78,6 +78,11 @@ ArbitAssignments::ArbitAssignments(QWidget *parent, PublicGame *iGame) this, SLOT(assignTopMove())); treeViewPlayers->installEventFilter(filter); + filter = new KeyEventFilter(this, Qt::Key_S); + QObject::connect(filter, SIGNAL(keyPressed(int, int)), + this, SLOT(addRemoveSolo())); + treeViewPlayers->installEventFilter(filter); + filter = new KeyEventFilter(this, Qt::Key_W); QObject::connect(filter, SIGNAL(keyPressed(int, int)), this, SLOT(addRemoveWarning())); @@ -271,7 +276,15 @@ void ArbitAssignments::populatePlayersMenu(QMenu &iMenu, const QPoint &iPoint) this, SLOT(assignTopMove())); iMenu.addAction(assignTopMoveAction); - // Action to warn (or "unwarn") players + // Action to give or remove a solo to players + QAction *soloAction = new QAction(_q("Give (or remove) a solo"), this); + soloAction->setStatusTip(_q("Give a solo to the selected player, or remove it if (s)he already has one")); + soloAction->setShortcut(Qt::Key_S); + QObject::connect(soloAction, SIGNAL(triggered()), + this, SLOT(addRemoveSolo())); + iMenu.addAction(soloAction); + + // Action to give or remove a warning to players QAction *warningAction = new QAction(_q("Give (or remove) a warning"), this); warningAction->setStatusTip(_q("Give a warning to the selected player(s), or remove it if they already have one")); warningAction->setShortcut(Qt::Key_W); @@ -279,9 +292,9 @@ void ArbitAssignments::populatePlayersMenu(QMenu &iMenu, const QPoint &iPoint) this, SLOT(addRemoveWarning())); iMenu.addAction(warningAction); - // Action to give a penalty to players - QAction *penaltyAction = new QAction(_q("Give a penalty"), this); - penaltyAction->setStatusTip(_q("Give a penalty to the selected player(s)")); + // Action to give or remove a penalty to players + QAction *penaltyAction = new QAction(_q("Give (or remove) a penalty"), this); + penaltyAction->setStatusTip(_q("Give a penalty to the selected player(s), or remove it if they already have one")); penaltyAction->setShortcut(Qt::Key_P); QObject::connect(penaltyAction, SIGNAL(triggered()), this, SLOT(addRemovePenalty())); @@ -596,6 +609,21 @@ void ArbitAssignments::helperAssignMove(const Move &iMove) } +void ArbitAssignments::addRemoveSolo() +{ + QSet playersIdSet = getSelectedPlayers(); + // Only one player can have a solo + if (playersIdSet.size() != 1) + return; + + BOOST_FOREACH(unsigned int id, playersIdSet) + { + m_game->arbitrationToggleSolo(id); + } + emit gameUpdated(); +} + + void ArbitAssignments::addRemoveWarning() { QSet playersIdSet = getSelectedPlayers(); diff --git a/qt/arbit_assignments.h b/qt/arbit_assignments.h index 3d8acef..64018ec 100644 --- a/qt/arbit_assignments.h +++ b/qt/arbit_assignments.h @@ -81,6 +81,7 @@ private slots: void populatePlayersMenu(QMenu &iMenu, const QPoint &iPoint); void assignTopMove(); void suppressMove(); + void addRemoveSolo(); void addRemoveWarning(); void addRemovePenalty(); void endTurn(); diff --git a/qt/prefs_dialog.cpp b/qt/prefs_dialog.cpp index 24a08f1..8aa561f 100644 --- a/qt/prefs_dialog.cpp +++ b/qt/prefs_dialog.cpp @@ -135,9 +135,8 @@ PrefsDialog::PrefsDialog(QWidget *iParent) bool linkArbit7P1 = qs.value(kARBIT_LINK_7P1, false).toBool(); checkBoxArbitLink7P1->setChecked(linkArbit7P1); spinBoxArbitSearchLimit->setValue(Settings::Instance().getInt("arbitration.search-limit")); - spinBoxArbitDefPenalty->setValue(Settings::Instance().getInt("arbitration.default-penalty")); + spinBoxArbitPenaltyValue->setValue(Settings::Instance().getInt("arbitration.penalty-value")); spinBoxArbitWarnLimit->setValue(Settings::Instance().getInt("arbitration.warnings-limit")); - spinBoxArbitSoloPlayers->setValue(Settings::Instance().getInt("arbitration.solo-players")); spinBoxArbitSoloValue->setValue(Settings::Instance().getInt("arbitration.solo-value")); // Confirmations @@ -255,12 +254,10 @@ void PrefsDialog::updateSettings() } Settings::Instance().setInt("arbitration.search-limit", spinBoxArbitSearchLimit->value()); - Settings::Instance().setInt("arbitration.default-penalty", - spinBoxArbitDefPenalty->value()); + Settings::Instance().setInt("arbitration.penalty-value", + spinBoxArbitPenaltyValue->value()); Settings::Instance().setInt("arbitration.warnings-limit", spinBoxArbitWarnLimit->value()); - Settings::Instance().setInt("arbitration.solo-players", - spinBoxArbitSoloPlayers->value()); Settings::Instance().setInt("arbitration.solo-value", spinBoxArbitSoloValue->value()); diff --git a/qt/stats_widget.cpp b/qt/stats_widget.cpp index dd2f72e..ee10f7d 100644 --- a/qt/stats_widget.cpp +++ b/qt/stats_widget.cpp @@ -108,12 +108,12 @@ void StatsWidget::refresh() setSectionHidden(col, !isArbit && !canHaveSolos); setModelHeader(col++, _q("Sub-total"), false); - setSectionHidden(col, !isArbit); - setModelHeader(col++, _q("Warnings"), false); - setSectionHidden(col, !isArbit); - setModelHeader(col++, _q("Penalties"), false); setSectionHidden(col, !isArbit && !canHaveSolos); setModelHeader(col++, _q("Solo points"), false); + setSectionHidden(col, !isArbit); + setModelHeader(col++, _q("Penalties"), false); + setSectionHidden(col, !isArbit); + setModelHeader(col++, _q("Warnings"), false); setModelHeader(col++, _q("Total"), false); setModelHeader(col++, _q("Diff"), false); @@ -277,12 +277,12 @@ void StatsWidget::setModelTurnData(const QModelIndex &iIndex, } // Set the background c constolor - if (iTurn.getPenaltyPoints() != 0) + if (iTurn.getSoloPoints() != 0) + m_model->setData(iIndex, SoloBrush, Qt::BackgroundRole); + else if (iTurn.getPenaltyPoints() != 0) m_model->setData(iIndex, PenaltyBrush, Qt::BackgroundRole); else if (iTurn.getWarningsNb() != 0) m_model->setData(iIndex, WarningBrush, Qt::BackgroundRole); - else if (iTurn.getSoloPoints() != 0) - m_model->setData(iIndex, SoloBrush, Qt::BackgroundRole); else if (iTurn.getMove().isNull()) m_model->setData(iIndex, PassBrush, Qt::BackgroundRole); @@ -300,12 +300,12 @@ void StatsWidget::setModelEventData(const QModelIndex &iIndex, int iEvent, const Player &iPlayer) { QVariant text; - if (iEvent == 0 && iPlayer.getWarningsNb() != 0) - text = iPlayer.getWarningsNb(); + if (iEvent == 0 && iPlayer.getSoloPoints() != 0) + text = iPlayer.getSoloPoints(); else if (iEvent == 1 && iPlayer.getPenaltyPoints() != 0) text = iPlayer.getPenaltyPoints(); - else if (iEvent == 2 && iPlayer.getSoloPoints() != 0) - text = iPlayer.getSoloPoints(); + else if (iEvent == 2 && iPlayer.getWarningsNb() != 0) + text = iPlayer.getWarningsNb(); setModelText(iIndex, text); } @@ -352,6 +352,10 @@ QString StatsWidget::getTooltip(const Turn &iTurn, const Turn &iGameTurn) const tooltip += "\n" + scoreString.arg(score - gameScore); } + if (iTurn.getSoloPoints()) + { + tooltip += "\n" + _q("Solo: %1").arg(iTurn.getSoloPoints()); + } if (iTurn.getWarningsNb()) { tooltip += "\n" + _q("Warnings: %1").arg(iTurn.getWarningsNb()); @@ -360,10 +364,6 @@ QString StatsWidget::getTooltip(const Turn &iTurn, const Turn &iGameTurn) const { tooltip += "\n" + _q("Penalties: %1").arg(iTurn.getPenaltyPoints()); } - if (iTurn.getSoloPoints()) - { - tooltip += "\n" + _q("Solo: %1").arg(iTurn.getSoloPoints()); - } return tooltip; } diff --git a/qt/ui/prefs_dialog.ui b/qt/ui/prefs_dialog.ui index d9c4dd7..62d285f 100644 --- a/qt/ui/prefs_dialog.ui +++ b/qt/ui/prefs_dialog.ui @@ -7,7 +7,7 @@ 0 0 474 - 655 + 622 @@ -363,7 +363,7 @@ - + 3 @@ -380,22 +380,22 @@ - + - _("Default penalty value:") + _("Penalty value:") - + _("Warnings limit:") - - + + _("Default number of points for a penalty") @@ -407,13 +407,6 @@ - - - - _("Search results limit:") - - - @@ -427,37 +420,27 @@ - - - - _("Value of the solo bonus. Set it to 0 if you don't want solo bonus") - - - 10 + + + + _("Search results limit:") - + _("Solo value:") - - - - _("Min. players for a solo:") - - - - - + + - _("Minimum number of players needed to take into account the solo bonus") + _("Value of the solo bonus. Set it to 0 if you don't want solo bonus") - 16 + 10 @@ -636,7 +619,7 @@ checkBoxArbitFillRack checkBoxArbitLink7P1 spinBoxArbitSearchLimit - spinBoxArbitDefPenalty + spinBoxArbitPenaltyValue checkBoxConfoStartGame checkBoxConfoLoadGame checkBoxConfoLoadDic