duplicate.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Copyright (C) 2005 Eliot
00003  * Authors: Olivier Teuliere  <ipkiss@via.ecp.fr>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  *****************************************************************************/
00019 
00020 #include "dic.h"
00021 #include "tile.h"
00022 #include "rack.h"
00023 #include "round.h"
00024 #include "pldrack.h"
00025 #include "results.h"
00026 #include "player.h"
00027 #include "ai_player.h"
00028 #include "duplicate.h"
00029 #include "debug.h"
00030 
00031 
00032 Duplicate::Duplicate(const Dictionary &iDic): Game(iDic)
00033 {
00034 }
00035 
00036 
00037 Duplicate::~Duplicate()
00038 {
00039 }
00040 
00041 
00042 int Duplicate::setRackRandom(int p, bool iCheck, set_rack_mode mode)
00043 {
00044     int res;
00045     do
00046     {
00047         res = helperSetRackRandom(p, iCheck, mode);
00048     } while (res == 2);
00049     return res;
00050 }
00051 
00052 
00053 int Duplicate::play(const string &iCoord, const string &iWord)
00054 {
00055     /* Perform all the validity checks, and fill a round */
00056     Round round;
00057     int res = checkPlayedWord(iCoord, iWord, round);
00058     if (res != 0)
00059     {
00060         return res;
00061     }
00062 
00063     /* Everything is OK, we can play the word */
00064     playRound(round, m_currPlayer);
00065 
00066     /* Next turn */
00067     // XXX: Should it be done by the interface instead?
00068     endTurn();
00069 
00070     return 0;
00071 }
00072 
00073 
00074 void Duplicate::duplicateAI(int n)
00075 {
00076     ASSERT(0 <= n && n < getNPlayers(), "Wrong player number");
00077     ASSERT(!m_players[n]->isHuman(), "AI requested for a human player");
00078 
00079     AIPlayer *player = static_cast<AIPlayer*>(m_players[n]);
00080     player->compute(*m_dic, m_board, m_history.getSize());
00081 
00082     if (player->changesLetters())
00083     {
00084         // The AI player has nothing to play. This should not happen in
00085         // duplicate mode, otherwise the implementation of the AI is buggy...
00086         ASSERT(false, "AI player has nothing to play!");
00087     }
00088     else
00089     {
00090         playRound(player->getChosenRound(), n);
00091     }
00092 }
00093 
00094 
00095 int Duplicate::start()
00096 {
00097     ASSERT(getNPlayers(), "Cannot start a game without any player");
00098 
00099     m_currPlayer = 0;
00100 
00101     /* XXX: code similar with endTurnForReal() */
00102     /* Complete the rack for the player that just played */
00103     int res = setRackRandom(m_currPlayer, true, RACK_NEW);
00104     /* End of the game? */
00105     if (res == 1)
00106     {
00107         end();
00108         return 1;
00109     }
00110 
00111     const PlayedRack& pld = m_players[m_currPlayer]->getCurrentRack();
00112     /* All the players have the same rack */
00113     for (int i = 0; i < getNPlayers(); i++)
00114     {
00115         if (i != m_currPlayer)
00116         {
00117             m_players[i]->setCurrentRack(pld);
00118         }
00119         /* Nobody has played yet in this round */
00120         m_hasPlayed[i] = false;
00121     }
00122 
00123     /* Next turn */
00124     // XXX: Should it be done by the interface instead?
00125     endTurn();
00126 
00127     return 0;
00128 }
00129 
00130 
00131 /*
00132  * This function does not terminate the turn itself, but performs some
00133  * checks to know whether or not it should be terminated (with a call to
00134  * endTurnForReal()).
00135  *
00136  * For the turn to be terminated, all the players must have played.
00137  * Since the AI players play after the human players, we check whether
00138  * one of the human players has not played yet:
00139  *   - if so, we have nothing to do (we are waiting for him)
00140  *   - if not (all human players have played), the AI players can play,
00141  *     and we finish the turn.
00142  */
00143 int Duplicate::endTurn()
00144 {
00145     int i;
00146     for (i = 0; i < getNPlayers(); i++)
00147     {
00148         if (m_players[i]->isHuman() && !m_hasPlayed[i])
00149         {
00150             /* A human player has not played... */
00151             m_currPlayer = i;
00152             // XXX: check return code meaning
00153             return 1;
00154         }
00155     }
00156 
00157     /* If all the human players have played */
00158     if (i == getNPlayers())
00159     {
00160         /* Make AI players play their turn */
00161         for (i = 0; i < getNPlayers(); i++)
00162         {
00163             if (!m_players[i]->isHuman())
00164             {
00165                 duplicateAI(i);
00166             }
00167         }
00168 
00169         /* Next turn */
00170         endTurnForReal();
00171     }
00172 
00173     // XXX: check return code meaning
00174     return 0;
00175 }
00176 
00177 
00178 void Duplicate::playRound(const Round &iRound, int n)
00179 {
00180     ASSERT(0 <= n && n < getNPlayers(), "Wrong player number");
00181     Player *player = m_players[n];
00182 
00183     /* Update the rack and the score of the current player */
00184     player->addPoints(iRound.getPoints());
00185     player->endTurn(iRound, m_history.getSize());
00186 
00187     m_hasPlayed[n] = true;
00188 }
00189 
00190 
00191 /*
00192  * This function really changes the turn, i.e. the best word is played and
00193  * a new rack is given to the players.
00194  * We suppose that all the players have finished to play for this turn (this
00195  * should have been checked by endturn())
00196  */
00197 int Duplicate::endTurnForReal()
00198 {
00199     int res, i, imax;
00200 
00201     /* Play the best word on the board */
00202     imax = 0;
00203     for (i = 1; i < getNPlayers(); i++)
00204     {
00205         if (m_players[i]->getLastRound().getPoints() >
00206             m_players[imax]->getLastRound().getPoints())
00207         {
00208             imax = i;
00209         }
00210     }
00211     m_currPlayer = imax;
00212     helperPlayRound(m_players[imax]->getLastRound());
00213 
00214     /* Complete the rack for the player that just played */
00215     res = setRackRandom(imax, true, RACK_NEW);
00216     /* End of the game? */
00217     if (res == 1)
00218     {
00219         end();
00220         return 1;
00221     }
00222 
00223     const PlayedRack& pld = m_players[imax]->getCurrentRack();
00224     /* All the players have the same rack */
00225     for (i = 0; i < getNPlayers(); i++)
00226     {
00227         if (i != imax)
00228         {
00229             m_players[i]->setCurrentRack(pld);
00230         }
00231         /* Nobody has played yet in this round */
00232         m_hasPlayed[i] = false;
00233     }
00234 
00235     /* XXX: Little hack to handle the games with only AI players.
00236      * This will have no effect when there is at least one human player */
00237     endTurn();
00238 
00239     return 0;
00240 }
00241 
00242 
00243 void Duplicate::end()
00244 {
00245     m_finished = true;
00246 }
00247 
00248 
00249 int Duplicate::setPlayer(int n)
00250 {
00251     ASSERT(0 <= n && n < getNPlayers(), "Wrong player number");
00252 
00253     /* Forbid switching to an AI player */
00254     if (!m_players[n]->isHuman())
00255         return 1;
00256 
00257     m_currPlayer = n;
00258     return 0;
00259 }
00260 
00261 
00262 void Duplicate::prevHumanPlayer()
00263 {
00264     if (getNHumanPlayers() == 0)
00265         return;
00266     // FIXME: possible infinite loop...
00267     do
00268     {
00269         prevPlayer();
00270     } while (!m_players[m_currPlayer]->isHuman() ||
00271              m_hasPlayed[m_currPlayer]);
00272 }
00273 
00274 
00275 void Duplicate::nextHumanPlayer()
00276 {
00277     if (getNHumanPlayers() == 0)
00278         return;
00279     // FIXME: possible infinite loop...
00280     do
00281     {
00282         nextPlayer();
00283     } while (!m_players[m_currPlayer]->isHuman() ||
00284              m_hasPlayed[m_currPlayer]);
00285 }
00286 
00287 /// Local Variables:
00288 /// mode: c++
00289 /// mode: hs-minor
00290 /// c-basic-offset: 4
00291 /// indent-tabs-mode: nil
00292 /// End:

Generated on Thu Dec 29 02:01:14 2005 for Eliot by  doxygen 1.4.5