2012-03-05 01:27:56 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* Eliot
|
2012-10-07 16:25:41 +02:00
|
|
|
* Copyright (C) 2005-2012 Olivier Teulière
|
2012-03-05 01:27:56 +01:00
|
|
|
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2012-03-14 21:08:09 +01:00
|
|
|
#include <boost/foreach.hpp>
|
2012-03-11 00:24:21 +01:00
|
|
|
|
2012-03-05 01:27:56 +01:00
|
|
|
#include "arbitration.h"
|
|
|
|
#include "rack.h"
|
|
|
|
#include "player.h"
|
2012-10-06 11:14:01 +02:00
|
|
|
#include "turn.h"
|
2012-03-17 23:45:47 +01:00
|
|
|
#include "results.h"
|
2012-12-05 20:26:47 +01:00
|
|
|
#include "cmd/game_rack_cmd.h"
|
|
|
|
#include "cmd/player_move_cmd.h"
|
|
|
|
#include "cmd/player_event_cmd.h"
|
2012-03-05 01:27:56 +01:00
|
|
|
#include "settings.h"
|
|
|
|
#include "encoding.h"
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
|
|
|
|
INIT_LOGGER(game, Arbitration);
|
|
|
|
|
|
|
|
|
2012-12-30 16:14:13 +01:00
|
|
|
Arbitration::Arbitration(const GameParams &iParams, const Game *iMasterGame)
|
|
|
|
: Duplicate(iParams, iMasterGame)
|
2012-03-05 01:27:56 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-11 00:24:21 +01:00
|
|
|
void Arbitration::setRackRandom()
|
|
|
|
{
|
2012-12-30 16:14:13 +01:00
|
|
|
ASSERT(!hasMasterGame(),
|
|
|
|
"Changing the rack is not allowed when there is a master game");
|
|
|
|
|
2012-03-11 00:24:21 +01:00
|
|
|
undoCurrentRack();
|
|
|
|
|
|
|
|
const PlayedRack &newRack =
|
2012-05-30 20:37:47 +02:00
|
|
|
helperSetRackRandom(getHistory().getCurrentRack(), true, RACK_NEW);
|
2013-01-15 11:38:46 +01:00
|
|
|
setGameAndPlayersRack(newRack, true);
|
2012-03-11 00:24:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Arbitration::setRackManual(const wstring &iLetters)
|
|
|
|
{
|
2012-12-30 16:14:13 +01:00
|
|
|
ASSERT(!hasMasterGame(),
|
|
|
|
"Changing the rack is not allowed when there is a master game");
|
|
|
|
|
2012-03-11 00:24:21 +01:00
|
|
|
undoCurrentRack();
|
|
|
|
|
|
|
|
// Letters can be lowercase or uppercase as they are
|
|
|
|
// coming from user input. We do not consider a lowercase
|
|
|
|
// letter to be a joker which has been assigned to a letter.
|
|
|
|
// As a result, we simply make all the letters uppercase
|
2012-12-23 18:15:55 +01:00
|
|
|
const wstring &upperLetters = toUpper(iLetters);
|
2012-03-11 00:19:36 +01:00
|
|
|
const PlayedRack &newRack = helperSetRackManual(false, upperLetters);
|
2013-01-15 11:38:46 +01:00
|
|
|
setGameAndPlayersRack(newRack, true);
|
2012-03-11 00:24:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-17 23:45:47 +01:00
|
|
|
void Arbitration::search(LimitResults &oResults)
|
2012-03-05 01:27:56 +01:00
|
|
|
{
|
2012-03-11 16:57:27 +01:00
|
|
|
const Rack &rack = getHistory().getCurrentRack().getRack();
|
2012-03-05 01:27:56 +01:00
|
|
|
LOG_DEBUG("Performing search for rack " + lfw(rack.toString()));
|
2012-03-05 22:15:42 +01:00
|
|
|
int limit = Settings::Instance().getInt("arbitration.search-limit");
|
2012-03-17 23:45:47 +01:00
|
|
|
oResults.setLimit(limit);
|
|
|
|
oResults.search(getDic(), getBoard(), rack, getHistory().beforeFirstRound());
|
|
|
|
LOG_DEBUG("Found " << oResults.size() << " results");
|
2012-03-05 01:27:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Move Arbitration::checkWord(const wstring &iWord,
|
|
|
|
const wstring &iCoords) const
|
|
|
|
{
|
2012-12-23 19:31:03 +01:00
|
|
|
Move move;
|
|
|
|
checkPlayedWord(iCoords, iWord, move, true);
|
|
|
|
return move;
|
2012-03-05 01:27:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-05 12:52:42 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-23 07:41:16 +01:00
|
|
|
void Arbitration::addWarning(unsigned iPlayerId)
|
|
|
|
{
|
|
|
|
ASSERT(iPlayerId < getNPlayers(), "Wrong player number");
|
|
|
|
Command *pCmd = new PlayerEventCmd(*m_players[iPlayerId],
|
|
|
|
PlayerEventCmd::WARNING, 0);
|
|
|
|
accessNavigation().insertCommand(pCmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Arbitration::removeWarning(unsigned iPlayerId)
|
|
|
|
{
|
|
|
|
ASSERT(iPlayerId < getNPlayers(), "Wrong player number");
|
|
|
|
const PlayerEventCmd *cmd = getPlayerEvent(iPlayerId, PlayerEventCmd::WARNING);
|
|
|
|
ASSERT(cmd != 0, "No matching PlayerEventCmd found");
|
|
|
|
|
|
|
|
accessNavigation().dropCommand(*cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Arbitration::hasWarning(unsigned iPlayerId) const
|
|
|
|
{
|
|
|
|
ASSERT(iPlayerId < getNPlayers(), "Wrong player number");
|
|
|
|
const PlayerEventCmd *cmd = getPlayerEvent(iPlayerId, PlayerEventCmd::WARNING);
|
|
|
|
return cmd != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-23 08:12:03 +01:00
|
|
|
void Arbitration::addPenalty(unsigned iPlayerId, int iPoints)
|
|
|
|
{
|
|
|
|
ASSERT(iPlayerId < getNPlayers(), "Wrong player number");
|
2012-05-20 22:12:42 +02:00
|
|
|
ASSERT(iPoints <= 0, "Expected a negative value for the penalty");
|
2012-03-23 08:12:03 +01:00
|
|
|
|
|
|
|
if (iPoints == 0)
|
|
|
|
{
|
|
|
|
// Retrieve the default value of the penalty
|
2012-10-05 12:52:42 +02:00
|
|
|
iPoints = Settings::Instance().getInt("arbitration.penalty-value");
|
2012-05-20 22:12:42 +02:00
|
|
|
|
|
|
|
// By convention, use negative values to indicate a penalty
|
|
|
|
iPoints = -iPoints;
|
2012-03-23 08:12:03 +01:00
|
|
|
}
|
|
|
|
LOG_INFO("Giving a penalty of " << iPoints << " to player " << iPlayerId);
|
|
|
|
|
|
|
|
// If an existing penalty exists, merge it with the new one
|
|
|
|
const PlayerEventCmd *cmd = getPlayerEvent(iPlayerId, PlayerEventCmd::PENALTY);
|
|
|
|
if (cmd == 0)
|
|
|
|
{
|
|
|
|
Command *pCmd = new PlayerEventCmd(*m_players[iPlayerId],
|
|
|
|
PlayerEventCmd::PENALTY, iPoints);
|
|
|
|
accessNavigation().insertCommand(pCmd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-05-20 22:12:42 +02:00
|
|
|
// When the resulting value is 0, instead of merging we drop the existing one
|
2012-03-23 08:12:03 +01:00
|
|
|
Command *pCmd = new PlayerEventCmd(*m_players[iPlayerId],
|
|
|
|
PlayerEventCmd::PENALTY,
|
|
|
|
iPoints + cmd->getPoints());
|
|
|
|
accessNavigation().replaceCommand(*cmd, pCmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-20 22:12:42 +02:00
|
|
|
void Arbitration::removePenalty(unsigned iPlayerId)
|
|
|
|
{
|
|
|
|
ASSERT(iPlayerId < getNPlayers(), "Wrong player number");
|
|
|
|
const PlayerEventCmd *cmd = getPlayerEvent(iPlayerId, PlayerEventCmd::PENALTY);
|
|
|
|
ASSERT(cmd != 0, "No penalty found for player " << iPlayerId);
|
|
|
|
accessNavigation().dropCommand(*cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-23 08:12:03 +01:00
|
|
|
int Arbitration::getPenalty(unsigned iPlayerId) const
|
|
|
|
{
|
|
|
|
ASSERT(iPlayerId < getNPlayers(), "Wrong player number");
|
|
|
|
const PlayerEventCmd *cmd = getPlayerEvent(iPlayerId, PlayerEventCmd::PENALTY);
|
|
|
|
if (cmd == 0)
|
|
|
|
return 0;
|
|
|
|
return cmd->getPoints();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-05 01:27:56 +01:00
|
|
|
void Arbitration::assignMove(unsigned int iPlayerId, const Move &iMove)
|
|
|
|
{
|
|
|
|
ASSERT(iPlayerId < getNPlayers(), "Wrong player number");
|
2012-04-08 01:07:59 +02:00
|
|
|
recordPlayerMove(*m_players[iPlayerId], iMove);
|
2012-12-05 23:02:12 +01:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
2012-03-05 01:27:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Arbitration::finalizeTurn()
|
|
|
|
{
|
|
|
|
tryEndTurn();
|
|
|
|
}
|
|
|
|
|
2012-03-11 00:24:21 +01:00
|
|
|
|
|
|
|
void Arbitration::undoCurrentRack()
|
|
|
|
{
|
|
|
|
// The interface is supposed to make sure we are never in this case
|
|
|
|
ASSERT(getNavigation().isLastTurn(),
|
|
|
|
"Cannot change rack for an old turn");
|
|
|
|
|
2012-03-23 07:41:16 +01:00
|
|
|
// Find the GameRackCmd we want to undo
|
2012-03-11 00:24:21 +01:00
|
|
|
const GameRackCmd *cmd =
|
|
|
|
getNavigation().getCurrentTurn().findMatchingCmd<GameRackCmd>();
|
|
|
|
ASSERT(cmd != 0, "No matching GameRackCmd found");
|
|
|
|
|
|
|
|
accessNavigation().dropFrom(*cmd);
|
|
|
|
}
|
|
|
|
|