eliot-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Eliot-dev] eliot game/Makefile.am game/ai_percent.cpp game... [cppdic]


From: eliot-dev
Subject: [Eliot-dev] eliot game/Makefile.am game/ai_percent.cpp game... [cppdic]
Date: Sun, 23 Dec 2007 23:12:46 +0000

CVSROOT:        /cvsroot/eliot
Module name:    eliot
Branch:         cppdic
Changes by:     Olivier Teulière <ipkiss>      07/12/23 23:12:46

Modified files:
        game           : Makefile.am ai_percent.cpp ai_percent.h 
                         ai_player.h board.h duplicate.cpp duplicate.h 
                         freegame.cpp freegame.h game.cpp game.h 
                         game_io.cpp history.cpp history.h player.cpp 
                         player.h results.cpp results.h settings.cpp 
                         settings.h training.cpp training.h turn.cpp 
                         turn.h 
        po             : eliot.pot fr.po 
        test           : freegame_change.input freegame_change.ref 
                         freegame_passing.ref 
        utils          : eliottxt.cpp ncurses.cpp 
        wxwin          : mainframe.cc printout.cc searchpanel.cc 
Added files:
        game           : move.cpp move.h 

Log message:
         - New Move class. A Move corresponds to any "action" of a player:
            * playing a valid round
            * trying to play an invalid word/coord pair
            * changing letters (freegame mode only)
            * simply passing the turn (freegame mode only)
         - Use Move objects internally in many places:
            * in Turn objects (so in History as well, indirectly)
            * in the interfaces (at least multi-player ones)
            * in the AIPlayer interface (it simplifies it a lot)
         - New settings (duplicate-reject-invalid and freegame-reject-invalid) 
to
           allow playing invalid moves in duplicate and fregame modes (of 
course,
           the player will get 0 point when playing an invalid word)
         - All the types of moves are now recorded into the game history and 
the 
           players' histories
         - Adapted and improved scenarii for freegame mode
         - Cleaned the interface of the various game classes, renamed methods, 
added and improved comments
         - Update of the French translation
        
        Overall, the introduction of Move objects simplifies the code and gives 
more
        consistency across the various game modes.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/eliot/game/Makefile.am?cvsroot=eliot&only_with_tag=cppdic&r1=1.13.2.4&r2=1.13.2.5
http://cvs.savannah.gnu.org/viewcvs/eliot/game/ai_percent.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.5.2.2&r2=1.5.2.3
http://cvs.savannah.gnu.org/viewcvs/eliot/game/ai_percent.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.6.2.1&r2=1.6.2.2
http://cvs.savannah.gnu.org/viewcvs/eliot/game/ai_player.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.7.2.1&r2=1.7.2.2
http://cvs.savannah.gnu.org/viewcvs/eliot/game/board.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.12.2.3&r2=1.12.2.4
http://cvs.savannah.gnu.org/viewcvs/eliot/game/duplicate.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.16.2.3&r2=1.16.2.4
http://cvs.savannah.gnu.org/viewcvs/eliot/game/duplicate.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.12.2.2&r2=1.12.2.3
http://cvs.savannah.gnu.org/viewcvs/eliot/game/freegame.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.18.2.6&r2=1.18.2.7
http://cvs.savannah.gnu.org/viewcvs/eliot/game/freegame.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.11.2.1&r2=1.11.2.2
http://cvs.savannah.gnu.org/viewcvs/eliot/game/game.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.31.2.10&r2=1.31.2.11
http://cvs.savannah.gnu.org/viewcvs/eliot/game/game.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.29.2.7&r2=1.29.2.8
http://cvs.savannah.gnu.org/viewcvs/eliot/game/game_io.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.4.2.5&r2=1.4.2.6
http://cvs.savannah.gnu.org/viewcvs/eliot/game/history.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.10.2.3&r2=1.10.2.4
http://cvs.savannah.gnu.org/viewcvs/eliot/game/history.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.11.2.2&r2=1.11.2.3
http://cvs.savannah.gnu.org/viewcvs/eliot/game/player.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.14.2.3&r2=1.14.2.4
http://cvs.savannah.gnu.org/viewcvs/eliot/game/player.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.18.2.3&r2=1.18.2.4
http://cvs.savannah.gnu.org/viewcvs/eliot/game/results.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.10.2.3&r2=1.10.2.4
http://cvs.savannah.gnu.org/viewcvs/eliot/game/results.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.8.2.4&r2=1.8.2.5
http://cvs.savannah.gnu.org/viewcvs/eliot/game/settings.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.1.2.1&r2=1.1.2.2
http://cvs.savannah.gnu.org/viewcvs/eliot/game/settings.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.1.2.1&r2=1.1.2.2
http://cvs.savannah.gnu.org/viewcvs/eliot/game/training.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.17.2.4&r2=1.17.2.5
http://cvs.savannah.gnu.org/viewcvs/eliot/game/training.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.15.2.1&r2=1.15.2.2
http://cvs.savannah.gnu.org/viewcvs/eliot/game/turn.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.11.2.2&r2=1.11.2.3
http://cvs.savannah.gnu.org/viewcvs/eliot/game/turn.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.9.2.2&r2=1.9.2.3
http://cvs.savannah.gnu.org/viewcvs/eliot/game/move.cpp?cvsroot=eliot&only_with_tag=cppdic&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/eliot/game/move.h?cvsroot=eliot&only_with_tag=cppdic&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/eliot/po/eliot.pot?cvsroot=eliot&only_with_tag=cppdic&r1=1.6.6.6&r2=1.6.6.7
http://cvs.savannah.gnu.org/viewcvs/eliot/po/fr.po?cvsroot=eliot&only_with_tag=cppdic&r1=1.6.6.6&r2=1.6.6.7
http://cvs.savannah.gnu.org/viewcvs/eliot/test/freegame_change.input?cvsroot=eliot&only_with_tag=cppdic&r1=1.1&r2=1.1.6.1
http://cvs.savannah.gnu.org/viewcvs/eliot/test/freegame_change.ref?cvsroot=eliot&only_with_tag=cppdic&r1=1.2&r2=1.2.4.1
http://cvs.savannah.gnu.org/viewcvs/eliot/test/freegame_passing.ref?cvsroot=eliot&only_with_tag=cppdic&r1=1.3.2.1&r2=1.3.2.2
http://cvs.savannah.gnu.org/viewcvs/eliot/utils/eliottxt.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.16.2.10&r2=1.16.2.11
http://cvs.savannah.gnu.org/viewcvs/eliot/utils/ncurses.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.22.2.11&r2=1.22.2.12
http://cvs.savannah.gnu.org/viewcvs/eliot/wxwin/mainframe.cc?cvsroot=eliot&only_with_tag=cppdic&r1=1.21.2.9&r2=1.21.2.10
http://cvs.savannah.gnu.org/viewcvs/eliot/wxwin/printout.cc?cvsroot=eliot&only_with_tag=cppdic&r1=1.10.4.1&r2=1.10.4.2
http://cvs.savannah.gnu.org/viewcvs/eliot/wxwin/searchpanel.cc?cvsroot=eliot&only_with_tag=cppdic&r1=1.15.2.4&r2=1.15.2.5

Patches:
Index: game/Makefile.am
===================================================================
RCS file: /cvsroot/eliot/eliot/game/Makefile.am,v
retrieving revision 1.13.2.4
retrieving revision 1.13.2.5
diff -u -b -r1.13.2.4 -r1.13.2.5
--- game/Makefile.am    20 Dec 2007 08:47:07 -0000      1.13.2.4
+++ game/Makefile.am    23 Dec 2007 23:12:42 -0000      1.13.2.5
@@ -34,6 +34,7 @@
        game.cpp game.h                 \
        game_factory.cpp game_factory.h \
        game_io.cpp                     \
+       move.cpp move.h                 \
        player.cpp player.h             \
        pldrack.cpp pldrack.h           \
        rack.cpp rack.h                 \

Index: game/ai_percent.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/ai_percent.cpp,v
retrieving revision 1.5.2.2
retrieving revision 1.5.2.3
diff -u -b -r1.5.2.2 -r1.5.2.3
--- game/ai_percent.cpp 20 Dec 2007 08:47:07 -0000      1.5.2.2
+++ game/ai_percent.cpp 23 Dec 2007 23:12:42 -0000      1.5.2.3
@@ -21,6 +21,7 @@
 #include "rack.h"
 #include "pldrack.h"
 #include "round.h"
+#include "move.h"
 #include "results.h"
 #include "board.h"
 #include "ai_percent.h"
@@ -37,24 +38,27 @@
 }
 
 
-void AIPercent::compute(const Dictionary &iDic, Board &iBoard, int turn)
+void AIPercent::compute(const Dictionary &iDic, Board &iBoard, bool iFirstWord)
 {
     m_results.clear();
 
     Rack rack;
     getCurrentRack().getRack(rack);
-    m_results.search(iDic, iBoard, rack, turn);
+    m_results.search(iDic, iBoard, rack, iFirstWord);
 }
 
 
-bool AIPercent::changesLetters() const
-{
-    return (m_results.size() == 0);
-}
-
-
-const Round & AIPercent::getChosenRound() const
+Move AIPercent::getMove() const
 {
+    if (m_results.size() == 0)
+    {
+        // If there is no result, simply pass the turn
+        // XXX: it is forbidden in duplicate mode, but well, what else to do?
+        return Move(L"");
+    }
+    else
+    {
+        // If there are results, apply the algorithm
     double wantedScore = m_percent * m_results.get(0).getPoints();
     // Look for the first round giving at least 'wantedScore' points
     // Browse the results 10 by 10 (a dichotomy would be better, but this
@@ -72,13 +76,8 @@
     {
         --index;
     }
-    return m_results.get(index);
-}
-
-
-vector<Tile> AIPercent::getChangedLetters() const
-{
-    return vector<Tile>();
+        return Move(m_results.get(index));
+    }
 }
 
 /// Local Variables:

Index: game/ai_percent.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/ai_percent.h,v
retrieving revision 1.6.2.1
retrieving revision 1.6.2.2
diff -u -b -r1.6.2.1 -r1.6.2.2
--- game/ai_percent.h   14 Dec 2007 18:12:32 -0000      1.6.2.1
+++ game/ai_percent.h   23 Dec 2007 23:12:42 -0000      1.6.2.2
@@ -45,17 +45,15 @@
      * This method does the actual computation. It will be called before any
      * of the following methods, so it must prepare everything for them.
      */
-    virtual void compute(const Dictionary &iDic, Board &iBoard, int turn);
-    /// Return true when the AI wants to change letters instead of playing a 
word
-    virtual bool changesLetters() const;
-    /// Return the round played by the AI (if changesLetters() returns false)
-    virtual const Round & getChosenRound() const;
-    /// Get the letters to change (if changesLetters() returns true)
-    virtual vector<Tile> getChangedLetters() const;
+    virtual void compute(const Dictionary &iDic, Board &iBoard, bool 
iFirstWord);
+
+    /// Return the move played by the AI
+    virtual Move getMove() const;
 
 private:
     /// Percentage used for this player
     float m_percent;
+
     /// Container for all the found solutions
     Results m_results;
 };

Index: game/ai_player.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/ai_player.h,v
retrieving revision 1.7.2.1
retrieving revision 1.7.2.2
diff -u -b -r1.7.2.1 -r1.7.2.2
--- game/ai_player.h    15 Oct 2006 11:07:55 -0000      1.7.2.1
+++ game/ai_player.h    23 Dec 2007 23:12:42 -0000      1.7.2.2
@@ -69,22 +69,14 @@
      * This method does the actual computation. It will be called before any
      * of the following methods, so it must prepare everything for them.
      */
-    virtual void compute(const Dictionary &iDic, Board &iBoard, int turn) = 0;
-    /**
-     * Return true when the AI wants to change letters instead of playing a
-     * word.
-     * Should return false in duplicate mode, as it is not allowed to change
-     * letters.
-     */
-    virtual bool changesLetters() const = 0;
-    /// Return the round played by the AI (if changesLetters() returns false)
-    virtual const Round & getChosenRound() const = 0;
-    /// Get the letters to change (if changesLetters() returns true)
-    virtual vector<Tile> getChangedLetters() const = 0;
+    virtual void compute(const Dictionary &iDic, Board &iBoard, bool 
iFirstWord) = 0;
+
+    /// Return the move played by the AI
+    virtual Move getMove() const = 0;
 
 protected:
     /// This class is a pure interface, forbid any direct instanciation
-    AIPlayer(int iId): Player(iId) {}
+    AIPlayer(unsigned int iId): Player(iId) {}
 };
 
 #endif

Index: game/board.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/board.h,v
retrieving revision 1.12.2.3
retrieving revision 1.12.2.4
diff -u -b -r1.12.2.3 -r1.12.2.4
--- game/board.h        13 Dec 2007 12:11:06 -0000      1.12.2.3
+++ game/board.h        23 Dec 2007 23:12:42 -0000      1.12.2.4
@@ -21,11 +21,12 @@
 #ifndef _BOARD_H_
 #define _BOARD_H_
 
-#include "tile.h"
-#include "cross.h"
 #include <string>
 #include <vector>
 
+#include "tile.h"
+#include "cross.h"
+
 class Dictionary;
 class Rack;
 class Round;

Index: game/duplicate.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/duplicate.cpp,v
retrieving revision 1.16.2.3
retrieving revision 1.16.2.4
diff -u -b -r1.16.2.3 -r1.16.2.4
--- game/duplicate.cpp  20 Dec 2007 08:47:07 -0000      1.16.2.3
+++ game/duplicate.cpp  23 Dec 2007 23:12:42 -0000      1.16.2.4
@@ -22,6 +22,7 @@
 #include "tile.h"
 #include "rack.h"
 #include "round.h"
+#include "move.h"
 #include "pldrack.h"
 #include "results.h"
 #include "player.h"
@@ -49,43 +50,52 @@
 
 int Duplicate::play(const wstring &iCoord, const wstring &iWord)
 {
-    /* Perform all the validity checks, and fill a round */
+    // Perform all the validity checks, and try to fill a round
     Round round;
     int res = checkPlayedWord(iCoord, iWord, round);
-    if (res != 0)
+    if (res != 0 && Settings::Instance().getBool("duplicate-reject-invalid"))
     {
         return res;
     }
 
-    /* Everything is OK, we can play the word */
-    playRound(round, m_currPlayer);
+    // If we reach this point, either the move is valid and we can use the
+    // "round" variable, or it is invalid but played nevertheless
+    if (res == 0)
+    {
+        // Everything is OK, we can play the word
+        playMove(Move(round), m_currPlayer);
+    }
+    else
+    {
+        // Record the invalid move of the player
+        playMove(Move(iWord, iCoord), m_currPlayer);
+    }
 
-    /* Next turn */
-    // XXX: Should it be done by the interface instead?
-    endTurn();
+    // Little hack to handle duplicate games with only AI players.
+    // This will have no effect when there is at least one human player
+    tryEndTurn();
 
     return 0;
 }
 
 
-void Duplicate::duplicateAI(unsigned int p)
+void Duplicate::playAI(unsigned int p)
 {
     ASSERT(p < getNPlayers(), "Wrong player number");
-    ASSERT(!m_players[p]->isHuman(), "AI requested for a human player");
 
-    AIPlayer *player = static_cast<AIPlayer*>(m_players[p]);
-    player->compute(m_dic, m_board, m_history.getSize());
+    AIPlayer *player = dynamic_cast<AIPlayer*>(m_players[p]);
+    ASSERT(player != NULL, "AI requested for a human player");
 
-    if (player->changesLetters())
+    player->compute(m_dic, m_board, m_history.beforeFirstRound());
+    const Move move = player->getMove();
+    if (move.getType() == Move::CHANGE_LETTERS ||
+        move.getType() == Move::PASS)
     {
-        // The AI player has nothing to play. This should not happen in
-        // duplicate mode, otherwise the implementation of the AI is buggy...
-        ASSERT(false, "AI player has nothing to play!");
-    }
-    else
-    {
-        playRound(player->getChosenRound(), p);
+        // The AI player must be buggy...
+        ASSERT(false, "AI tried to cheat!");
     }
+
+    playMove(move, p);
 }
 
 
@@ -96,119 +106,102 @@
     // Arbitrary player, since they should all have the same rack
     m_currPlayer = 0;
 
-    /* Complete the rack for the player that just played */
+    // Complete the rack for the player that just played
     int res = setRackRandom(m_currPlayer, true, RACK_NEW);
-    /* End of the game? */
+    // End of the game?
     if (res == 1)
     {
-        end();
+        endGame();
         return 1;
     }
 
     const PlayedRack& pld = m_players[m_currPlayer]->getCurrentRack();
-    /* All the players have the same rack */
+    // All the players have the same rack
     for (unsigned int i = 0; i < getNPlayers(); i++)
     {
         if (i != m_currPlayer)
         {
             m_players[i]->setCurrentRack(pld);
         }
-        /* Nobody has played yet in this round */
+        // Nobody has played yet in this round
         m_hasPlayed[i] = false;
     }
 
-    /* Next turn */
-    // XXX: Should it be done by the interface instead?
-    endTurn();
+    // Little hack to handle duplicate games with only AI players.
+    // This will have no effect when there is at least one human player
+    tryEndTurn();
 
     return 0;
 }
 
 
-/*
- * This function does not terminate the turn itself, but performs some
- * checks to know whether or not it should be terminated (with a call to
- * endTurnForReal()).
- *
- * For the turn to be terminated, all the players must have played.
- * Since the AI players play after the human players, we check whether
- * one of the human players has not played yet:
- *   - if so, we have nothing to do (we are waiting for him)
- *   - if not (all human players have played), the AI players can play,
- *     and we finish the turn.
- */
-int Duplicate::endTurn()
+void Duplicate::tryEndTurn()
 {
-    unsigned int i;
-    for (i = 0; i < getNPlayers(); i++)
+    for (unsigned int i = 0; i < getNPlayers(); i++)
     {
         if (m_players[i]->isHuman() && !m_hasPlayed[i])
         {
-            /* A human player has not played... */
+            // A human player has not played...
             m_currPlayer = i;
-            // XXX: check return code meaning
-            return 1;
+            // So we don't finish the turn
+            return;
         }
     }
 
-    /* If all the human players have played */
-    if (i == getNPlayers())
-    {
-        /* Make AI players play their turn */
-        for (i = 0; i < getNPlayers(); i++)
+    // Now that all the human players have played,
+    // make AI players play their turn
+    for (unsigned int i = 0; i < getNPlayers(); i++)
         {
             if (!m_players[i]->isHuman())
             {
-                duplicateAI(i);
-            }
+            playAI(i);
         }
-
-        /* Next turn */
-        endTurnForReal();
-        start();
     }
 
-    // XXX: check return code meaning
-    return 0;
+    // Next turn
+    endTurn();
 }
 
 
-void Duplicate::playRound(const Round &iRound, unsigned int p)
+void Duplicate::playMove(const Move &iMove, unsigned int p)
 {
     ASSERT(p < getNPlayers(), "Wrong player number");
 
     // Update the rack and the score of the playing player
-    m_players[p]->endTurn(iRound, m_history.getSize());
+    m_players[p]->endTurn(iMove, m_history.getSize());
 
     m_hasPlayed[p] = true;
 }
 
 
-void Duplicate::endTurnForReal()
+void Duplicate::endTurn()
 {
     // Find the player with the best score
     unsigned int imax = 0;
     for (unsigned int i = 1; i < getNPlayers(); i++)
     {
-        if (m_players[i]->getLastRound().getPoints() >
-            m_players[imax]->getLastRound().getPoints())
+        if (m_players[i]->getLastMove().getScore() >
+            m_players[imax]->getLastMove().getScore())
         {
             imax = i;
         }
     }
 
+    // TODO: do something if nobody played a valid round!
+
     // Handle solo bonus
-    // First check whetherf there are enough players in the game for the
+    // First check whether there are enough players in the game for the
     // bonus to apply
     int minNbPlayers = Settings::Instance().getInt("duplicate-solo-players");
-    if (getNPlayers() >= (unsigned int)minNbPlayers)
+    if (getNPlayers() >= (unsigned int)minNbPlayers &&
+        m_players[imax]->getLastMove().getType() == Move::VALID_ROUND)
     {
+        int maxScore = m_players[imax]->getLastMove().getScore();
         // Find whether other players than imax have the same score
         bool otherWithSameScore = false;
         for (unsigned int i = imax + 1; i < getNPlayers(); i++)
         {
-            if (m_players[i]->getLastRound().getPoints() >=
-                m_players[imax]->getLastRound().getPoints())
+            if (m_players[i]->getLastMove().getScore() >= maxScore)
             {
                 otherWithSameScore = true;
                 break;
@@ -225,7 +218,7 @@
     }
 
     // Play the best word on the board
-    helperPlayRound(imax, m_players[imax]->getLastRound());
+    helperPlayMove(imax, m_players[imax]->getLastMove());
 
     // Leave the same reliquate to all players
     // This is required by the start() method which will be called to
@@ -238,10 +231,13 @@
             m_players[i]->setCurrentRack(pld);
         }
     }
+
+    // Start next turn...
+    start();
 }
 
 
-void Duplicate::end()
+void Duplicate::endGame()
 {
     m_finished = true;
 }
@@ -251,7 +247,7 @@
 {
     ASSERT(p < getNPlayers(), "Wrong player number");
 
-    /* Forbid switching to an AI player */
+    // Forbid switching to an AI player
     if (!m_players[p]->isHuman())
         return 1;
 

Index: game/duplicate.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/duplicate.h,v
retrieving revision 1.12.2.2
retrieving revision 1.12.2.3
diff -u -b -r1.12.2.2 -r1.12.2.3
--- game/duplicate.h    20 Dec 2007 08:47:07 -0000      1.12.2.2
+++ game/duplicate.h    23 Dec 2007 23:12:42 -0000      1.12.2.3
@@ -34,7 +34,7 @@
  *     and rack are updated. He cannot change his word afterwards.
  *   - if there is still a human player who has not played for the current
  *     turn, we wait for him
- *   - if all the human players have played, it's the turn to the AI players
+ *   - if all the human players have played, it's the turn of the AI players
  *     (currently handled in a loop, but we could imagine that they are running
  *     in their own thread).
  *   - once all the players have played, we can really end the turn:
@@ -60,15 +60,28 @@
     /**
      * In Duplicate mode, the start() method starts a new turn, and is
      * automatically called when the previous turn is finished.
-     * It has an important pre-requisite: all the players must have the
-     * same rack when calling this function
+     *
+     * Pre-requisite: all the players must have the same rack when this
+     * method is called
      */
     virtual int start();
-    virtual int setRackRandom(unsigned int, bool, set_rack_mode);
+
+    /**
+     * See description of Game::play() for the possible return values.
+     * Note that if the "duplicate-reject-invalid" setting is set to false
+     * the method always returns 0 (the player will have 0 for this turn)
+     */
     virtual int play(const wstring &iCoord, const wstring &iWord);
-    virtual int endTurn();
 
-    int setPlayer(unsigned int);
+    /**
+     * Set the current player, given its ID.
+     * The given player ID must correspond to a human player, which did not
+     * play yet for this turn.
+     * Possible return values:
+     *  0: everything went fine
+     *  1: the player is not human
+     */
+    int setPlayer(unsigned int p);
 
     /// Switch to the previous human player who has not played yet
     void prevHumanPlayer();
@@ -80,20 +93,38 @@
     // Private constructor to force using the GameFactory class
     Duplicate(const Dictionary &iDic);
 
-    void playRound(const Round &iRound, unsigned int p);
+    void playMove(const Move &iMove, unsigned int p);
+    int setRackRandom(unsigned int, bool, set_rack_mode);
+
+    /// Make the AI player whose ID is p play its turn
+    void playAI(unsigned int p);
+
+    /**
+     * This function does not terminate the turn itself, but performs some
+     * checks to know whether or not it should be terminated (with a call to
+     * endTurn()).
+     *
+     * For the turn to be terminated, all the players must have played.
+     * Since the AI players play after the human players, we check whether
+     * one of the human players has not played yet:
+     *   - if so, we have nothing to do (we are waiting for him/her)
+     *   - if not (all human players have played), the AI players can play,
+     *     and we finish the turn.
+     */
+    void tryEndTurn();
 
     /**
      * This function really changes the turn, i.e. the best word is played,
      * the game history is updated, a "solo" bonus is given if needed, and
-     * all racks are made equal to the one of the player which played the best
-     * move.
-     * We suppose here that all the players have finished to play for this turn
-     * (this should have been checked by endturn())
+     * all racks are made equal to the one of the player who played the
+     * best move.
+     * We suppose here that all the players have finished to play for this
+     * turn (this should have been checked by tryEndturn())
      */
-    void endTurnForReal();
+    void endTurn();
 
-    void end();
-    void duplicateAI(unsigned int p);
+    /// Finish the game
+    void endGame();
 
     // m_hasPlayed[p] is true iff player p has played for this turn
     map<int, bool> m_hasPlayed;

Index: game/freegame.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/freegame.cpp,v
retrieving revision 1.18.2.6
retrieving revision 1.18.2.7
diff -u -b -r1.18.2.6 -r1.18.2.7
--- game/freegame.cpp   20 Dec 2007 08:47:08 -0000      1.18.2.6
+++ game/freegame.cpp   23 Dec 2007 23:12:42 -0000      1.18.2.7
@@ -19,25 +19,24 @@
 
 #include <iomanip>
 #include <wctype.h>
+
+#include "freegame.h"
 #include "dic.h"
 #include "tile.h"
 #include "rack.h"
 #include "round.h"
+#include "move.h"
 #include "pldrack.h"
 #include "results.h"
 #include "player.h"
 #include "ai_player.h"
-#include "freegame.h"
+#include "settings.h"
 
 #include "debug.h"
 
 
-FreeGame::FreeGame(const Dictionary &iDic): Game(iDic)
-{
-}
-
-
-FreeGame::~FreeGame()
+FreeGame::FreeGame(const Dictionary &iDic)
+    : Game(iDic)
 {
 }
 
@@ -55,51 +54,64 @@
 
 int FreeGame::play(const wstring &iCoord, const wstring &iWord)
 {
-    /* Perform all the validity checks, and fill a round */
+    // Perform all the validity checks, and try to fill a round
     Round round;
-
     int res = checkPlayedWord(iCoord, iWord, round);
-    if (res != 0)
+    if (res != 0 && Settings::Instance().getBool("freegame-reject-invalid"))
     {
         return res;
     }
 
-    /* Update the rack and the score of the current player */
-    m_players[m_currPlayer]->endTurn(round, m_history.getSize());
+    // If we reach this point, either the move is valid and we can use the
+    // "round" variable, or it is invalid but played nevertheless
+    if (res == 0)
+    {
+        Move move(round);
+
+        // Update the rack and the score of the current player
+        m_players[m_currPlayer]->endTurn(move, m_history.getSize());
+
+        // Everything is OK, we can play the word
+        helperPlayMove(m_currPlayer, move);
+    }
+    else
+    {
+        Move move(iWord, iCoord);
+
+        // Record the invalid move of the player
+        m_players[m_currPlayer]->endTurn(move, m_history.getSize());
 
-    /* Everything is OK, we can play the word */
-    helperPlayRound(m_currPlayer, round);
+        // Update the game
+        helperPlayMove(m_currPlayer, move);
+    }
 
-    /* Next turn */
-    // XXX: Should it be done by the interface instead?
+    // Next turn
     endTurn();
 
     return 0;
 }
 
 
-void FreeGame::freegameAI(unsigned int p)
+void FreeGame::playAI(unsigned int p)
 {
     ASSERT(p < getNPlayers(), "Wrong player number");
     ASSERT(!m_players[p]->isHuman(), "AI requested for a human player");
 
     AIPlayer *player = static_cast<AIPlayer*>(m_players[p]);
 
-    player->compute(m_dic, m_board, m_history.getSize());
-    if (player->changesLetters())
+    player->compute(m_dic, m_board, m_history.beforeFirstRound());
+    const Move move = player->getMove();
+    if (move.getType() == Move::CHANGE_LETTERS ||
+        move.getType() == Move::PASS)
     {
-        helperPass(player->getChangedLetters(), p);
-        endTurn();
+        ASSERT(checkPass(move.getChangedLetters(), p) == 0, "AI tried to 
cheat!");
     }
-    else
-    {
-        const Round &round = player->getChosenRound();
-        /* Update the rack and the score of the current player */
-        player->endTurn(round, m_history.getSize());
 
-        helperPlayRound(p, round);
+    // Update the rack and the score of the current player
+    player->endTurn(move, m_history.getSize());
+
+    helperPlayMove(p, move);
         endTurn();
-    }
 }
 
 
@@ -107,19 +119,18 @@
 {
     ASSERT(getNPlayers(), "Cannot start a game without any player");
 
-    /* Set the initial racks of the players */
+    // Set the initial racks of the players
     for (unsigned int i = 0; i < getNPlayers(); i++)
     {
         setRackRandom(i, false, RACK_NEW);
     }
 
-    // XXX
     m_currPlayer = 0;
 
-    /* If the first player is an AI, make it play now */
-    if (!m_players[0]->isHuman())
+    // If the first player is an AI, make it play now
+    if (!m_players[m_currPlayer]->isHuman())
     {
-        freegameAI(0);
+        playAI(m_currPlayer);
     }
 
     return 0;
@@ -128,21 +139,21 @@
 
 int FreeGame::endTurn()
 {
-    /* Complete the rack for the player that just played */
+    // Complete the rack for the player that just played
     if (setRackRandom(m_currPlayer, false, RACK_NEW) == 1)
     {
-        /* End of the game */
-        end();
+        // End of the game
+        endGame();
         return 1;
     }
 
-    /* Next player */
+    // Next player
     nextPlayer();
 
-    /* If this player is an AI, make it play now */
+    // If this player is an AI, make it play now
     if (!m_players[m_currPlayer]->isHuman())
     {
-        freegameAI(m_currPlayer);
+        playAI(m_currPlayer);
     }
 
     return 0;
@@ -150,7 +161,7 @@
 
 
 // Adjust the scores of the players with the points of the remaining tiles
-void FreeGame::end()
+void FreeGame::endGame()
 {
     vector<Tile> tiles;
 
@@ -163,7 +174,7 @@
     // We currently handle case 1, and cannot handle case 3 until timers are
     // implemented.
     // For case 2, we need both to detect a blocked situation (not easy...) and
-    // to handle it in the end() method (very easy).
+    // to handle it in the endGame() method (very easy).
 
     /* Add the points of the remaining tiles to the score of the current
      * player (i.e. the first player with an empty rack), and remove them
@@ -182,45 +193,23 @@
         }
     }
 
-    /* Lock game */
+    // Lock game
     m_finished = true;
 }
 
 
-int FreeGame::pass(const wstring &iToChange, unsigned int p)
+int FreeGame::checkPass(const wstring &iToChange, unsigned int p) const
 {
+    ASSERT(p < getNPlayers(), "Wrong player number");
+
+    // Check that the game is not finished
     if (m_finished)
         return 3;
 
+    // Check that the letters are valid for the current dictionary
     if (!m_dic.validateLetters(iToChange))
         return 4;
 
-    // According to the rules in the ODS, it is allowed to pass its turn (no
-    // need to change letters for that).
-    // TODO: However, if all the players pass their turn, the first one has to
-    // play, or change at least one letter. To implement this behaviour, we
-    // must also take care of blocked positions, where no one _can_ play (see
-    // also comment in the end() method).
-
-    // Convert the string into tiles
-    vector<Tile> tilesVect;
-    for (unsigned int i = 0; i < iToChange.size(); i++)
-    {
-        Tile tile(towupper(iToChange[i]));
-        tilesVect.push_back(tile);
-    }
-
-    int res = helperPass(tilesVect, p);
-    if (res == 0)
-        endTurn();
-    return res;
-}
-
-
-int FreeGame::helperPass(const vector<Tile> &iToChange, unsigned int p)
-{
-    ASSERT(p < getNPlayers(), "Wrong player number");
-
     // It is forbidden to change letters when the bag does not contain at
     // least 7 letters (this is explicitly stated in the ODS). But it is
     // still allowed to pass
@@ -231,28 +220,46 @@
         return 1;
     }
 
+    // Check that the letters are all present in the player's rack
     Player *player = m_players[p];
     PlayedRack pld = player->getCurrentRack();
     Rack rack;
     pld.getRack(rack);
-
     for (unsigned int i = 0; i < iToChange.size(); i++)
     {
-        /* Remove the letter from the rack */
-        if (!rack.in(iToChange[i]))
+        // Remove the letter from the rack
+        if (!rack.in(Tile(iToChange[i])))
         {
             return 2;
         }
-        rack.remove(iToChange[i]);
+        rack.remove(Tile(iToChange[i]));
     }
 
-    pld.reset();
-    pld.setOld(rack);
+    // According to the rules in the ODS, it is allowed to pass its turn (no
+    // need to change letters for that).
+    // TODO: However, if all the players pass their turn, the first one has to
+    // play, or change at least one letter. To implement this behaviour, we
+    // must also take care of blocked positions, where no one _can_ play (see
+    // also comment in the endGame() method).
 
-    player->setCurrentRack(pld);
+    return 0;
+}
 
-    // FIXME: the letters to change should not be in the bag while generating
-    // the new rack!
+
+int FreeGame::pass(const wstring &iToChange)
+{
+    int res = checkPass(iToChange, m_currPlayer);
+    if (res != 0)
+        return res;
+
+    Move move(iToChange);
+    // End the player's turn
+    m_players[m_currPlayer]->endTurn(move, m_history.getSize());
+    // Update the game
+    helperPlayMove(m_currPlayer, move);
+
+    // Next game turn
+    endTurn();
 
     return 0;
 }

Index: game/freegame.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/freegame.h,v
retrieving revision 1.11.2.1
retrieving revision 1.11.2.2
diff -u -b -r1.11.2.1 -r1.11.2.2
--- game/freegame.h     17 Dec 2007 11:27:41 -0000      1.11.2.1
+++ game/freegame.h     23 Dec 2007 23:12:43 -0000      1.11.2.2
@@ -48,20 +48,56 @@
     /*************************
      * Game handling
      *************************/
+    /**
+     * Start the game.
+     * Possible return values:
+     *  0: everything went fine
+     */
     virtual int start();
-    virtual int setRackRandom(unsigned int, bool, set_rack_mode);
+
+    /**
+     * See description of Game::play() for the possible return values.
+     * Note that if the "freegame-reject-invalid" setting is set to false
+     * the method always returns 0 (the player will have 0 for this turn)
+     */
     virtual int play(const wstring &iCoord, const wstring &iWord);
-    virtual int endTurn();
-    int pass(const wstring &iToChange, unsigned int p);
+
+    /**
+     * Pass the turn, changing the letters listed in iToChange.
+     * If you simply want to pass the turn without changing any letter,
+     * provide an empty string.
+     *
+     * Possible return values:
+     *  0: everything went fine
+     *  1: changing letters is not allowed if there are less than 7 tiles
+     *     left in the bag
+     *  2: the rack of the current player does not contain all the
+     *     listed letters
+     *  3: the game is already finished
+     *  4: some letters are invalid for the current dictionary
+     */
+    int pass(const wstring &iToChange);
 
 private:
-    // Private constructor and destructor to force using the GameFactory class
+    // Private constructor to force using the GameFactory class
     FreeGame(const Dictionary &iDic);
-    virtual ~FreeGame();
 
-    void freegameAI(unsigned int p);
-    void end();
-    int helperPass(const vector<Tile> &iToChange, unsigned int p);
+    int setRackRandom(unsigned int, bool, set_rack_mode);
+
+    /// Make the AI player whose ID is p play its turn
+    void playAI(unsigned int p);
+
+    /// Finish the current turn
+    int endTurn();
+
+    /// Finish the game
+    void endGame();
+
+    /**
+     * Check whether it is legal to change the letters of iToChange.
+     * The return codes are the same as the ones on the pass() method
+     */
+    int checkPass(const wstring &iToChange, unsigned int p) const;
 };
 
 #endif /* _FREEGAME_H_ */

Index: game/game.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/game.cpp,v
retrieving revision 1.31.2.10
retrieving revision 1.31.2.11
diff -u -b -r1.31.2.10 -r1.31.2.11
--- game/game.cpp       20 Dec 2007 08:47:08 -0000      1.31.2.10
+++ game/game.cpp       23 Dec 2007 23:12:43 -0000      1.31.2.11
@@ -63,22 +63,28 @@
 }
 
 
-void Game::helperPlayRound(unsigned int iPlayerId, const Round &iRound)
+void Game::helperPlayMove(unsigned int iPlayerId, const Move &iMove)
 {
-    /*
-     * We remove tiles from the bag only when they are played
-     * on the board. When going back in the game, we must only
-     * replace played tiles.
-     * We test a rack when it is set but tiles are left in the bag.
-     */
-
     // History of the game
     m_history.setCurrentRack(getPlayer(iPlayerId).getLastRack());
-    m_history.playRound(iPlayerId, m_history.getSize(), iRound);
+    m_history.playMove(iPlayerId, m_history.getSize(), iMove);
 
-    debug("    helper: %d points\n",iRound.getPoints());
-    m_points += iRound.getPoints();
+    // Points
+    debug("    helper: %d points\n", iMove.getScore());
+    m_points += iMove.getScore();
 
+    // For moves corresponding to a valid round, we have much more
+    // work to do...
+    if (iMove.getType() == Move::VALID_ROUND)
+    {
+        helperPlayRound(iPlayerId, iMove.getRound());
+    }
+}
+
+
+
+void Game::helperPlayRound(unsigned int iPlayerId, const Round &iRound)
+{
     // Before updating the bag and the board, if we are playing a "joker game",
     // we replace in the round the joker by the letter it represents
     // This is currently done by a succession of ugly hacks :-/
@@ -133,7 +139,11 @@
         }
     }
 
-    // Update the bag and the board
+    // Update the bag
+    // We remove tiles from the bag only when they are played
+    // on the board. When going back in the game, we must only
+    // replace played tiles.
+    // We test a rack when it is set but tiles are left in the bag.
     for (unsigned int i = 0; i < iRound.getWordLen(); i++)
     {
         if (iRound.isPlayedFromRack(i))
@@ -148,6 +158,8 @@
             }
         }
     }
+
+    // Update the board
     m_board.addRound(m_dic, iRound);
 }
 
@@ -162,7 +174,12 @@
     for (unsigned int i = 0; i < n; i++)
     {
         prevPlayer();
-        const Round &lastround = m_history.getPreviousTurn().getRound();
+        const Move &lastMove = m_history.getPreviousTurn().getMove();
+        // Nothing to cancel if the move was not a valid round
+        if (lastMove.getType() != Move::VALID_ROUND)
+            continue;
+
+        const Round &lastround = lastMove.getRound();
         debug("Game::back last round %s\n",
               convertToMb(lastround.toString()).c_str());
         /* Remove the word from the board, and put its letters back
@@ -445,6 +462,7 @@
 
 void Game::addAIPlayer()
 {
+    // TODO: allow other percentages, and even other types of AI
     m_players.push_back(new AIPercent(getNPlayers(), 1));
 }
 
@@ -477,13 +495,9 @@
     ASSERT(getNPlayers() != 0, "Expected at least one player");
 
     if (!m_dic.validateLetters(iWord))
-        return 12;
-
-    int res;
-    vector<Tile> tiles;
-    Tile t;
+        return 1;
 
-    /* Init the round with the given coordinates */
+    // Init the round with the given coordinates
     oRound.init();
     oRound.accessCoord().setFromString(iCoord);
     if (!oRound.getCoord().isValid())
@@ -492,16 +506,17 @@
         return 2;
     }
 
-    /* Check the existence of the word */
+    // Check the existence of the word
     if (!m_dic.searchWord(iWord))
     {
         return 3;
     }
 
-    /* Set the word */
+    // Set the word
     // TODO: make this a Round_ function (Round_setwordfromchar for example)
     // or a Tiles_ function (to transform a char* into a vector<Tile>)
     // Adding a getter on the word could help too...
+    vector<Tile> tiles;
     for (unsigned int i = 0; i < iWord.size(); i++)
     {
         tiles.push_back(Tile(iWord[i]));
@@ -513,19 +528,20 @@
             oRound.setJoker(i);
     }
 
-    /* Check the word position, compute its points,
-     * and specify the origin of each letter (board or rack) */
-    res = m_board.checkRound(oRound, m_history.getSize() == 0);
+    // Check the word position, compute its points,
+    // and specify the origin of each letter (board or rack)
+    int res = m_board.checkRound(oRound, m_history.getSize() == 0);
     if (res != 0)
         return res + 4;
 
-    /* Check that the word can be formed with the tiles in the rack:
-     * we first create a copy of the rack, then we remove the tiles
-     * one by one */
+    // Check that the word can be formed with the tiles in the rack:
+    // we first create a copy of the rack, then we remove the tiles
+    // one by one
     Rack rack;
     Player *player = m_players[m_currPlayer];
     player->getCurrentRack().getRack(rack);
 
+    Tile t;
     for (unsigned int i = 0; i < oRound.getWordLen(); i++)
     {
         if (oRound.isPlayedFromRack(i))

Index: game/game.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/game.h,v
retrieving revision 1.29.2.7
retrieving revision 1.29.2.8
diff -u -b -r1.29.2.7 -r1.29.2.8
--- game/game.h 20 Dec 2007 08:47:08 -0000      1.29.2.7
+++ game/game.h 23 Dec 2007 23:12:43 -0000      1.29.2.8
@@ -119,25 +119,32 @@
      ***************/
 
     /**
-     * Start the game, and make the AI players play.
-     * If the game only has AI players, it will play completely.
+     * Start the game.
+     * AI players are handled automatically, so if the game only has AI
+     * players, it will play until the end.
      */
     virtual int start() = 0;
 
     /**
      * Method used by human players to play the word iWord at coordinates
      * iCoord, and end the turn (if possible)
+     * Possible return values:
+     *  0: correct word, the Round can be used by the caller
+     *  1: one letter of the word is invalid in the current dictionary
+     *  2: invalid coordinates (unreadable or out of the board)
+     *  3: word not present in the dictionary
+     *  4: not enough letters in the rack to play the word
+     *  5: word is part of a longer one
+     *  6: word overwriting an existing letter
+     *  7: invalid crosscheck, or word going out of the board
+     *  8: word already present on the board (no new letter from the rack)
+     *  9: isolated word (not connected to the rest)
+     * 10: first word not horizontal
+     * 11: first word not covering the H8 square
      */
     virtual int play(const wstring &iCoord, const wstring &iWord) = 0;
 
     /**
-     * End the current turn. This method is automatically called by start()
-     * and by play(), so should not be called directly
-     * FIXME: Do not make it public then!
-     */
-    virtual int endTurn() = 0;
-
-    /**
      * Go back to turn iTurn.
      * We must have: iTurn < getHistory().getSize()
      * Possible return values:
@@ -218,8 +225,8 @@
      * Helper functions
      *********************************************************/
 
-    /** Play a round on the board */
-    void helperPlayRound(unsigned int iPlayerId, const Round &iRound);
+    /** Play a Move for the given player, updating game history */
+    void helperPlayMove(unsigned int iPlayerId, const Move &iMove);
 
     /**
      * Set the rack randomly for the player p
@@ -271,20 +278,7 @@
      * This function checks whether it is legal to play the given word at the
      * given coordinates. If so, the function fills a Round object, also given
      * as a parameter.
-     * Possible return values:
-     *  0: correct word, the Round can be used by the caller
-     *  1: no dictionary set
-     *  2: invalid coordinates (unreadable or out of the board)
-     *  3: word not present in the dictionary
-     *  4: not enough letters in the rack to play the word
-     *  5: word is part of a longer one
-     *  6: word overwriting an existing letter
-     *  7: invalid crosscheck, or word going out of the board
-     *  8: word already present on the board (no new letter from the rack)
-     *  9: isolated word (not connected to the rest)
-     * 10: first word not horizontal
-     * 11: first word not covering the H8 square
-     * 12: one letter of the word is invalid in the current dictionary
+     * Possible return values: same as the play() method
      */
     int  checkPlayedWord(const wstring &iCoord,
                          const wstring &iWord, Round &oRound);
@@ -313,6 +307,12 @@
 
 private:
 
+    /**
+     * Play a round on the board.
+     * This should only be called by helperPlayMove().
+     */
+    void helperPlayRound(unsigned int iPlayerId, const Round &iRound);
+
 };
 
 #endif /* _GAME_H_ */

Index: game/game_io.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/game_io.cpp,v
retrieving revision 1.4.2.5
retrieving revision 1.4.2.6
diff -u -b -r1.4.2.5 -r1.4.2.6
--- game/game_io.cpp    20 Dec 2007 08:47:08 -0000      1.4.2.5
+++ game/game_io.cpp    23 Dec 2007 23:12:43 -0000      1.4.2.6
@@ -500,15 +500,17 @@
     {
         const Turn& turn = m_history.getTurn(i);
         wstring rack = turn.getPlayedRack().toString(PlayedRack::RACK_EXTRA);
-        wstring word = turn.getRound().getWord();
-        string coord = 
convertToMb(turn.getRound().getCoord().toString(Coord::COORD_MODE_LONG));
+        // FIXME: this will not work if the move does not correspond to a 
played round!
+        const Round &round = turn.getMove().getRound();
+        wstring word = round.getWord();
+        string coord = 
convertToMb(round.getCoord().toString(Coord::COORD_MODE_LONG));
 
         // rack [space] word [space] bonus points coord
         sprintf(line,"%s%s%c%4d %s",
                 padAndConvert(rack, 12, false).c_str(),
                 padAndConvert(word, 16, false).c_str(),
-                turn.getRound().getBonus() ? '*' : ' ',
-                turn.getRound().getPoints(),
+                round.getBonus() ? '*' : ' ',
+                round.getPoints(),
                 coord.c_str()
                );
 
@@ -550,16 +552,65 @@
     {
         const Turn& turn = m_history.getTurn(i);
         wstring rack = turn.getPlayedRack().toString(PlayedRack::RACK_EXTRA);
-        wstring word = turn.getRound().getWord();
-        string coord = convertToMb(turn.getRound().getCoord().toString());
+        const Move &move = turn.getMove();
+        switch (move.getType())
+        {
+            case Move::VALID_ROUND:
+            {
+                const Round &round = move.getRound();
+                wstring word = round.getWord();
+                string coord = convertToMb(round.getCoord().toString());
         sprintf(line, "%2d | %s | %s | %3s | %3d | %1d | %c",
                 i + 1,
                 padAndConvert(rack, 8).c_str(),             /* pldrack     */
                 padAndConvert(word, 15, false).c_str(),     /* word        */
                 coord.c_str(),                              /* coord       */
-                turn.getRound().getPoints(),
+                        move.getScore(),
                 turn.getPlayer(),
-                turn.getRound().getBonus() ? '*' : ' ');
+                        round.getBonus() ? '*' : ' ');
+                break;
+            }
+            case Move::INVALID_WORD:
+            {
+                wstring word = move.getBadWord();
+                string coord = convertToMb(move.getBadCoord());
+                sprintf(line, "%2d | %s | %s | %3s | %3d | %1d |",
+                        i + 1,
+                        padAndConvert(rack, 8).c_str(),             /* pldrack 
    */
+                        padAndConvert(word, 15, false).c_str(),     /* word    
    */
+                        coord.c_str(),                              /* coord   
    */
+                        move.getScore(),
+                        turn.getPlayer());
+                break;
+            }
+            case Move::PASS:
+            {
+                string action = "(PASS)";
+                string coord = " - ";
+                sprintf(line, "%2d | %s | %s | %3s | %3d | %1d |",
+                        i + 1,
+                        padAndConvert(rack, 8).c_str(),             /* pldrack 
    */
+                        truncOrPad(action, 15, ' ').c_str(),        /* word    
    */
+                        coord.c_str(),                              /* coord   
    */
+                        move.getScore(),
+                        turn.getPlayer());
+                break;
+            }
+            case Move::CHANGE_LETTERS:
+            {
+                wstring action = L"(-" + move.getChangedLetters() + L")";
+                string coord = " - ";
+                sprintf(line, "%2d | %s | %s | %3s | %3d | %1d |",
+                        i + 1,
+                        padAndConvert(rack, 8).c_str(),             /* pldrack 
    */
+                        padAndConvert(action, 15, false).c_str(),   /* word    
    */
+                        coord.c_str(),                              /* coord   
    */
+                        move.getScore(),
+                        turn.getPlayer());
+                break;
+            }
+
+        }
 
         out << decal << line << endl;
     }

Index: game/history.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/history.cpp,v
retrieving revision 1.10.2.3
retrieving revision 1.10.2.4
diff -u -b -r1.10.2.3 -r1.10.2.4
--- game/history.cpp    17 Dec 2007 11:27:41 -0000      1.10.2.3
+++ game/history.cpp    23 Dec 2007 23:12:43 -0000      1.10.2.4
@@ -27,7 +27,7 @@
 #include <string>
 #include "rack.h"
 #include "pldrack.h"
-#include "round.h"
+#include "move.h"
 #include "turn.h"
 #include "history.h"
 #include "encoding.h"
@@ -90,20 +90,34 @@
 }
 
 
-void History::playRound(unsigned int player, unsigned int turn, const Round& 
round)
+bool History::beforeFirstRound() const
+{
+    for (unsigned int i = 0; i < m_history.size() - 1; i++)
+    {
+        if (m_history[i]->getMove().getType() == Move::VALID_ROUND)
+            return false;
+    }
+    return true;
+}
+
+
+void History::playMove(unsigned int iPlayer, unsigned int iTurn, const Move 
&iMove)
 {
     Turn * current_turn = m_history.back();
 
-    /* set the number and the round */
-    current_turn->setNum(turn);
-    current_turn->setPlayer(player);
-    current_turn->setRound(round);
+    // Set the number and the round
+    current_turn->setNum(iTurn);
+    current_turn->setPlayer(iPlayer);
+    current_turn->setMove(iMove);
 
-    /* get what was the rack for the current turn */
+    // Get what was the rack for the current turn
     Rack rack;
     current_turn->getPlayedRack().getRack(rack);
 
-    /* remove the played tiles from the rack */
+    if (iMove.getType() == Move::VALID_ROUND)
+    {
+        // Remove the played tiles from the rack
+        const Round &round = iMove.getRound();
     for (unsigned int i = 0; i < round.getWordLen(); i++)
     {
         if (round.isPlayedFromRack(i))
@@ -114,8 +128,18 @@
                 rack.remove(round.getTile(i));
         }
     }
+    }
+    else if (iMove.getType() == Move::CHANGE_LETTERS)
+    {
+        // Remove the changed tiles from the rack
+        const wstring & changed = iMove.getChangedLetters();
+        for (unsigned int i = 0; i < changed.size(); ++i)
+        {
+            rack.remove(Tile(changed[i]));
+        }
+    }
 
-    /* create a new turn */
+    // Create a new turn
     Turn * next_turn = new Turn();
     PlayedRack pldrack;
     pldrack.setOld(rack);
@@ -140,7 +164,7 @@
     Turn *t = m_history.back();
     t->setNum(0);
     t->setPlayer(0);
-    t->setRound(Round());
+    //t->setRound(Round());
 #ifdef BACK_REMOVE_RACK_NEW_PART
     t->getPlayedRound().setNew(Rack());
 #endif

Index: game/history.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/history.h,v
retrieving revision 1.11.2.2
retrieving revision 1.11.2.3
diff -u -b -r1.11.2.2 -r1.11.2.3
--- game/history.h      17 Dec 2007 11:27:41 -0000      1.11.2.2
+++ game/history.h      23 Dec 2007 23:12:43 -0000      1.11.2.3
@@ -33,7 +33,7 @@
 using std::wstring;
 using std::vector;
 
-class Round;
+class Move;
 class Turn;
 class PlayedRack;
 
@@ -77,11 +77,19 @@
     const Turn& getTurn(unsigned int) const;
 
     /**
-     * Update the history with the given round and complete the turn.
+     * Return true if the history doesn't contain at least one move
+     * corresponding to a valid round, false otherwise.
+     * Said differently, this method checks whether a word was already played
+     * on the board.
+     */
+    bool beforeFirstRound() const;
+
+    /**
+     * Update the history with the given move and complete the turn.
      * A new turn is created with the unplayed letters in the rack
      * 03 sept 2000: We have to sort the tiles according to the new rules
      */
-    void playRound(unsigned int player, unsigned int turn, const Round& round);
+    void playMove(unsigned int player, unsigned int turn, const Move &iMove);
 
     /// Remove last turn
     void removeLastTurn();

Index: game/player.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/player.cpp,v
retrieving revision 1.14.2.3
retrieving revision 1.14.2.4
diff -u -b -r1.14.2.3 -r1.14.2.4
--- game/player.cpp     20 Dec 2007 08:47:08 -0000      1.14.2.3
+++ game/player.cpp     23 Dec 2007 23:12:44 -0000      1.14.2.4
@@ -55,22 +55,22 @@
 }
 
 
-const Round & Player::getLastRound() const
+const Move & Player::getLastMove() const
 {
-    return m_history.getPreviousTurn().getRound();
+    return m_history.getPreviousTurn().getMove();
 }
 
 
-void Player::endTurn(const Round &iRound, unsigned int iTurn)
+void Player::endTurn(const Move &iMove, unsigned int iTurn)
 {
-    addPoints(iRound.getPoints());
-    m_history.playRound(m_id, iTurn, iRound);
+    addPoints(iMove.getScore());
+    m_history.playMove(m_id, iTurn, iMove);
 }
 
 void Player::removeLastTurn()
 {
     // Remove points of the last turn
-    addPoints(- m_history.getPreviousTurn().getRound().getPoints());
+    addPoints(- m_history.getPreviousTurn().getMove().getScore());
     m_history.removeLastTurn();
 }
 

Index: game/player.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/player.h,v
retrieving revision 1.18.2.3
retrieving revision 1.18.2.4
diff -u -b -r1.18.2.3 -r1.18.2.4
--- game/player.h       20 Dec 2007 08:47:08 -0000      1.18.2.3
+++ game/player.h       23 Dec 2007 23:12:44 -0000      1.18.2.4
@@ -48,8 +48,8 @@
     const PlayedRack & getCurrentRack() const;
     // Get the previous rack
     const PlayedRack & getLastRack() const;
-    // Get the previous round (corresponding to the previous rack...)
-    const Round & getLastRound() const;
+    /// Get the previous move (corresponding to the previous rack...)
+    const Move & getLastMove() const;
 
     void setCurrentRack(const PlayedRack &iPld);
 
@@ -66,11 +66,12 @@
     int  getPoints() const      { return m_score; }
 
     /**
-     * Update the player "history", with the given round.
+     * Update the player "history", with the given move.
      * A new rack is created with the remaining letters.
-     * The points of the rack are added to the player's score.
+     * The score of the player is updated with the one of the move, if it is
+     * meaningful.
      */
-    void endTurn(const Round &iRound, unsigned int iTurn);
+    void endTurn(const Move &iMove, unsigned int iTurn);
 
     wstring toString() const;
 

Index: game/results.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/results.cpp,v
retrieving revision 1.10.2.3
retrieving revision 1.10.2.4
diff -u -b -r1.10.2.3 -r1.10.2.4
--- game/results.cpp    20 Dec 2007 08:47:08 -0000      1.10.2.3
+++ game/results.cpp    23 Dec 2007 23:12:44 -0000      1.10.2.4
@@ -54,11 +54,11 @@
 
 
 void Results::search(const Dictionary &iDic, Board &iBoard,
-                     const Rack &iRack, unsigned int iTurn)
+                     const Rack &iRack, bool iFirstWord)
 {
     clear();
 
-    if (iTurn == 0)
+    if (iFirstWord)
     {
         iBoard.searchFirst(iDic, iRack, *this);
     }

Index: game/results.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/results.h,v
retrieving revision 1.8.2.4
retrieving revision 1.8.2.5
diff -u -b -r1.8.2.4 -r1.8.2.5
--- game/results.h      20 Dec 2007 08:47:09 -0000      1.8.2.4
+++ game/results.h      23 Dec 2007 23:12:44 -0000      1.8.2.5
@@ -51,9 +51,9 @@
     void clear()        { m_rounds.clear(); }
     const Round & get(unsigned int) const;
 
-    // Perform a search on the board
+    /// Perform a search on the board
     void search(const Dictionary &iDic, Board &iBoard,
-                const Rack &iRack, unsigned int iTurn);
+                const Rack &iRack, bool iFirstWord);
 
     // FIXME: This method is used to fill the container with the rounds,
     // but it should not be part of the public interface

Index: game/settings.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/Attic/settings.cpp,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -u -b -r1.1.2.1 -r1.1.2.2
--- game/settings.cpp   20 Dec 2007 08:47:09 -0000      1.1.2.1
+++ game/settings.cpp   23 Dec 2007 23:12:44 -0000      1.1.2.2
@@ -18,7 +18,6 @@
  *****************************************************************************/
 
 #include "settings.h"
-// TMP
 #include <stdlib.h>
 
 
@@ -44,11 +43,46 @@
 
 Settings::Settings()
 {
+    // ============== General options ==============
+
+
+    // ============== Training mode options ==============
+
+
+    // ============== Duplicate mode options ==============
+
     // Minimum number of players in a duplicate game needed to apply a "solo" 
bonus
     // (16 is the ODS value)
     m_intHandler.addOption("duplicate-solo-players", 16);
     // Number of points granted for a solo (10 is the ODS value)
     m_intHandler.addOption("duplicate-solo-value", 10);
+
+    // If true, Eliot complains when the player does something illegal
+    // If false, the word is accepted (with a score of 0) and the player does
+    // not get a second chance
+    m_boolHandler.addOption("duplicate-reject-invalid", false);
+
+
+    // ============== Freegame mode options ==============
+
+    // If true, Eliot complains when the player does something illegal
+    // If false, the word is accepted (with a score of 0) and the player does
+    // not get a second chance.
+    // Trying to change letters or to pass the turn in an incorrect way will
+    // be rejected in any case.
+    m_boolHandler.addOption("freegame-reject-invalid", false);
+}
+
+
+void Settings::setBool(const string &iName, bool iValue)
+{
+    m_boolHandler.setOption(iName, iValue);
+}
+
+
+bool Settings::getBool(const string &iName) const
+{
+    return m_boolHandler.getOption(iName);
 }
 
 

Index: game/settings.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/Attic/settings.h,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -u -b -r1.1.2.1 -r1.1.2.2
--- game/settings.h     20 Dec 2007 08:47:09 -0000      1.1.2.1
+++ game/settings.h     23 Dec 2007 23:12:44 -0000      1.1.2.2
@@ -47,10 +47,12 @@
     /// Destroy the singleton cleanly
     static void Destroy();
 
+    void setBool(const string &iName, bool iValue);
+    bool getBool(const string &iName) const;
+
     void setInt(const string &iName, int iValue);
     int getInt(const string &iName) const;
 
-
 private:
 
     /**

Index: game/training.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/training.cpp,v
retrieving revision 1.17.2.4
retrieving revision 1.17.2.5
diff -u -b -r1.17.2.4 -r1.17.2.5
--- game/training.cpp   20 Dec 2007 08:47:09 -0000      1.17.2.4
+++ game/training.cpp   23 Dec 2007 23:12:44 -0000      1.17.2.5
@@ -24,6 +24,7 @@
 #include "tile.h"
 #include "rack.h"
 #include "round.h"
+#include "move.h"
 #include "pldrack.h"
 #include "player.h"
 #include "training.h"
@@ -38,22 +39,16 @@
 }
 
 
-Training::~Training()
-{
-}
-
-
 int Training::setRackRandom(bool iCheck, set_rack_mode mode)
 {
 #define MAX_RANDOM_TRY 5
 
     int res;
     int try_number = 0;
-    unsigned int p = m_currPlayer;
     m_results.clear();
     do
     {
-        res = helperSetRackRandom(p, iCheck, mode);
+        res = helperSetRackRandom(m_currPlayer, iCheck, mode);
         try_number ++;
     } while (res == 2 && try_number < MAX_RANDOM_TRY);
     // 0 : ok
@@ -65,18 +60,14 @@
 
 int Training::setRackManual(bool iCheck, const wstring &iLetters)
 {
-    int res;
-    unsigned int p = m_currPlayer;
-    wstring::iterator it;
-    wstring upperLetters = iLetters;
     // 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
-    upperLetters = iLetters;
+    wstring upperLetters = iLetters;
     std::transform(upperLetters.begin(), upperLetters.end(),
                    upperLetters.begin(), towupper);
-    res = helperSetRackManual(p, iCheck, upperLetters);
+    int res = helperSetRackManual(m_currPlayer, iCheck, upperLetters);
     // 0: ok
     // 1: not enough tiles
     // 2: check failed (number of vowels before round 15)
@@ -108,7 +99,7 @@
 
 int Training::play(const wstring &iCoord, const wstring &iWord)
 {
-    /* Perform all the validity checks, and fill a round */
+    // Perform all the validity checks, and fill a round
     Round round;
 
     int res = checkPlayedWord(iCoord, iWord, round);
@@ -118,20 +109,21 @@
         return res;
     }
 
-    /* Update the rack and the score of the current player */
     debug("play: %s %s %d\n",
           convertToMb(round.getWord()).c_str(),
           convertToMb(round.getCoord().toString()).c_str(),
           round.getPoints());
 
-    // Player::endTurn() must be called before Game::helperPlayRound().
+    Move move(round);
+    // Update the rack and the score of the current player
+    // Player::endTurn() must be called before Game::helperPlayMove().
     // See the big comment in game.cpp, line 96
-    m_players[m_currPlayer]->endTurn(round, m_history.getSize());
+    m_players[m_currPlayer]->endTurn(move, m_history.getSize());
 
-    /* Everything is OK, we can play the word */
-    helperPlayRound(m_currPlayer, round);
+    // Everything is OK, we can play the word
+    helperPlayMove(m_currPlayer, move);
 
-    /* Next turn */
+    // Next turn
     endTurn();
 
     return 0;
@@ -150,10 +142,9 @@
 }
 
 
-int Training::endTurn()
+void Training::endTurn()
 {
-    // Nothing to do?
-    return 0;
+    // Nothing to do, but this method is kept for consistency with other modes
 }
 
 
@@ -163,7 +154,7 @@
     Rack r;
     m_players[m_currPlayer]->getCurrentRack().getRack(r);
     debug("Training::search for %s\n", convertToMb(r.toString()).c_str());
-    m_results.search(m_dic, m_board, r, m_history.getSize());
+    m_results.search(m_dic, m_board, r, m_history.beforeFirstRound());
 }
 
 
@@ -171,16 +162,16 @@
 {
     if (n >= m_results.size())
         return 2;
-    const Round &round = m_results.get(n);
 
-    /* Update the rack and the score of the current player */
-    m_players[m_currPlayer]->endTurn(round, m_history.getSize());
+    Move move(m_results.get(n));
+    // Update the rack and the score of the current player
+    m_players[m_currPlayer]->endTurn(move, m_history.getSize());
 
-    helperPlayRound(m_currPlayer, round);
+    // Update the game
+    helperPlayMove(m_currPlayer, move);
     m_results.clear();
 
-    /* Next turn */
-    // XXX: Should it be done by the interface instead?
+    // Next turn
     endTurn();
 
     return 0;
@@ -201,9 +192,9 @@
 }
 
 
-void Training::testPlay(int num)
+void Training::testPlay(unsigned int num)
 {
-    ASSERT(0 <= num && num < m_results.size(), "Wrong result number");
+    ASSERT(num < m_results.size(), "Wrong result number");
     m_testRound = m_results.get(num);
     m_board.testRound(m_results.get(num));
 }

Index: game/training.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/training.h,v
retrieving revision 1.15.2.1
retrieving revision 1.15.2.2
diff -u -b -r1.15.2.1 -r1.15.2.2
--- game/training.h     20 Dec 2007 08:47:09 -0000      1.15.2.1
+++ game/training.h     23 Dec 2007 23:12:44 -0000      1.15.2.2
@@ -24,6 +24,7 @@
 #include <string>
 
 #include "game.h"
+#include "round.h"
 #include "results.h"
 
 using std::string;
@@ -34,6 +35,7 @@
  * This class handles the logic specific to a training game.
  * As its name indicates, it is not a game in the literal meaning of the word,
  * in particular because the rack can be set at will.
+ *
  * Note: No player should be added to this game, a human player is added
  * automatically (in the start() method)
  */
@@ -48,9 +50,12 @@
      * Game handling
      *************************/
     virtual int start();
+
+    /// See description of Game::play()
     virtual int play(const wstring &iCoord, const wstring &iWord);
-    virtual int endTurn();
+
     void search();
+    const Results& getResults() const { return m_results; };
     int playResult(unsigned int);
 
     int setRackRandom(bool, set_rack_mode);
@@ -59,7 +64,7 @@
 
     /*************************
      * Override the default behaviour of these methods, because in training
-     * we only want a human player
+     * mode we only want a human player
      *************************/
     virtual void addHumanPlayer();
     virtual void addAIPlayer();
@@ -68,23 +73,25 @@
      * Functions to access the current search results
      * The int parameter should be 0 <= int < getNResults
      *************************/
-    const Results& getResults() const { return m_results; };
 
-    /// Place a temporary word on the board for preview purpose
-    void testPlay(int);
-    /// Remove the temporary word(s)
+    /// Place a temporary word on the board for preview purposes
+    void testPlay(unsigned int);
+    /// Remove the temporary word
     void removeTestPlay();
     /// Get the temporary word
     wstring getTestPlayWord() const;
 
 private:
-    // Private constructor and destructor to force using the GameFactory class
+    /// Private constructor and destructor to force using the GameFactory class
     Training(const Dictionary &iDic);
-    virtual ~Training();
 
-    // Search results, with all the possible rounds
-    Round   m_testRound;
+    void endTurn();
+
+    /// Search results, with all the possible rounds
     Results m_results;
+
+    /// Round corresponding to the last test play (if any)
+    Round m_testRound;
 };
 
 #endif /* _TRAINING_H_ */

Index: game/turn.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/game/turn.cpp,v
retrieving revision 1.11.2.2
retrieving revision 1.11.2.3
diff -u -b -r1.11.2.2 -r1.11.2.3
--- game/turn.cpp       17 Dec 2007 11:27:42 -0000      1.11.2.2
+++ game/turn.cpp       23 Dec 2007 23:12:44 -0000      1.11.2.3
@@ -19,38 +19,37 @@
 
 /**
  *  \file   turn.cpp
- *  \brief  Game turn (= id + pldrack + round)
+ *  \brief  Game turn (= id + pldrack + move)
  *  \author Antoine Fraboulet
  *  \date   2005
  */
 
-#include <string>
-#include "pldrack.h"
-#include "round.h"
 #include "turn.h"
 
 
+// FIXME: move set to an invalid value. It would be better to get rid of this
+// constructor completely
 Turn::Turn()
-    : m_num(0), m_playerId(0)
+    : m_num(0), m_playerId(0), m_move(L"", L"")
 {
 }
 
 
 Turn::Turn(unsigned int iNum, unsigned int iPlayerId,
-           const PlayedRack& iPldRack, const Round& iRound)
-    : m_num(iNum), m_playerId(iPlayerId), m_pldrack(iPldRack), m_round(iRound)
+           const PlayedRack& iPldRack, const Move& iMove)
+    : m_num(iNum), m_playerId(iPlayerId), m_pldrack(iPldRack), m_move(iMove)
 {
 }
 
 
 wstring Turn::toString(bool iShowExtraSigns) const
 {
-    wstring rs = L"";
+    wstring rs;
     if (iShowExtraSigns)
     {
         // TODO
     }
-    rs = rs + m_pldrack.toString() + L" " + m_round.toString();
+    rs = rs + m_pldrack.toString() + L" " + m_move.toString();
     return rs;
 }
 

Index: game/turn.h
===================================================================
RCS file: /cvsroot/eliot/eliot/game/turn.h,v
retrieving revision 1.9.2.2
retrieving revision 1.9.2.3
diff -u -b -r1.9.2.2 -r1.9.2.3
--- game/turn.h 17 Dec 2007 11:27:42 -0000      1.9.2.2
+++ game/turn.h 23 Dec 2007 23:12:44 -0000      1.9.2.3
@@ -19,7 +19,7 @@
 
 /**
  *  \file   turn.h
- *  \brief  Game turn (= id + pldrack + round)
+ *  \brief  Game turn (= id + pldrack + move)
  *  \author Antoine Fraboulet
  *  \date   2005
  */
@@ -28,13 +28,15 @@
 #define _TURN_H
 
 #include <string>
+#include "pldrack.h"
+#include "move.h"
 
 using std::wstring;
 
 
 /**
  * A Turn is the information about one 'move' done by a player.
- * It consists of the player who played, the rack, and the played round.
+ * It consists of the player who played, the rack, and the actual move.
  * A turn also has an id (XXX: currently never read)
  *
  * This class has no logic, it is merely there to aggregate corresponding
@@ -45,17 +47,17 @@
 public:
     Turn();
     Turn(unsigned int iNum, unsigned int iPlayerId,
-         const PlayedRack& iPldRack, const Round& iRound);
+         const PlayedRack& iPldRack, const Move& iMove);
 
     void setNum(unsigned int iNum)                 { m_num = iNum; }
     void setPlayer(unsigned int iPlayerId)         { m_playerId = iPlayerId; }
     void setPlayedRack(const PlayedRack& iPldRack) { m_pldrack = iPldRack; }
-    void setRound(const Round& iRound)             { m_round = iRound; }
+    void setMove(const Move& iMove)             { m_move = iMove; }
 
     unsigned int      getNum()        const { return m_num; }
     unsigned int      getPlayer()     const { return m_playerId; }
     const PlayedRack& getPlayedRack() const { return m_pldrack; }
-    const Round&      getRound()      const { return m_round; }
+    const Move&       getMove()       const { return m_move; }
 
     wstring toString(bool iShowExtraSigns = false) const;
 
@@ -63,8 +65,7 @@
     unsigned int m_num;
     unsigned int m_playerId;
     PlayedRack   m_pldrack;
-    Round        m_round;
-
+    Move         m_move;
 };
 
 #endif

Index: po/eliot.pot
===================================================================
RCS file: /cvsroot/eliot/eliot/po/eliot.pot,v
retrieving revision 1.6.6.6
retrieving revision 1.6.6.7
diff -u -b -r1.6.6.6 -r1.6.6.7
--- po/eliot.pot        16 Dec 2007 18:20:55 -0000      1.6.6.6
+++ po/eliot.pot        23 Dec 2007 23:12:45 -0000      1.6.6.7
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-12-16 19:18+0100\n"
+"POT-Creation-Date: 2007-12-23 23:08+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <address@hidden>\n"
 "Language-Team: LANGUAGE <address@hidden>\n"
@@ -286,125 +286,129 @@
 msgid "Search results"
 msgstr ""
 
-#: utils/ncurses.cpp:344
+#: utils/ncurses.cpp:345
 msgid "History of the game"
 msgstr ""
 
-#: utils/ncurses.cpp:350
+#: utils/ncurses.cpp:351
 msgid " N |   RACK   |    SOLUTION     | REF | PTS | P | BONUS"
 msgstr ""
 
-#: utils/ncurses.cpp:384
+#: utils/ncurses.cpp:390
+msgid "(PASS)"
+msgstr ""
+
+#: utils/ncurses.cpp:416
 msgid "Help"
 msgstr ""
 
-#: utils/ncurses.cpp:388
+#: utils/ncurses.cpp:420
 msgid "[Global]"
 msgstr ""
 
-#: utils/ncurses.cpp:389
+#: utils/ncurses.cpp:421
 msgid "   h, H, ?          Show/hide help box"
 msgstr ""
 
-#: utils/ncurses.cpp:390
+#: utils/ncurses.cpp:422
 msgid "   y, Y             Show/hide history of the game"
 msgstr ""
 
-#: utils/ncurses.cpp:391
+#: utils/ncurses.cpp:423
 msgid ""
 "   b, B             Show/hide contents of the bag (including letters of the "
 "racks)"
 msgstr ""
 
-#: utils/ncurses.cpp:392
+#: utils/ncurses.cpp:424
 msgid "   e, E             Show/hide dots on empty squares of the board"
 msgstr ""
 
-#: utils/ncurses.cpp:393
+#: utils/ncurses.cpp:425
 msgid "   d, D             Check the existence of a word in the dictionary"
 msgstr ""
 
-#: utils/ncurses.cpp:394
+#: utils/ncurses.cpp:426
 msgid "   j, J             Play a word"
 msgstr ""
 
-#: utils/ncurses.cpp:395
+#: utils/ncurses.cpp:427
 msgid "   s, S             Save the game"
 msgstr ""
 
-#: utils/ncurses.cpp:396
+#: utils/ncurses.cpp:428
 msgid "   l, L             Load a game"
 msgstr ""
 
-#: utils/ncurses.cpp:397
+#: utils/ncurses.cpp:429
 msgid "   q, Q             Quit"
 msgstr ""
 
-#: utils/ncurses.cpp:400
+#: utils/ncurses.cpp:432
 msgid "[Training mode]"
 msgstr ""
 
-#: utils/ncurses.cpp:401
+#: utils/ncurses.cpp:433
 msgid "   *                Take a random rack"
 msgstr ""
 
-#: utils/ncurses.cpp:402
+#: utils/ncurses.cpp:434
 msgid "   +                Complete the current rack randomly"
 msgstr ""
 
-#: utils/ncurses.cpp:403
+#: utils/ncurses.cpp:435
 msgid "   t, T             Set the rack manually"
 msgstr ""
 
-#: utils/ncurses.cpp:404
+#: utils/ncurses.cpp:436
 msgid "   c, C             Compute all the possible words"
 msgstr ""
 
-#: utils/ncurses.cpp:405
+#: utils/ncurses.cpp:437
 msgid "   r, R             Show/hide search results"
 msgstr ""
 
-#: utils/ncurses.cpp:408
+#: utils/ncurses.cpp:440
 msgid "[Duplicate mode]"
 msgstr ""
 
-#: utils/ncurses.cpp:409
+#: utils/ncurses.cpp:441
 msgid "   n, N             Switch to the next human player"
 msgstr ""
 
-#: utils/ncurses.cpp:412
+#: utils/ncurses.cpp:444
 msgid "[Free game mode]"
 msgstr ""
 
-#: utils/ncurses.cpp:413
+#: utils/ncurses.cpp:445
 msgid "   p, P             Pass your turn (with or without changing letters)"
 msgstr ""
 
-#: utils/ncurses.cpp:416
+#: utils/ncurses.cpp:448
 msgid "[Miscellaneous]"
 msgstr ""
 
-#: utils/ncurses.cpp:417
+#: utils/ncurses.cpp:449
 msgid "   <up>, <down>     Navigate in a box line by line"
 msgstr ""
 
-#: utils/ncurses.cpp:418
+#: utils/ncurses.cpp:450
 msgid "   <pgup>, <pgdown> Navigate in a box page by page"
 msgstr ""
 
-#: utils/ncurses.cpp:419
+#: utils/ncurses.cpp:451
 msgid "   Ctrl-l           Refresh the screen"
 msgstr ""
 
-#: utils/ncurses.cpp:430 wxwin/auxframes.cc:148
+#: utils/ncurses.cpp:462 wxwin/auxframes.cc:148
 msgid "Bag"
 msgstr ""
 
-#: utils/ncurses.cpp:437
+#: utils/ncurses.cpp:469
 msgid " LETTER | POINTS | FREQUENCY | REMAINING"
 msgstr ""
 
-#: utils/ncurses.cpp:490
+#: utils/ncurses.cpp:522
 msgid "Play a word"
 msgstr ""
 
@@ -412,115 +416,115 @@
 #. "Coordinates:". For example:
 #. Pl. word   :
 #. Coordinates:
-#: utils/ncurses.cpp:491 utils/ncurses.cpp:499
+#: utils/ncurses.cpp:523 utils/ncurses.cpp:531
 msgid "Played word:"
 msgstr ""
 
-#: utils/ncurses.cpp:492 utils/ncurses.cpp:500
+#: utils/ncurses.cpp:524 utils/ncurses.cpp:532
 msgid "Coordinates:"
 msgstr ""
 
-#: utils/ncurses.cpp:514
+#: utils/ncurses.cpp:546
 msgid "Incorrect or misplaced word"
 msgstr ""
 
-#: utils/ncurses.cpp:524
+#: utils/ncurses.cpp:556
 msgid "Dictionary"
 msgstr ""
 
-#: utils/ncurses.cpp:525
+#: utils/ncurses.cpp:557
 msgid "Enter the word to check:"
 msgstr ""
 
-#: utils/ncurses.cpp:534
+#: utils/ncurses.cpp:566
 #, c-format
 msgid "The word '%ls' exists"
 msgstr ""
 
-#: utils/ncurses.cpp:536
+#: utils/ncurses.cpp:568
 #, c-format
 msgid "The word '%ls' does not exist"
 msgstr ""
 
-#: utils/ncurses.cpp:546 wxwin/mainframe.cc:464 wxwin/mainframe.cc:472
+#: utils/ncurses.cpp:578 wxwin/mainframe.cc:460 wxwin/mainframe.cc:468
 msgid "Save the game"
 msgstr ""
 
-#: utils/ncurses.cpp:547 utils/ncurses.cpp:576
+#: utils/ncurses.cpp:579 utils/ncurses.cpp:609
 msgid "Enter the file name:"
 msgstr ""
 
-#: utils/ncurses.cpp:557
+#: utils/ncurses.cpp:589
 #, c-format
 msgid "Cannot open file %ls for writing"
 msgstr ""
 
-#: utils/ncurses.cpp:564
+#: utils/ncurses.cpp:597
 #, c-format
-msgid "Game saved in %ls"
+msgid "Game saved in '%ls'"
 msgstr ""
 
-#: utils/ncurses.cpp:575 wxwin/mainframe.cc:268 wxwin/mainframe.cc:389
-#: wxwin/mainframe.cc:413
+#: utils/ncurses.cpp:608 wxwin/mainframe.cc:269 wxwin/mainframe.cc:390
+#: wxwin/mainframe.cc:414
 msgid "Load a game"
 msgstr ""
 
-#: utils/ncurses.cpp:586
+#: utils/ncurses.cpp:619
 #, c-format
-msgid "Cannot open file %ls for reading"
+msgid "Cannot open file '%ls' for reading"
 msgstr ""
 
-#: utils/ncurses.cpp:594
+#: utils/ncurses.cpp:627
 #, c-format
 msgid "Invalid saved game"
 msgstr ""
 
-#: utils/ncurses.cpp:598
+#: utils/ncurses.cpp:632
 #, c-format
 msgid "Game loaded"
 msgstr ""
 
-#: utils/ncurses.cpp:613
+#: utils/ncurses.cpp:647
 msgid "Pass your turn"
 msgstr ""
 
-#: utils/ncurses.cpp:614
+#: utils/ncurses.cpp:648
 msgid "Enter the letters to change:"
 msgstr ""
 
-#: utils/ncurses.cpp:623
+#: utils/ncurses.cpp:657
 msgid "Cannot pass the turn"
 msgstr ""
 
-#: utils/ncurses.cpp:633
+#: utils/ncurses.cpp:667
 msgid "Set rack"
 msgstr ""
 
-#: utils/ncurses.cpp:634
+#: utils/ncurses.cpp:668
 msgid "Enter the new letters:"
 msgstr ""
 
-#: utils/ncurses.cpp:643
+#: utils/ncurses.cpp:677
 msgid "Cannot take these letters from the bag"
 msgstr ""
 
-#: utils/ncurses.cpp:1037
+#: utils/ncurses.cpp:1071
 msgid "Training mode"
 msgstr ""
 
-#: utils/ncurses.cpp:1039
+#: utils/ncurses.cpp:1073
 msgid "Free game mode"
 msgstr ""
 
-#: utils/ncurses.cpp:1041
+#: utils/ncurses.cpp:1075
 msgid "Duplicate mode"
 msgstr ""
 
-#: utils/ncurses.cpp:1044
+#: utils/ncurses.cpp:1078
 msgid "Joker game"
 msgstr ""
 
-#: utils/ncurses.cpp:1045
+#: utils/ncurses.cpp:1079
 msgid "[h for help]"
 msgstr ""
 
@@ -556,8 +560,8 @@
 msgid "Copy"
 msgstr ""
 
-#: wxwin/auxframes.cc:348 wxwin/mainframe.cc:491 wxwin/mainframe.cc:511
-#: wxwin/mainframe.cc:542
+#: wxwin/auxframes.cc:348 wxwin/mainframe.cc:487 wxwin/mainframe.cc:507
+#: wxwin/mainframe.cc:538
 msgid "No on going game"
 msgstr ""
 
@@ -569,11 +573,11 @@
 msgid "Rack: "
 msgstr ""
 
-#: wxwin/auxframes.cc:525 wxwin/mainframe.cc:318
+#: wxwin/auxframes.cc:525 wxwin/mainframe.cc:319
 msgid "Game history"
 msgstr ""
 
-#: wxwin/auxframes.cc:557 wxwin/mainframe.cc:320
+#: wxwin/auxframes.cc:557 wxwin/mainframe.cc:321
 msgid "Results"
 msgstr ""
 
@@ -685,7 +689,7 @@
 msgid "Nb"
 msgstr ""
 
-#: wxwin/configdb.cc:323 wxwin/mainframe.cc:173
+#: wxwin/configdb.cc:323 wxwin/mainframe.cc:174
 msgid "Rack"
 msgstr ""
 
@@ -721,396 +725,396 @@
 msgid "Results of the search"
 msgstr ""
 
-#: wxwin/mainframe.cc:204
+#: wxwin/mainframe.cc:205
 msgid " Rack "
 msgstr ""
 
-#: wxwin/mainframe.cc:205
+#: wxwin/mainframe.cc:206
 msgid " Complement "
 msgstr ""
 
-#: wxwin/mainframe.cc:206
+#: wxwin/mainframe.cc:207
 msgid " Search "
 msgstr ""
 
-#: wxwin/mainframe.cc:207
+#: wxwin/mainframe.cc:208
 msgid " Back "
 msgstr ""
 
-#: wxwin/mainframe.cc:208
+#: wxwin/mainframe.cc:209
 msgid " Play "
 msgstr ""
 
-#: wxwin/mainframe.cc:210
+#: wxwin/mainframe.cc:211
 msgid "Random rack"
 msgstr ""
 
-#: wxwin/mainframe.cc:211
+#: wxwin/mainframe.cc:212
 msgid "Random complement of the rack"
 msgstr ""
 
-#: wxwin/mainframe.cc:212
+#: wxwin/mainframe.cc:213
 msgid "Search with the current rack"
 msgstr ""
 
-#: wxwin/mainframe.cc:213
+#: wxwin/mainframe.cc:214
 msgid "Go back one turn"
 msgstr ""
 
-#: wxwin/mainframe.cc:214
+#: wxwin/mainframe.cc:215
 msgid "Play the selected word"
 msgstr ""
 
-#: wxwin/mainframe.cc:265
+#: wxwin/mainframe.cc:266
 msgid "&New game\tctrl+n"
 msgstr ""
 
-#: wxwin/mainframe.cc:265
+#: wxwin/mainframe.cc:266
 msgid "Start a new game"
 msgstr ""
 
-#: wxwin/mainframe.cc:266
+#: wxwin/mainframe.cc:267
 msgid "New &joker game\tctrl+j"
 msgstr ""
 
-#: wxwin/mainframe.cc:266
+#: wxwin/mainframe.cc:267
 msgid "Start a new joker game"
 msgstr ""
 
-#: wxwin/mainframe.cc:268
+#: wxwin/mainframe.cc:269
 msgid "&Load...\tctrl+l"
 msgstr ""
 
-#: wxwin/mainframe.cc:269
+#: wxwin/mainframe.cc:270
 msgid "&Save as...\tctrl+s"
 msgstr ""
 
-#: wxwin/mainframe.cc:269
+#: wxwin/mainframe.cc:270
 msgid "Save the current game"
 msgstr ""
 
-#: wxwin/mainframe.cc:271
+#: wxwin/mainframe.cc:272
 msgid "&Print...\tctrl+p"
 msgstr ""
 
-#: wxwin/mainframe.cc:271
+#: wxwin/mainframe.cc:272
 msgid "Print this game"
 msgstr ""
 
-#: wxwin/mainframe.cc:272
+#: wxwin/mainframe.cc:273
 msgid "Print pre&view..."
 msgstr ""
 
-#: wxwin/mainframe.cc:272
+#: wxwin/mainframe.cc:273
 msgid "Print preview of the game"
 msgstr ""
 
-#: wxwin/mainframe.cc:274
+#: wxwin/mainframe.cc:275
 msgid "Print in PostS&cript..."
 msgstr ""
 
-#: wxwin/mainframe.cc:274
+#: wxwin/mainframe.cc:275
 msgid "Print in a PostScript file"
 msgstr ""
 
-#: wxwin/mainframe.cc:277
+#: wxwin/mainframe.cc:278
 msgid "&Quit"
 msgstr ""
 
-#: wxwin/mainframe.cc:277
+#: wxwin/mainframe.cc:278
 msgid "Quit Eliot"
 msgstr ""
 
-#: wxwin/mainframe.cc:280
+#: wxwin/mainframe.cc:281
 msgid "&Dictionary..."
 msgstr ""
 
-#: wxwin/mainframe.cc:280 wxwin/mainframe.cc:593
+#: wxwin/mainframe.cc:281 wxwin/mainframe.cc:589
 msgid "Choose a dictionary"
 msgstr ""
 
-#: wxwin/mainframe.cc:281
+#: wxwin/mainframe.cc:282
 msgid "&Search..."
 msgstr ""
 
-#: wxwin/mainframe.cc:281
+#: wxwin/mainframe.cc:282
 msgid "Search options"
 msgstr ""
 
-#: wxwin/mainframe.cc:284
+#: wxwin/mainframe.cc:285
 msgid "&Background..."
 msgstr ""
 
-#: wxwin/mainframe.cc:284
+#: wxwin/mainframe.cc:285
 msgid "Background color"
 msgstr ""
 
-#: wxwin/mainframe.cc:285
+#: wxwin/mainframe.cc:286
 msgid "L&ines..."
 msgstr ""
 
-#: wxwin/mainframe.cc:285
+#: wxwin/mainframe.cc:286
 msgid "Color of the lines"
 msgstr ""
 
-#: wxwin/mainframe.cc:287
+#: wxwin/mainframe.cc:288
 msgid "&Played letters..."
 msgstr ""
 
-#: wxwin/mainframe.cc:287
+#: wxwin/mainframe.cc:288
 msgid "Color of the letters played on the board"
 msgstr ""
 
-#: wxwin/mainframe.cc:288
+#: wxwin/mainframe.cc:289
 msgid "&Temporary letters..."
 msgstr ""
 
-#: wxwin/mainframe.cc:288
+#: wxwin/mainframe.cc:289
 msgid "Color of the letters of the temporary word"
 msgstr ""
 
-#: wxwin/mainframe.cc:289
+#: wxwin/mainframe.cc:290
 msgid "B&ackground of played letters..."
 msgstr ""
 
-#: wxwin/mainframe.cc:289
+#: wxwin/mainframe.cc:290
 msgid "Background color of the letters played on the board"
 msgstr ""
 
-#: wxwin/mainframe.cc:290
+#: wxwin/mainframe.cc:291
 msgid "Ba&ckground of temporary letters..."
 msgstr ""
 
-#: wxwin/mainframe.cc:290
+#: wxwin/mainframe.cc:291
 msgid "Background color of the temporary letters on the board"
 msgstr ""
 
-#: wxwin/mainframe.cc:292
+#: wxwin/mainframe.cc:293
 msgid "Double &letter..."
 msgstr ""
 
-#: wxwin/mainframe.cc:292
+#: wxwin/mainframe.cc:293
 msgid "Color of the \"double letter\" squares"
 msgstr ""
 
-#: wxwin/mainframe.cc:293
+#: wxwin/mainframe.cc:294
 msgid "Triple l&etter..."
 msgstr ""
 
-#: wxwin/mainframe.cc:293
+#: wxwin/mainframe.cc:294
 msgid "Color of the \"triple letter\" squares"
 msgstr ""
 
-#: wxwin/mainframe.cc:294
+#: wxwin/mainframe.cc:295
 msgid "Double &word..."
 msgstr ""
 
-#: wxwin/mainframe.cc:294
+#: wxwin/mainframe.cc:295
 msgid "Color of the \"double word\" squares"
 msgstr ""
 
-#: wxwin/mainframe.cc:295
+#: wxwin/mainframe.cc:296
 msgid "Triple w&ord..."
 msgstr ""
 
-#: wxwin/mainframe.cc:295
+#: wxwin/mainframe.cc:296
 msgid "Color of the \"triple word\" squares"
 msgstr ""
 
-#: wxwin/mainframe.cc:297
+#: wxwin/mainframe.cc:298
 msgid "&Default colors"
 msgstr ""
 
-#: wxwin/mainframe.cc:297
+#: wxwin/mainframe.cc:298
 msgid "Restore the default colors"
 msgstr ""
 
-#: wxwin/mainframe.cc:300
+#: wxwin/mainframe.cc:301
 msgid "&Search letters..."
 msgstr ""
 
-#: wxwin/mainframe.cc:300
+#: wxwin/mainframe.cc:301
 msgid "Font for the search"
 msgstr ""
 
-#: wxwin/mainframe.cc:303 wxwin/mainframe.cc:327
+#: wxwin/mainframe.cc:304 wxwin/mainframe.cc:328
 msgid "&Game"
 msgstr ""
 
-#: wxwin/mainframe.cc:303
+#: wxwin/mainframe.cc:304
 msgid "Configuration of the game"
 msgstr ""
 
-#: wxwin/mainframe.cc:304
+#: wxwin/mainframe.cc:305
 msgid "&Fonts"
 msgstr ""
 
-#: wxwin/mainframe.cc:304
+#: wxwin/mainframe.cc:305
 msgid "Configuration of the fonts"
 msgstr ""
 
-#: wxwin/mainframe.cc:305
+#: wxwin/mainframe.cc:306
 msgid "&Colors"
 msgstr ""
 
-#: wxwin/mainframe.cc:305
+#: wxwin/mainframe.cc:306
 msgid "Configuration of the colors"
 msgstr ""
 
-#: wxwin/mainframe.cc:306
+#: wxwin/mainframe.cc:307
 msgid "&Printing..."
 msgstr ""
 
-#: wxwin/mainframe.cc:306
+#: wxwin/mainframe.cc:307
 msgid "Configuration of the printing parameters"
 msgstr ""
 
-#: wxwin/mainframe.cc:309
+#: wxwin/mainframe.cc:310
 msgid "&Board"
 msgstr ""
 
-#: wxwin/mainframe.cc:309
+#: wxwin/mainframe.cc:310
 msgid "Game board"
 msgstr ""
 
-#: wxwin/mainframe.cc:310
+#: wxwin/mainframe.cc:311
 msgid "Ba&g"
 msgstr ""
 
-#: wxwin/mainframe.cc:310
+#: wxwin/mainframe.cc:311
 msgid "Remaining letters in the bag"
 msgstr ""
 
-#: wxwin/mainframe.cc:311
+#: wxwin/mainframe.cc:312
 msgid "&Check"
 msgstr ""
 
-#: wxwin/mainframe.cc:311
+#: wxwin/mainframe.cc:312
 msgid "Check a word in the dictionary"
 msgstr ""
 
-#: wxwin/mainframe.cc:312
+#: wxwin/mainframe.cc:313
 msgid "&Search"
 msgstr ""
 
-#: wxwin/mainframe.cc:312
+#: wxwin/mainframe.cc:313
 msgid "Search in the dictionary"
 msgstr ""
 
-#: wxwin/mainframe.cc:314
+#: wxwin/mainframe.cc:315
 msgid "&Rack + 1"
 msgstr ""
 
-#: wxwin/mainframe.cc:314
+#: wxwin/mainframe.cc:315
 msgid "Letters of the rack plus one"
 msgstr ""
 
-#: wxwin/mainframe.cc:315
+#: wxwin/mainframe.cc:316
 msgid "R&accords"
 msgstr ""
 
-#: wxwin/mainframe.cc:315
+#: wxwin/mainframe.cc:316
 msgid "Raccords on a word of the search"
 msgstr ""
 
-#: wxwin/mainframe.cc:316
+#: wxwin/mainframe.cc:317
 msgid "&Benjamins"
 msgstr ""
 
-#: wxwin/mainframe.cc:316
+#: wxwin/mainframe.cc:317
 msgid "Benjamins on a word of the search"
 msgstr ""
 
-#: wxwin/mainframe.cc:318
+#: wxwin/mainframe.cc:319
 msgid "Game &history"
 msgstr ""
 
-#: wxwin/mainframe.cc:320
+#: wxwin/mainframe.cc:321
 msgid "R&esults"
 msgstr ""
 
-#: wxwin/mainframe.cc:324
+#: wxwin/mainframe.cc:325
 msgid "&About..."
 msgstr ""
 
-#: wxwin/mainframe.cc:324 wxwin/mainframe.cc:722
+#: wxwin/mainframe.cc:325 wxwin/mainframe.cc:718
 msgid "About Eliot"
 msgstr ""
 
-#: wxwin/mainframe.cc:328
+#: wxwin/mainframe.cc:329
 msgid "&Settings"
 msgstr ""
 
-#: wxwin/mainframe.cc:329
+#: wxwin/mainframe.cc:330
 msgid "&Windows"
 msgstr ""
 
-#: wxwin/mainframe.cc:330
+#: wxwin/mainframe.cc:331
 msgid "&Help"
 msgstr ""
 
-#: wxwin/mainframe.cc:354 wxwin/mainframe.cc:392
+#: wxwin/mainframe.cc:355 wxwin/mainframe.cc:393
 msgid "No dictionary selected"
 msgstr ""
 
-#: wxwin/mainframe.cc:354 wxwin/mainframe.cc:392 wxwin/mainframe.cc:491
-#: wxwin/mainframe.cc:511 wxwin/mainframe.cc:542
+#: wxwin/mainframe.cc:355 wxwin/mainframe.cc:393 wxwin/mainframe.cc:487
+#: wxwin/mainframe.cc:507 wxwin/mainframe.cc:538
 msgid "Eliot: error"
 msgstr ""
 
-#: wxwin/mainframe.cc:412
+#: wxwin/mainframe.cc:413
 msgid "Cannot open "
 msgstr ""
 
-#: wxwin/mainframe.cc:424 wxwin/mainframe.cc:433
+#: wxwin/mainframe.cc:425 wxwin/mainframe.cc:434
 msgid "Error while loading the game"
 msgstr ""
 
-#: wxwin/mainframe.cc:425
+#: wxwin/mainframe.cc:426
 msgid "Invalid game"
 msgstr ""
 
-#: wxwin/mainframe.cc:434
+#: wxwin/mainframe.cc:435
 msgid "The game is empty"
 msgstr ""
 
-#: wxwin/mainframe.cc:471
+#: wxwin/mainframe.cc:467
 msgid "Cannot create "
 msgstr ""
 
-#: wxwin/mainframe.cc:500 wxwin/mainframe.cc:564
+#: wxwin/mainframe.cc:496 wxwin/mainframe.cc:560
 msgid "Printing not done"
 msgstr ""
 
-#: wxwin/mainframe.cc:500 wxwin/mainframe.cc:528
+#: wxwin/mainframe.cc:496 wxwin/mainframe.cc:524
 msgid "Printing"
 msgstr ""
 
-#: wxwin/mainframe.cc:523
+#: wxwin/mainframe.cc:519
 msgid "Print preview problem.\n"
 msgstr ""
 
-#: wxwin/mainframe.cc:524
+#: wxwin/mainframe.cc:520
 msgid "The printer may not be correctly initialized"
 msgstr ""
 
-#: wxwin/mainframe.cc:525
+#: wxwin/mainframe.cc:521
 msgid "Print preview"
 msgstr ""
 
-#: wxwin/mainframe.cc:546
+#: wxwin/mainframe.cc:542
 msgid "Print to a PostScript file"
 msgstr ""
 
-#: wxwin/mainframe.cc:565 wxwin/mainframe.cc:571
+#: wxwin/mainframe.cc:561 wxwin/mainframe.cc:567
 msgid "PostScript printing"
 msgstr ""
 
-#: wxwin/mainframe.cc:570
+#: wxwin/mainframe.cc:566
 msgid "Cannot initialize PostScript printer"
 msgstr ""
 
-#: wxwin/mainframe.cc:718
+#: wxwin/mainframe.cc:714
 msgid ""
 "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 "
@@ -1118,52 +1122,57 @@
 "any later version."
 msgstr ""
 
-#: wxwin/mainframe.cc:916
+#: wxwin/mainframe.cc:912
 msgid "turn:"
 msgstr ""
 
-#: wxwin/mainframe.cc:917
+#: wxwin/mainframe.cc:913
 msgid "points:"
 msgstr ""
 
-#: wxwin/mainframe.cc:954
+#: wxwin/mainframe.cc:948
 msgid ""
 "The bag doesn't contain enough letters\n"
 "for a new rack."
 msgstr ""
 
-#: wxwin/mainframe.cc:955 wxwin/mainframe.cc:959 wxwin/mainframe.cc:963
+#: wxwin/mainframe.cc:949 wxwin/mainframe.cc:953 wxwin/mainframe.cc:957
 msgid "Rack validation"
 msgstr ""
 
-#: wxwin/mainframe.cc:958
+#: wxwin/mainframe.cc:952
 msgid "The rack must contain at least 2 consonants and 2 vowels."
 msgstr ""
 
-#: wxwin/mainframe.cc:962
+#: wxwin/mainframe.cc:956
 msgid "The rack contains invalid letters for the current dictionary"
 msgstr ""
 
-#: wxwin/mainframe.cc:966
+#: wxwin/mainframe.cc:960
 msgid "The rack has been modified manually"
 msgstr ""
 
-#: wxwin/searchpanel.cc:303
+#: wxwin/searchpanel.cc:146 wxwin/searchpanel.cc:190
+#, c-format
+msgid "The search is limited to %d letters"
+msgstr ""
+
+#: wxwin/searchpanel.cc:301
 msgid "Minimum length"
 msgstr ""
 
-#: wxwin/searchpanel.cc:305
+#: wxwin/searchpanel.cc:303
 msgid "Maximum length"
 msgstr ""
 
-#: wxwin/searchpanel.cc:368
+#: wxwin/searchpanel.cc:366
 msgid "Cross words"
 msgstr ""
 
-#: wxwin/searchpanel.cc:369
+#: wxwin/searchpanel.cc:367
 msgid "Plus 1"
 msgstr ""
 
-#: wxwin/searchpanel.cc:370
+#: wxwin/searchpanel.cc:368
 msgid "Regular expressions"
 msgstr ""

Index: po/fr.po
===================================================================
RCS file: /cvsroot/eliot/eliot/po/fr.po,v
retrieving revision 1.6.6.6
retrieving revision 1.6.6.7
diff -u -b -r1.6.6.6 -r1.6.6.7
--- po/fr.po    16 Dec 2007 18:20:55 -0000      1.6.6.6
+++ po/fr.po    23 Dec 2007 23:12:45 -0000      1.6.6.7
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: eliot 1.4\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-12-16 19:18+0100\n"
+"POT-Creation-Date: 2007-12-23 23:08+0100\n"
 "PO-Revision-Date: 2005-02-06 20:03+0100\n"
 "Last-Translator: Olivier Teuliere <address@hidden>\n"
 "Language-Team: French <address@hidden>\n"
@@ -302,31 +302,35 @@
 msgid "Search results"
 msgstr "Résultats de la recherche"
 
-#: utils/ncurses.cpp:344
+#: utils/ncurses.cpp:345
 msgid "History of the game"
 msgstr "Historique de la partie"
 
-#: utils/ncurses.cpp:350
+#: utils/ncurses.cpp:351
 msgid " N |   RACK   |    SOLUTION     | REF | PTS | P | BONUS"
 msgstr " N |  TIRAGE  |    SOLUTION     | REF | PTS | J | BONUS"
 
-#: utils/ncurses.cpp:384
+#: utils/ncurses.cpp:390
+msgid "(PASS)"
+msgstr "(PASSE)"
+
+#: utils/ncurses.cpp:416
 msgid "Help"
 msgstr "Aide"
 
-#: utils/ncurses.cpp:388
+#: utils/ncurses.cpp:420
 msgid "[Global]"
 msgstr "[Général]"
 
-#: utils/ncurses.cpp:389
+#: utils/ncurses.cpp:421
 msgid "   h, H, ?          Show/hide help box"
 msgstr "   h, H, ?          Afficher/cacher la boîte d'aide"
 
-#: utils/ncurses.cpp:390
+#: utils/ncurses.cpp:422
 msgid "   y, Y             Show/hide history of the game"
 msgstr "   y, Y             Afficher/cacher l'historique de la partie"
 
-#: utils/ncurses.cpp:391
+#: utils/ncurses.cpp:423
 msgid ""
 "   b, B             Show/hide contents of the bag (including letters of the "
 "racks)"
@@ -334,98 +338,98 @@
 "   b, B             Afficher/cacher le contenu du sac (avec les lettres des "
 "tirages)"
 
-#: utils/ncurses.cpp:392
+#: utils/ncurses.cpp:424
 msgid "   e, E             Show/hide dots on empty squares of the board"
 msgstr ""
 "   e, E             Afficher/cacher les points sur les cases vides du "
 "plateau de jeu"
 
-#: utils/ncurses.cpp:393
+#: utils/ncurses.cpp:425
 msgid "   d, D             Check the existence of a word in the dictionary"
 msgstr "   d, D             Vérifier l'existence d'un mot dans le 
dictionnaire"
 
-#: utils/ncurses.cpp:394
+#: utils/ncurses.cpp:426
 msgid "   j, J             Play a word"
 msgstr "   j, J             Jouer un mot"
 
-#: utils/ncurses.cpp:395
+#: utils/ncurses.cpp:427
 msgid "   s, S             Save the game"
 msgstr "   s, S             Sauvegarder la partie"
 
-#: utils/ncurses.cpp:396
+#: utils/ncurses.cpp:428
 msgid "   l, L             Load a game"
 msgstr "   l, L             Charger une partie"
 
-#: utils/ncurses.cpp:397
+#: utils/ncurses.cpp:429
 msgid "   q, Q             Quit"
 msgstr "   q, Q             Quitter"
 
-#: utils/ncurses.cpp:400
+#: utils/ncurses.cpp:432
 msgid "[Training mode]"
 msgstr "[Mode entraînement]"
 
-#: utils/ncurses.cpp:401
+#: utils/ncurses.cpp:433
 msgid "   *                Take a random rack"
 msgstr "   *                Tirage aléatoire"
 
-#: utils/ncurses.cpp:402
+#: utils/ncurses.cpp:434
 msgid "   +                Complete the current rack randomly"
 msgstr "   +                Compléter le tirage courant de manière 
aléatoire"
 
-#: utils/ncurses.cpp:403
+#: utils/ncurses.cpp:435
 msgid "   t, T             Set the rack manually"
 msgstr "   t, T             Entrer le tirage manuellement"
 
-#: utils/ncurses.cpp:404
+#: utils/ncurses.cpp:436
 msgid "   c, C             Compute all the possible words"
 msgstr "   c, C             Calculer tous les mots possibles"
 
-#: utils/ncurses.cpp:405
+#: utils/ncurses.cpp:437
 msgid "   r, R             Show/hide search results"
 msgstr "   r, R             Afficher/cacher les résultats de la recherche"
 
-#: utils/ncurses.cpp:408
+#: utils/ncurses.cpp:440
 msgid "[Duplicate mode]"
 msgstr "[Mode duplicate]"
 
-#: utils/ncurses.cpp:409
+#: utils/ncurses.cpp:441
 msgid "   n, N             Switch to the next human player"
 msgstr "   n, N             Passer au joueur humain suivant"
 
-#: utils/ncurses.cpp:412
+#: utils/ncurses.cpp:444
 msgid "[Free game mode]"
 msgstr "[Mode partie libre]"
 
-#: utils/ncurses.cpp:413
+#: utils/ncurses.cpp:445
 msgid "   p, P             Pass your turn (with or without changing letters)"
 msgstr ""
 "   p, P             Passer son tour (en changeant ou pas certaines lettres)"
 
-#: utils/ncurses.cpp:416
+#: utils/ncurses.cpp:448
 msgid "[Miscellaneous]"
 msgstr "[Divers]"
 
-#: utils/ncurses.cpp:417
+#: utils/ncurses.cpp:449
 msgid "   <up>, <down>     Navigate in a box line by line"
 msgstr "   <haut>, <bas>    Naviguer dans une boîte ligne par ligne"
 
-#: utils/ncurses.cpp:418
+#: utils/ncurses.cpp:450
 msgid "   <pgup>, <pgdown> Navigate in a box page by page"
 msgstr "   <pgup>, <pgdown> Naviguer dans une boîte page par page"
 
-#: utils/ncurses.cpp:419
+#: utils/ncurses.cpp:451
 msgid "   Ctrl-l           Refresh the screen"
 msgstr "   Ctrl-l           Rafraîchir l'écran"
 
-#: utils/ncurses.cpp:430 wxwin/auxframes.cc:148
+#: utils/ncurses.cpp:462 wxwin/auxframes.cc:148
 msgid "Bag"
 msgstr "Sac"
 
-#: utils/ncurses.cpp:437
+#: utils/ncurses.cpp:469
 msgid " LETTER | POINTS | FREQUENCY | REMAINING"
 msgstr " LETTRE | POINTS | FREQUENCE | RESTANT"
 
-#: utils/ncurses.cpp:490
+#: utils/ncurses.cpp:522
 msgid "Play a word"
 msgstr "Jouer un mot"
 
@@ -433,115 +437,115 @@
 #. "Coordinates:". For example:
 #. Pl. word   :
 #. Coordinates:
-#: utils/ncurses.cpp:491 utils/ncurses.cpp:499
+#: utils/ncurses.cpp:523 utils/ncurses.cpp:531
 msgid "Played word:"
 msgstr "Mot joué    :"
 
-#: utils/ncurses.cpp:492 utils/ncurses.cpp:500
+#: utils/ncurses.cpp:524 utils/ncurses.cpp:532
 msgid "Coordinates:"
 msgstr "Coordonnées :"
 
-#: utils/ncurses.cpp:514
+#: utils/ncurses.cpp:546
 msgid "Incorrect or misplaced word"
 msgstr "Mot incorrect ou mal placé"
 
-#: utils/ncurses.cpp:524
+#: utils/ncurses.cpp:556
 msgid "Dictionary"
 msgstr "Dictionnaire"
 
-#: utils/ncurses.cpp:525
+#: utils/ncurses.cpp:557
 msgid "Enter the word to check:"
 msgstr "Entrer le mot à vérifier:"
 
-#: utils/ncurses.cpp:534
+#: utils/ncurses.cpp:566
 #, c-format
 msgid "The word '%ls' exists"
 msgstr "Le mot '%ls' existe"
 
-#: utils/ncurses.cpp:536
+#: utils/ncurses.cpp:568
 #, c-format
 msgid "The word '%ls' does not exist"
 msgstr "Le mot '%ls' n'existe pas"
 
-#: utils/ncurses.cpp:546 wxwin/mainframe.cc:464 wxwin/mainframe.cc:472
+#: utils/ncurses.cpp:578 wxwin/mainframe.cc:460 wxwin/mainframe.cc:468
 msgid "Save the game"
 msgstr "Sauvegarder la partie"
 
-#: utils/ncurses.cpp:547 utils/ncurses.cpp:576
+#: utils/ncurses.cpp:579 utils/ncurses.cpp:609
 msgid "Enter the file name:"
 msgstr "Entrer le nom du fichier :"
 
-#: utils/ncurses.cpp:557
+#: utils/ncurses.cpp:589
 #, c-format
 msgid "Cannot open file %ls for writing"
 msgstr "Impossible d'ouvrir le fichier %ls en écriture"
 
-#: utils/ncurses.cpp:564
+#: utils/ncurses.cpp:597
 #, c-format
-msgid "Game saved in %ls"
-msgstr "Partie sauvée dans %ls"
+msgid "Game saved in '%ls'"
+msgstr "Partie sauvée dans '%ls'"
 
-#: utils/ncurses.cpp:575 wxwin/mainframe.cc:268 wxwin/mainframe.cc:389
-#: wxwin/mainframe.cc:413
+#: utils/ncurses.cpp:608 wxwin/mainframe.cc:269 wxwin/mainframe.cc:390
+#: wxwin/mainframe.cc:414
 msgid "Load a game"
 msgstr "Charger une partie"
 
-#: utils/ncurses.cpp:586
+#: utils/ncurses.cpp:619
 #, c-format
-msgid "Cannot open file %ls for reading"
-msgstr "Impossible d'ouvrir le fichier %ls en lecture"
+msgid "Cannot open file '%ls' for reading"
+msgstr "Impossible d'ouvrir le fichier '%ls' en lecture"
 
-#: utils/ncurses.cpp:594
+#: utils/ncurses.cpp:627
 #, c-format
 msgid "Invalid saved game"
 msgstr "Partie sauvée invalide"
 
-#: utils/ncurses.cpp:598
+#: utils/ncurses.cpp:632
 #, c-format
 msgid "Game loaded"
 msgstr "Partie chargée"
 
-#: utils/ncurses.cpp:613
+#: utils/ncurses.cpp:647
 msgid "Pass your turn"
 msgstr "Passer son tour"
 
-#: utils/ncurses.cpp:614
+#: utils/ncurses.cpp:648
 msgid "Enter the letters to change:"
 msgstr "Entrer les lettres à changer:"
 
-#: utils/ncurses.cpp:623
+#: utils/ncurses.cpp:657
 msgid "Cannot pass the turn"
 msgstr "Impossible de passer le tour"
 
-#: utils/ncurses.cpp:633
+#: utils/ncurses.cpp:667
 msgid "Set rack"
 msgstr "Choix du tirage"
 
-#: utils/ncurses.cpp:634
+#: utils/ncurses.cpp:668
 msgid "Enter the new letters:"
 msgstr "Entrer les nouvelles lettres:"
 
-#: utils/ncurses.cpp:643
+#: utils/ncurses.cpp:677
 msgid "Cannot take these letters from the bag"
 msgstr "Impossible de retirer ces lettres du sac"
 
-#: utils/ncurses.cpp:1037
+#: utils/ncurses.cpp:1071
 msgid "Training mode"
 msgstr "Mode entraînement"
 
-#: utils/ncurses.cpp:1039
+#: utils/ncurses.cpp:1073
 msgid "Free game mode"
 msgstr "Mode partie libre"
 
-#: utils/ncurses.cpp:1041
+#: utils/ncurses.cpp:1075
 msgid "Duplicate mode"
 msgstr "Mode duplicate"
 
-#: utils/ncurses.cpp:1044
+#: utils/ncurses.cpp:1078
 msgid "Joker game"
 msgstr "Partie joker"
 
-#: utils/ncurses.cpp:1045
+#: utils/ncurses.cpp:1079
 msgid "[h for help]"
 msgstr "[h pour l'aide]"
 
@@ -577,8 +581,8 @@
 msgid "Copy"
 msgstr "Copier"
 
-#: wxwin/auxframes.cc:348 wxwin/mainframe.cc:491 wxwin/mainframe.cc:511
-#: wxwin/mainframe.cc:542
+#: wxwin/auxframes.cc:348 wxwin/mainframe.cc:487 wxwin/mainframe.cc:507
+#: wxwin/mainframe.cc:538
 msgid "No on going game"
 msgstr "Pas de partie en cours"
 
@@ -590,11 +594,11 @@
 msgid "Rack: "
 msgstr "Tirage :"
 
-#: wxwin/auxframes.cc:525 wxwin/mainframe.cc:318
+#: wxwin/auxframes.cc:525 wxwin/mainframe.cc:319
 msgid "Game history"
 msgstr "Historique de la partie"
 
-#: wxwin/auxframes.cc:557 wxwin/mainframe.cc:320
+#: wxwin/auxframes.cc:557 wxwin/mainframe.cc:321
 msgid "Results"
 msgstr "Résultats"
 
@@ -706,7 +710,7 @@
 msgid "Nb"
 msgstr "Num"
 
-#: wxwin/configdb.cc:323 wxwin/mainframe.cc:173
+#: wxwin/configdb.cc:323 wxwin/mainframe.cc:174
 msgid "Rack"
 msgstr "Tirage"
 
@@ -742,396 +746,396 @@
 msgid "Results of the search"
 msgstr "Résultats de la recherche"
 
-#: wxwin/mainframe.cc:204
+#: wxwin/mainframe.cc:205
 msgid " Rack "
 msgstr " Tirage "
 
-#: wxwin/mainframe.cc:205
+#: wxwin/mainframe.cc:206
 msgid " Complement "
 msgstr " Complément "
 
-#: wxwin/mainframe.cc:206
+#: wxwin/mainframe.cc:207
 msgid " Search "
 msgstr " Rechercher "
 
-#: wxwin/mainframe.cc:207
+#: wxwin/mainframe.cc:208
 msgid " Back "
 msgstr " Arrière "
 
-#: wxwin/mainframe.cc:208
+#: wxwin/mainframe.cc:209
 msgid " Play "
 msgstr " Jouer "
 
-#: wxwin/mainframe.cc:210
+#: wxwin/mainframe.cc:211
 msgid "Random rack"
 msgstr "Tirage aléatoire"
 
-#: wxwin/mainframe.cc:211
+#: wxwin/mainframe.cc:212
 msgid "Random complement of the rack"
 msgstr "Complément aléatoire du tirage"
 
-#: wxwin/mainframe.cc:212
+#: wxwin/mainframe.cc:213
 msgid "Search with the current rack"
 msgstr "Recherche sur le tirage courant"
 
-#: wxwin/mainframe.cc:213
+#: wxwin/mainframe.cc:214
 msgid "Go back one turn"
 msgstr "Revenir un coup en arrière"
 
-#: wxwin/mainframe.cc:214
+#: wxwin/mainframe.cc:215
 msgid "Play the selected word"
 msgstr "Jouer le mot selectionné"
 
-#: wxwin/mainframe.cc:265
+#: wxwin/mainframe.cc:266
 msgid "&New game\tctrl+n"
 msgstr "&Nouvelle partie\tctrl+n"
 
-#: wxwin/mainframe.cc:265
+#: wxwin/mainframe.cc:266
 msgid "Start a new game"
 msgstr "Démarrer une nouvelle partie"
 
-#: wxwin/mainframe.cc:266
+#: wxwin/mainframe.cc:267
 msgid "New &joker game\tctrl+j"
 msgstr "Nouvelle partie &joker\tctrl+j"
 
-#: wxwin/mainframe.cc:266
+#: wxwin/mainframe.cc:267
 msgid "Start a new joker game"
 msgstr "Démarrer une nouvelle partie joker"
 
-#: wxwin/mainframe.cc:268
+#: wxwin/mainframe.cc:269
 msgid "&Load...\tctrl+l"
 msgstr "&Charger...\tctrl+l"
 
-#: wxwin/mainframe.cc:269
+#: wxwin/mainframe.cc:270
 msgid "&Save as...\tctrl+s"
 msgstr "&Enregistrer sous...\tctrl+s"
 
-#: wxwin/mainframe.cc:269
+#: wxwin/mainframe.cc:270
 msgid "Save the current game"
 msgstr "Sauvegarder la partie en cours"
 
-#: wxwin/mainframe.cc:271
+#: wxwin/mainframe.cc:272
 msgid "&Print...\tctrl+p"
 msgstr "&Imprimer...\tctrl+p"
 
-#: wxwin/mainframe.cc:271
+#: wxwin/mainframe.cc:272
 msgid "Print this game"
 msgstr "Imprimer la partie en cours"
 
-#: wxwin/mainframe.cc:272
+#: wxwin/mainframe.cc:273
 msgid "Print pre&view..."
 msgstr "&Aperçu avant impression..."
 
-#: wxwin/mainframe.cc:272
+#: wxwin/mainframe.cc:273
 msgid "Print preview of the game"
 msgstr "Aperçu avant impression de la partie"
 
-#: wxwin/mainframe.cc:274
+#: wxwin/mainframe.cc:275
 msgid "Print in PostS&cript..."
 msgstr "Imprimer au format &PostScript..."
 
-#: wxwin/mainframe.cc:274
+#: wxwin/mainframe.cc:275
 msgid "Print in a PostScript file"
 msgstr "Imprimer dans un fichier PostScript"
 
-#: wxwin/mainframe.cc:277
+#: wxwin/mainframe.cc:278
 msgid "&Quit"
 msgstr "&Quitter"
 
-#: wxwin/mainframe.cc:277
+#: wxwin/mainframe.cc:278
 msgid "Quit Eliot"
 msgstr "Quitter Eliot"
 
-#: wxwin/mainframe.cc:280
+#: wxwin/mainframe.cc:281
 msgid "&Dictionary..."
 msgstr "&Dictionnaire..."
 
-#: wxwin/mainframe.cc:280 wxwin/mainframe.cc:593
+#: wxwin/mainframe.cc:281 wxwin/mainframe.cc:589
 msgid "Choose a dictionary"
 msgstr "Choisir un dictionnaire"
 
-#: wxwin/mainframe.cc:281
+#: wxwin/mainframe.cc:282
 msgid "&Search..."
 msgstr "&Recherche..."
 
-#: wxwin/mainframe.cc:281
+#: wxwin/mainframe.cc:282
 msgid "Search options"
 msgstr "Options de recherche"
 
-#: wxwin/mainframe.cc:284
+#: wxwin/mainframe.cc:285
 msgid "&Background..."
 msgstr "&Fond..."
 
-#: wxwin/mainframe.cc:284
+#: wxwin/mainframe.cc:285
 msgid "Background color"
 msgstr "Couleur de fond"
 
-#: wxwin/mainframe.cc:285
+#: wxwin/mainframe.cc:286
 msgid "L&ines..."
 msgstr "L&ignes..."
 
-#: wxwin/mainframe.cc:285
+#: wxwin/mainframe.cc:286
 msgid "Color of the lines"
 msgstr "Couleur des lignes"
 
-#: wxwin/mainframe.cc:287
+#: wxwin/mainframe.cc:288
 msgid "&Played letters..."
 msgstr "Lettres &jouées..."
 
-#: wxwin/mainframe.cc:287
+#: wxwin/mainframe.cc:288
 msgid "Color of the letters played on the board"
 msgstr "Couleur des lettres jouées sur la grille"
 
-#: wxwin/mainframe.cc:288
+#: wxwin/mainframe.cc:289
 msgid "&Temporary letters..."
 msgstr "Lettres &temporaires..."
 
-#: wxwin/mainframe.cc:288
+#: wxwin/mainframe.cc:289
 msgid "Color of the letters of the temporary word"
 msgstr "Couleur des lettres du mot temporaire"
 
-#: wxwin/mainframe.cc:289
+#: wxwin/mainframe.cc:290
 msgid "B&ackground of played letters..."
 msgstr "Fo&nd des lettres jouées..."
 
-#: wxwin/mainframe.cc:289
+#: wxwin/mainframe.cc:290
 msgid "Background color of the letters played on the board"
 msgstr "Couleur de fond des lettres jouées sur la grille"
 
-#: wxwin/mainframe.cc:290
+#: wxwin/mainframe.cc:291
 msgid "Ba&ckground of temporary letters..."
 msgstr "Fon&d des lettres temporaires..."
 
-#: wxwin/mainframe.cc:290
+#: wxwin/mainframe.cc:291
 msgid "Background color of the temporary letters on the board"
 msgstr "Couleur de fond des lettres temporaires sur la grille"
 
-#: wxwin/mainframe.cc:292
+#: wxwin/mainframe.cc:293
 msgid "Double &letter..."
 msgstr "&Lettre compte double..."
 
-#: wxwin/mainframe.cc:292
+#: wxwin/mainframe.cc:293
 msgid "Color of the \"double letter\" squares"
 msgstr "Couleur des cases \"mot compte double\""
 
-#: wxwin/mainframe.cc:293
+#: wxwin/mainframe.cc:294
 msgid "Triple l&etter..."
 msgstr "L&ettre compte triple..."
 
-#: wxwin/mainframe.cc:293
+#: wxwin/mainframe.cc:294
 msgid "Color of the \"triple letter\" squares"
 msgstr "Couleur des cases \"mot compte triple\""
 
-#: wxwin/mainframe.cc:294
+#: wxwin/mainframe.cc:295
 msgid "Double &word..."
 msgstr "&Mot compte double..."
 
-#: wxwin/mainframe.cc:294
+#: wxwin/mainframe.cc:295
 msgid "Color of the \"double word\" squares"
 msgstr "Couleur des cases \"mot compte double\""
 
-#: wxwin/mainframe.cc:295
+#: wxwin/mainframe.cc:296
 msgid "Triple w&ord..."
 msgstr "M&ot compte triple..."
 
-#: wxwin/mainframe.cc:295
+#: wxwin/mainframe.cc:296
 msgid "Color of the \"triple word\" squares"
 msgstr "Couleur des cases \"mot compte triple\""
 
-#: wxwin/mainframe.cc:297
+#: wxwin/mainframe.cc:298
 msgid "&Default colors"
 msgstr "&Couleurs d'origine"
 
-#: wxwin/mainframe.cc:297
+#: wxwin/mainframe.cc:298
 msgid "Restore the default colors"
 msgstr "Restaurer les couleurs d'origine"
 
-#: wxwin/mainframe.cc:300
+#: wxwin/mainframe.cc:301
 msgid "&Search letters..."
 msgstr "&Lettres de recherche..."
 
-#: wxwin/mainframe.cc:300
+#: wxwin/mainframe.cc:301
 msgid "Font for the search"
 msgstr "Police de caractères pour la recherche"
 
-#: wxwin/mainframe.cc:303 wxwin/mainframe.cc:327
+#: wxwin/mainframe.cc:304 wxwin/mainframe.cc:328
 msgid "&Game"
 msgstr "&Partie"
 
-#: wxwin/mainframe.cc:303
+#: wxwin/mainframe.cc:304
 msgid "Configuration of the game"
 msgstr "Configuration de la partie"
 
-#: wxwin/mainframe.cc:304
+#: wxwin/mainframe.cc:305
 msgid "&Fonts"
 msgstr "P&olices de caractères"
 
-#: wxwin/mainframe.cc:304
+#: wxwin/mainframe.cc:305
 msgid "Configuration of the fonts"
 msgstr "Configuration des polices de caractères"
 
-#: wxwin/mainframe.cc:305
+#: wxwin/mainframe.cc:306
 msgid "&Colors"
 msgstr "&Couleurs"
 
-#: wxwin/mainframe.cc:305
+#: wxwin/mainframe.cc:306
 msgid "Configuration of the colors"
 msgstr "Configuration des couleurs"
 
-#: wxwin/mainframe.cc:306
+#: wxwin/mainframe.cc:307
 msgid "&Printing..."
 msgstr "&Impression..."
 
-#: wxwin/mainframe.cc:306
+#: wxwin/mainframe.cc:307
 msgid "Configuration of the printing parameters"
 msgstr "Configuration des paramètres d'impression"
 
-#: wxwin/mainframe.cc:309
+#: wxwin/mainframe.cc:310
 msgid "&Board"
 msgstr "&Grille"
 
-#: wxwin/mainframe.cc:309
+#: wxwin/mainframe.cc:310
 msgid "Game board"
 msgstr "Plateau de jeu"
 
-#: wxwin/mainframe.cc:310
+#: wxwin/mainframe.cc:311
 msgid "Ba&g"
 msgstr "&Sac"
 
-#: wxwin/mainframe.cc:310
+#: wxwin/mainframe.cc:311
 msgid "Remaining letters in the bag"
 msgstr "Lettres restantes dans le sac"
 
-#: wxwin/mainframe.cc:311
+#: wxwin/mainframe.cc:312
 msgid "&Check"
 msgstr "&Vérification"
 
-#: wxwin/mainframe.cc:311
+#: wxwin/mainframe.cc:312
 msgid "Check a word in the dictionary"
 msgstr "Vérifier l'existence d'un mot dans le dictionnaire"
 
-#: wxwin/mainframe.cc:312
+#: wxwin/mainframe.cc:313
 msgid "&Search"
 msgstr "&Recherche"
 
-#: wxwin/mainframe.cc:312
+#: wxwin/mainframe.cc:313
 msgid "Search in the dictionary"
 msgstr "Recherche dans le dictionnaire"
 
-#: wxwin/mainframe.cc:314
+#: wxwin/mainframe.cc:315
 msgid "&Rack + 1"
 msgstr "&Tirage + 1"
 
-#: wxwin/mainframe.cc:314
+#: wxwin/mainframe.cc:315
 msgid "Letters of the rack plus one"
 msgstr "Lettres du tirage plus une"
 
-#: wxwin/mainframe.cc:315
+#: wxwin/mainframe.cc:316
 msgid "R&accords"
 msgstr "R&accords"
 
-#: wxwin/mainframe.cc:315
+#: wxwin/mainframe.cc:316
 msgid "Raccords on a word of the search"
 msgstr "Raccords sur un mot de la recherche"
 
-#: wxwin/mainframe.cc:316
+#: wxwin/mainframe.cc:317
 msgid "&Benjamins"
 msgstr "&Benjamins"
 
-#: wxwin/mainframe.cc:316
+#: wxwin/mainframe.cc:317
 msgid "Benjamins on a word of the search"
 msgstr "Benjamins sur un mot de la recherche"
 
-#: wxwin/mainframe.cc:318
+#: wxwin/mainframe.cc:319
 msgid "Game &history"
 msgstr "&Historique de la partie"
 
-#: wxwin/mainframe.cc:320
+#: wxwin/mainframe.cc:321
 msgid "R&esults"
 msgstr "Ré&sultats"
 
-#: wxwin/mainframe.cc:324
+#: wxwin/mainframe.cc:325
 msgid "&About..."
 msgstr "À &propos..."
 
-#: wxwin/mainframe.cc:324 wxwin/mainframe.cc:722
+#: wxwin/mainframe.cc:325 wxwin/mainframe.cc:718
 msgid "About Eliot"
 msgstr "À propos d'Eliot"
 
-#: wxwin/mainframe.cc:328
+#: wxwin/mainframe.cc:329
 msgid "&Settings"
 msgstr "&Paramètres"
 
-#: wxwin/mainframe.cc:329
+#: wxwin/mainframe.cc:330
 msgid "&Windows"
 msgstr "&Fenêtres"
 
-#: wxwin/mainframe.cc:330
+#: wxwin/mainframe.cc:331
 msgid "&Help"
 msgstr "&Aide"
 
-#: wxwin/mainframe.cc:354 wxwin/mainframe.cc:392
+#: wxwin/mainframe.cc:355 wxwin/mainframe.cc:393
 msgid "No dictionary selected"
 msgstr "Pas de dictionnaire sélectionné"
 
-#: wxwin/mainframe.cc:354 wxwin/mainframe.cc:392 wxwin/mainframe.cc:491
-#: wxwin/mainframe.cc:511 wxwin/mainframe.cc:542
+#: wxwin/mainframe.cc:355 wxwin/mainframe.cc:393 wxwin/mainframe.cc:487
+#: wxwin/mainframe.cc:507 wxwin/mainframe.cc:538
 msgid "Eliot: error"
 msgstr "Eliot : erreur"
 
-#: wxwin/mainframe.cc:412
+#: wxwin/mainframe.cc:413
 msgid "Cannot open "
 msgstr "Impossible d'ouvrir "
 
-#: wxwin/mainframe.cc:424 wxwin/mainframe.cc:433
+#: wxwin/mainframe.cc:425 wxwin/mainframe.cc:434
 msgid "Error while loading the game"
 msgstr "Erreur pendant le chargement de la partie"
 
-#: wxwin/mainframe.cc:425
+#: wxwin/mainframe.cc:426
 msgid "Invalid game"
 msgstr "Partie invalide"
 
-#: wxwin/mainframe.cc:434
+#: wxwin/mainframe.cc:435
 msgid "The game is empty"
 msgstr "La partie est vide"
 
-#: wxwin/mainframe.cc:471
+#: wxwin/mainframe.cc:467
 msgid "Cannot create "
 msgstr "Impossible de créer "
 
-#: wxwin/mainframe.cc:500 wxwin/mainframe.cc:564
+#: wxwin/mainframe.cc:496 wxwin/mainframe.cc:560
 msgid "Printing not done"
 msgstr "Impression non effectuée"
 
-#: wxwin/mainframe.cc:500 wxwin/mainframe.cc:528
+#: wxwin/mainframe.cc:496 wxwin/mainframe.cc:524
 msgid "Printing"
 msgstr "Impression"
 
-#: wxwin/mainframe.cc:523
+#: wxwin/mainframe.cc:519
 msgid "Print preview problem.\n"
 msgstr "Problème avec l'aperçu avant impression.\n"
 
-#: wxwin/mainframe.cc:524
+#: wxwin/mainframe.cc:520
 msgid "The printer may not be correctly initialized"
 msgstr "Il se peut que l'imprimante soit mal initialisée"
 
-#: wxwin/mainframe.cc:525
+#: wxwin/mainframe.cc:521
 msgid "Print preview"
 msgstr "Aperçu avant impression"
 
-#: wxwin/mainframe.cc:546
+#: wxwin/mainframe.cc:542
 msgid "Print to a PostScript file"
 msgstr "Imprimer dans un fichier PostScript"
 
-#: wxwin/mainframe.cc:565 wxwin/mainframe.cc:571
+#: wxwin/mainframe.cc:561 wxwin/mainframe.cc:567
 msgid "PostScript printing"
 msgstr "Impression PostScript"
 
-#: wxwin/mainframe.cc:570
+#: wxwin/mainframe.cc:566
 msgid "Cannot initialize PostScript printer"
 msgstr "Impossible d'initialiser l'impression PostScript"
 
-#: wxwin/mainframe.cc:718
+#: wxwin/mainframe.cc:714
 msgid ""
 "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 "
@@ -1143,15 +1147,15 @@
 "publiée par la Free Software Fundation ; soit la version 2 de la Licence, "
 "soit (comme vous le préférez), n'importe quelle version ultérieure."
 
-#: wxwin/mainframe.cc:916
+#: wxwin/mainframe.cc:912
 msgid "turn:"
 msgstr "coup :"
 
-#: wxwin/mainframe.cc:917
+#: wxwin/mainframe.cc:913
 msgid "points:"
 msgstr "points :"
 
-#: wxwin/mainframe.cc:954
+#: wxwin/mainframe.cc:948
 msgid ""
 "The bag doesn't contain enough letters\n"
 "for a new rack."
@@ -1159,40 +1163,45 @@
 "Le sac ne contient pas assez de lettres\n"
 "pour un nouveau tirage."
 
-#: wxwin/mainframe.cc:955 wxwin/mainframe.cc:959 wxwin/mainframe.cc:963
+#: wxwin/mainframe.cc:949 wxwin/mainframe.cc:953 wxwin/mainframe.cc:957
 msgid "Rack validation"
 msgstr "Validation du tirage"
 
-#: wxwin/mainframe.cc:958
+#: wxwin/mainframe.cc:952
 msgid "The rack must contain at least 2 consonants and 2 vowels."
 msgstr "Le tirage doit contenir au moins 2 consonnes et 2 voyelles."
 
-#: wxwin/mainframe.cc:962
+#: wxwin/mainframe.cc:956
 msgid "The rack contains invalid letters for the current dictionary"
 msgstr ""
 "Le tirage contient des lettres incorrectes pour le dictionnaire courant"
 
-#: wxwin/mainframe.cc:966
+#: wxwin/mainframe.cc:960
 msgid "The rack has been modified manually"
 msgstr "Le tirage a été modifié manuellement"
 
-#: wxwin/searchpanel.cc:303
+#: wxwin/searchpanel.cc:146 wxwin/searchpanel.cc:190
+#, c-format
+msgid "The search is limited to %d letters"
+msgstr "La recherche est limitée à %d lettres"
+
+#: wxwin/searchpanel.cc:301
 msgid "Minimum length"
 msgstr "Longueur minimum"
 
-#: wxwin/searchpanel.cc:305
+#: wxwin/searchpanel.cc:303
 msgid "Maximum length"
 msgstr "Longueur maximum"
 
-#: wxwin/searchpanel.cc:368
+#: wxwin/searchpanel.cc:366
 msgid "Cross words"
 msgstr "Mots croisés"
 
-#: wxwin/searchpanel.cc:369
+#: wxwin/searchpanel.cc:367
 msgid "Plus 1"
 msgstr "Plus 1"
 
-#: wxwin/searchpanel.cc:370
+#: wxwin/searchpanel.cc:368
 msgid "Regular expressions"
 msgstr "Expressions régulières"
 

Index: test/freegame_change.input
===================================================================
RCS file: /cvsroot/eliot/eliot/test/freegame_change.input,v
retrieving revision 1.1
retrieving revision 1.1.6.1
diff -u -b -r1.1 -r1.1.6.1
--- test/freegame_change.input  16 Apr 2005 15:47:59 -0000      1.1
+++ test/freegame_change.input  23 Dec 2007 23:12:45 -0000      1.1.6.1
@@ -10,6 +10,7 @@
 a T
 p KEEEAAI
 a T
+a p
 q
 q
 

Index: test/freegame_change.ref
===================================================================
RCS file: /cvsroot/eliot/eliot/test/freegame_change.ref,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -u -b -r1.2 -r1.2.4.1
--- test/freegame_change.ref    24 Dec 2005 17:50:11 -0000      1.2
+++ test/freegame_change.ref    23 Dec 2007 23:12:45 -0000      1.2.4.1
@@ -25,6 +25,24 @@
 commande> a T
 Joueur 0: EENNTOD
 Joueur 1: UNLEUSS
+commande> a p
+Eliot 1.5
+
+Game type: Free game
+Player 0: Human
+Player 1: Human
+
+    N |   RACK   |    SOLUTION     | REF | PTS | P | BONUS
+   ===|==========|=================|=====|=====|===|======
+    1 |  NEIJEDN | (-JID)          |  -  |   0 | 0 |
+    2 |  UUEALEO | (-AUOUEL)       |  -  |   0 | 1 |
+    3 | EENN+WTA | (-WA)           |  -  |   0 | 0 |
+    4 | E+EAKEIA | (-KEEEAAI)      |  -  |   0 | 1 |
+
+   Total: 0
+
+Rack 0: EENNT+OD
+Rack 1: UNLEUSS
 commande> q
 fin du mode partie libre
 commande> q

Index: test/freegame_passing.ref
===================================================================
RCS file: /cvsroot/eliot/eliot/test/freegame_passing.ref,v
retrieving revision 1.3.2.1
retrieving revision 1.3.2.2
diff -u -b -r1.3.2.1 -r1.3.2.2
--- test/freegame_passing.ref   14 Dec 2007 18:12:33 -0000      1.3.2.1
+++ test/freegame_passing.ref   23 Dec 2007 23:12:45 -0000      1.3.2.2
@@ -47,29 +47,52 @@
 
     N |   RACK   |    SOLUTION     | REF | PTS | P | BONUS
    ===|==========|=================|=====|=====|===|======
-    1 |  RENLOHL | HERON           |  H4 |  24 | 1 |  
-    2 | LL+XUORC | OCREUX          |  5E |  34 | 1 |  
-    3 | LL+NAECT | CALLENT         |  I7 |  73 | 1 | *
-    4 |  ?EMTOEO | ENTOlOME        | 12H |  70 | 1 | *
-    5 |  MLZESLS | MEZES           | O11 |  45 | 1 |  
-    6 | LLS+IUEG | GOUILLES        |  E4 |  68 | 1 | *
-    7 |  TVAWLAE | AWELE           | 10A |  34 | 1 |  
-    8 | ATV+PUFA | PAVAT           |  A7 |  30 | 1 |  
-    9 | AFU+AIAE | FA              |  G7 |  24 | 1 |  
-   10 | AAEIU+YU | YEUX            |  J2 |  42 | 1 |  
-   11 | AAIU+TEN | NEZ             | 13M |  31 | 1 |  
-   12 | AAITU+IR | AUTRE           | 14K |  21 | 1 |  
-   13 | AII+MPNA | PAMAI           | 15G |  26 | 1 |  
-   14 | IN+IUURE | TUNES           | 11A |  20 | 1 |  
-   15 | IIRU+RNF | NIF             | 11K |  24 | 1 |  
-   16 | IRRU+OEI | HOUER           |  4H |  18 | 1 |  
-   17 | IIRU+TSE | YETIS           |  2J |  28 | 1 |  
-   18 | IRU+ETHO | HERE            |  3I |  27 | 1 |  
-   19 | IOTU+?JN | SUJeTION        |  N2 |  66 | 1 | *
-   20 |  SEVDQIR | DEVENIRS        |  C7 |  36 | 1 |  
-   21 | Q+BAKIAE | KABIG           |  4A |  54 | 1 |  
-   22 |      AEQ | QUE             |  6D |  18 | 1 |  
-   23 |        A | KA              |  A4 |  11 | 1 |  
+    1 |  TISSUEG | (PASS)          |  -  |   0 | 0 |
+    2 |  RENLOHL | HERON           |  H4 |  24 | 1 |  
+    3 |  EGISSTU | (PASS)          |  -  |   0 | 0 |
+    4 | LL+XUORC | OCREUX          |  5E |  34 | 1 |  
+    5 |  EGISSTU | (-UIET)         |  -  |   0 | 0 |
+    6 | LL+NAECT | CALLENT         |  I7 |  73 | 1 | *
+    7 | GSS+DIDB | (PASS)          |  -  |   0 | 0 |
+    8 |  ?EMTOEO | ENTOlOME        | 12H |  70 | 1 | *
+    9 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   10 |  MLZESLS | MEZES           | O11 |  45 | 1 |  
+   11 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   12 | LLS+IUEG | GOUILLES        |  E4 |  68 | 1 | *
+   13 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   14 |  TVAWLAE | AWELE           | 10A |  34 | 1 |  
+   15 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   16 | ATV+PUFA | PAVAT           |  A7 |  30 | 1 |  
+   17 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   18 | AFU+AIAE | FA              |  G7 |  24 | 1 |  
+   19 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   20 | AAEIU+YU | YEUX            |  J2 |  42 | 1 |  
+   21 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   22 | AAIU+TEN | NEZ             | 13M |  31 | 1 |  
+   23 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   24 | AAITU+IR | AUTRE           | 14K |  21 | 1 |  
+   25 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   26 | AII+MPNA | PAMAI           | 15G |  26 | 1 |  
+   27 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   28 | IN+IUURE | TUNES           | 11A |  20 | 1 |  
+   29 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   30 | IIRU+RNF | NIF             | 11K |  24 | 1 |  
+   31 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   32 | IRRU+OEI | HOUER           |  4H |  18 | 1 |  
+   33 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   34 | IIRU+TSE | YETIS           |  2J |  28 | 1 |  
+   35 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   36 | IRU+ETHO | HERE            |  3I |  27 | 1 |  
+   37 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   38 | IOTU+?JN | SUJeTION        |  N2 |  66 | 1 | *
+   39 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   40 |  SEVDQIR | DEVENIRS        |  C7 |  36 | 1 |  
+   41 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   42 | Q+BAKIAE | KABIG           |  4A |  54 | 1 |  
+   43 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   44 |      AEQ | QUE             |  6D |  18 | 1 |  
+   45 |  BDDGISS | (PASS)          |  -  |   0 | 0 |
+   46 |        A | KA              |  A4 |  11 | 1 |  
 
    Total: 824
 

Index: utils/eliottxt.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/utils/eliottxt.cpp,v
retrieving revision 1.16.2.10
retrieving revision 1.16.2.11
diff -u -b -r1.16.2.10 -r1.16.2.11
--- utils/eliottxt.cpp  5 Dec 2007 10:36:00 -0000       1.16.2.10
+++ utils/eliottxt.cpp  23 Dec 2007 23:12:45 -0000      1.16.2.11
@@ -643,7 +643,7 @@
                     if (token == NULL)
                         token = L"";
 
-                    if (iGame.pass(token, iGame.currPlayer()) != 0)
+                    if (iGame.pass(token) != 0)
                         break;
                     break;
                 case L's':
@@ -744,10 +744,14 @@
                         help_duplicate();
                     else
                     {
+                        int n = _wtoi(token);
+                        if (n < 0 || n >= (int)iGame.getNPlayers())
+                        {
+                            fprintf(stderr, "Numéro de joueur invalide\n");
+                            break;
+                        }
                         int res = iGame.setPlayer(_wtoi(token));
                         if (res == 1)
-                            fprintf(stderr, "Numéro de joueur invalide\n");
-                        else if (res == 2)
                             fprintf(stderr, "Impossible de choisir un joueur 
non humain\n");
                     }
                     break;

Index: utils/ncurses.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/utils/ncurses.cpp,v
retrieving revision 1.22.2.11
retrieving revision 1.22.2.12
diff -u -b -r1.22.2.11 -r1.22.2.12
--- utils/ncurses.cpp   20 Dec 2007 08:47:10 -0000      1.22.2.11
+++ utils/ncurses.cpp   23 Dec 2007 23:12:45 -0000      1.22.2.12
@@ -358,7 +358,11 @@
          i < (int)m_game->getHistory().getSize() && i < ioBox.getLastLine(); 
i++)
     {
         const Turn& t = m_game->getHistory().getTurn(i);
-        const Round& r = t.getRound();
+        const Move& m = t.getMove();
+        if (m.getType() == Move::VALID_ROUND)
+        {
+            // The move corresponds to a played round: display it
+            const Round &r = m.getRound();
         wstring coord = r.getCoord().toString();
         ioBox.printDataLine(i, x,
             " %2d   %s   %s   %s   %3d   %1d   %c",
@@ -367,6 +371,33 @@
             padAndConvert(coord, 3).c_str(), r.getPoints(),
             t.getPlayer(), r.getBonus() ? '*' : ' ');
     }
+        else if (m.getType() == Move::INVALID_WORD)
+        {
+            // The move corresponds to an invalid word: display it
+            wstring invWord = L"<" + m.getBadWord() + L">";
+            ioBox.printDataLine(i, x,
+                " %2d   %s   %s   %s   %3d   %1d",
+                i + 1, padAndConvert(t.getPlayedRack().toString(), 8).c_str(),
+                padAndConvert(invWord, 15, false).c_str(),
+                padAndConvert(m.getBadCoord(), 3).c_str(), m.getScore(),
+                t.getPlayer());
+        }
+        else
+        {
+            // The move corresponds to a passed turn or changed letters
+            wstring action;
+            if (m.getType() == Move::PASS)
+                action = convertToWc(_("(PASS)"));
+            else if (m.getType() == Move::CHANGE_LETTERS)
+                action = L"(-" + m.getChangedLetters() + L")";
+
+            ioBox.printDataLine(i, x,
+                " %2d   %s   %s   %s   %3d   %1d",
+                i + 1, padAndConvert(t.getPlayedRack().toString(), 8).c_str(),
+                padAndConvert(action, 15, false).c_str(),
+                " - ", m.getScore(), t.getPlayer());
+        }
+    }
     int nbLines = min(i + 2 - ioBox.getFirstLine(),
                       ioBox.getLastLine() - ioBox.getFirstLine() + 2);
     mvwvline(m_win, y, x + 4,  ACS_VLINE, nbLines);
@@ -620,7 +651,7 @@
     wstring letters;
     if (readString(win, y + 2, x + 2, 7, letters))
     {
-        int res = iGame.pass(letters, m_game->currPlayer());
+        int res = iGame.pass(letters);
         if (res)
         {
             drawStatus(win, _("Cannot pass the turn"));

Index: wxwin/mainframe.cc
===================================================================
RCS file: /cvsroot/eliot/eliot/wxwin/mainframe.cc,v
retrieving revision 1.21.2.9
retrieving revision 1.21.2.10
diff -u -b -r1.21.2.9 -r1.21.2.10
--- wxwin/mainframe.cc  20 Dec 2007 08:47:10 -0000      1.21.2.9
+++ wxwin/mainframe.cc  23 Dec 2007 23:12:46 -0000      1.21.2.10
@@ -929,7 +929,6 @@
 void
 MainFrame::SetRack(Game::set_rack_mode mode, wxString srack)
 {
-    int res = 0;
     wxString msg;
     bool check = config.getRackChecking();
 
@@ -938,8 +937,7 @@
         return;
     }
     static_cast<Training*>(m_game)->removeTestPlay();
-    std::wstring str = srack.c_str();
-    res = static_cast<Training*>(m_game)->setRack(mode, check, str);
+    int res = static_cast<Training*>(m_game)->setRack(mode, check, 
srack.c_str());
 
     switch (res)
     {

Index: wxwin/printout.cc
===================================================================
RCS file: /cvsroot/eliot/eliot/wxwin/printout.cc,v
retrieving revision 1.10.4.1
retrieving revision 1.10.4.2
diff -u -b -r1.10.4.1 -r1.10.4.2
--- wxwin/printout.cc   11 Nov 2007 19:57:01 -0000      1.10.4.1
+++ wxwin/printout.cc   23 Dec 2007 23:12:46 -0000      1.10.4.2
@@ -176,14 +176,14 @@
     DIM(2);
     if ((numline > 0) && (numline <= NRounds))
     {
-        str = wxU(m_game.getHistory().getTurn(numline - 
1).getRound().getWord().c_str());
+        str = wxU(m_game.getHistory().getTurn(numline - 
1).getMove().getRound().getWord().c_str());
         DRW(2);
     }
     // pos
     DIM(3);
     if ((numline > 0) && (numline <= NRounds))
     {
-        str = wxU(m_game.getHistory().getTurn(numline - 
1).getRound().getCoord().toString().c_str());
+        str = wxU(m_game.getHistory().getTurn(numline - 
1).getMove().getRound().getCoord().toString().c_str());
         DRW(3);
     }
     // pts
@@ -191,7 +191,7 @@
     if ((numline > 0) && (numline <= NRounds))
     {
         str = wxT("");
-        str << m_game.getHistory().getTurn(numline - 1).getRound().getPoints();
+        str << m_game.getHistory().getTurn(numline - 
1).getMove().getRound().getPoints();
         DRW(4);
     }
     // total points

Index: wxwin/searchpanel.cc
===================================================================
RCS file: /cvsroot/eliot/eliot/wxwin/searchpanel.cc,v
retrieving revision 1.15.2.4
retrieving revision 1.15.2.5
diff -u -b -r1.15.2.4 -r1.15.2.5
--- wxwin/searchpanel.cc        11 Dec 2007 14:07:16 -0000      1.15.2.4
+++ wxwin/searchpanel.cc        23 Dec 2007 23:12:46 -0000      1.15.2.5
@@ -142,9 +142,8 @@
 
     if (t->GetValue().Len() >= DIC_WORD_MAX)
     {
-        wxString msg = wxT("");
-        // XXX:      msg << wxT("La recherche est limitée à ") << DIC_WORD_MAX 
- 1 << wxT(" lettres");
-        msg << wxT("La recherche est limitee a ") << DIC_WORD_MAX - 1 << wxT(" 
lettres");
+        wxString msg;
+        msg.Printf(_("The search is limited to %d letters"), DIC_WORD_MAX - 1);
         l->Append(msg);
         return;
     }
@@ -187,9 +186,8 @@
 
     if (t->GetValue().Len() >= DIC_WORD_MAX)
     {
-        wxString msg = wxT("");
-        // XXX:      msg << wxT("La recherche est limitée à ") << DIC_WORD_MAX 
- 1 << wxT(" lettres");
-        msg << wxT("La recherche est limitee a ") << DIC_WORD_MAX - 1 << wxT(" 
lettres");
+        wxString msg;
+        msg.Printf(_("The search is limited to %d letters"), DIC_WORD_MAX - 1);
         l->Append(msg);
         return;
     }

Index: game/move.cpp
===================================================================
RCS file: game/move.cpp
diff -N game/move.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ game/move.cpp       23 Dec 2007 23:12:43 -0000      1.1.2.1
@@ -0,0 +1,106 @@
+/*****************************************************************************
+ * Copyright (C) 2007 Eliot
+ * Authors: Olivier Teuliere  <address@hidden>
+ *
+ * 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
+ *****************************************************************************/
+
+#include <algorithm>
+#include <wctype.h>
+
+#include "move.h"
+
+
+Move::Move(const Round &iRound)
+    : m_score(0), m_round(iRound)
+{
+    m_type = VALID_ROUND;
+    m_score = m_round.getPoints();
+}
+
+
+Move::Move(const wstring &iWord, const wstring &iCoord)
+    : m_word(iWord), m_coord(iCoord)
+{
+    m_type = INVALID_WORD;
+    m_score = 0;
+}
+
+
+Move::Move(const wstring &iLetters)
+    : m_score(0), m_letters(iLetters)
+{
+    // Make the letters uppercase
+    std::transform(m_letters.begin(), m_letters.end(),
+                   m_letters.begin(), towupper);
+
+    if (m_letters.empty())
+        m_type = PASS;
+    else
+        m_type = CHANGE_LETTERS;
+}
+
+
+const Round & Move::getRound() const
+{
+    if (m_type != VALID_ROUND)
+    {
+        // FIXME: throw an exception object instead
+        throw 1;
+    }
+    return m_round;
+}
+
+
+const wstring & Move::getBadWord() const
+{
+    if (m_type != INVALID_WORD)
+    {
+        // FIXME: throw an exception object instead
+        throw 1;
+    }
+    return m_word;
+}
+
+
+const wstring & Move::getBadCoord() const
+{
+    if (m_type != INVALID_WORD)
+    {
+        // FIXME: throw an exception object instead
+        throw 1;
+    }
+    return m_coord;
+}
+
+
+const wstring & Move::getChangedLetters() const
+{
+    if (m_type != CHANGE_LETTERS &&
+        m_type != PASS)
+    {
+        // FIXME: throw an exception object instead
+        throw 1;
+    }
+    return m_letters;
+}
+
+
+wstring Move::toString() const
+{
+    // TODO
+    return L"";
+}
+

Index: game/move.h
===================================================================
RCS file: game/move.h
diff -N game/move.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ game/move.h 23 Dec 2007 23:12:44 -0000      1.1.2.1
@@ -0,0 +1,133 @@
+/*****************************************************************************
+ * Copyright (C) 2007 Eliot
+ * Authors: Olivier Teuliere  <address@hidden>
+ *
+ * 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
+ *****************************************************************************/
+
+#ifndef _MOVE_H
+#define _MOVE_H
+
+#include <string>
+
+#include "round.h"
+
+using std::wstring;
+
+
+/**
+ * A Move is what a player can do during the game:
+ *  - play a valid word
+ *  - play an invalid or misplaced word
+ *  - pass the turn (freegame only)
+ *  - change letters (freegame only)
+ *  - play nothing (timeout) (not supported yet)
+ *
+ * Moves are useful to record what happened, even if the board doesn't keep
+ * a trace of the move (e.g.: an invalid move which was rejected will still
+ * be remembered in the player history).
+ *
+ * Currently, moves are not used by the interfaces (they are only used
+ * internally), but this could change in the future.
+ */
+class Move
+{
+    public:
+        /**
+         * Constructor taking a (valid) round
+         */
+        explicit Move(const Round &iRound);
+
+        /**
+         * Constructor taking a word and its coordinates, corresponding
+         * to an invalid move by the player (invalid word, invalid coordinates,
+         * letters not corresponding to the rack, ...)
+         */
+        explicit Move(const wstring &iWord, const wstring &iCoord);
+
+        /**
+         * Constructor taking letters to change.
+         * An empty string means that the player simply passes without
+         * changing any letter.
+         * The given letters must have been already validated for correctness.
+         */
+        explicit Move(const wstring &iLetters);
+
+        enum Type
+        {
+            VALID_ROUND,
+            INVALID_WORD,
+            PASS,
+            CHANGE_LETTERS
+        };
+
+        /// Return the type of move
+        Type getType() const { return m_type; }
+
+        /// Get the score of this move (0 unless the round is valid)
+        int getScore() const { return m_score; };
+
+        /**
+         * Return the round associated with the move, or throw an exception
+         * if this move was not constructed from a valid round
+         */
+        const Round & getRound() const;
+
+        /**
+         * Return the word played at this move associated with the move, or
+         * throw an exception if this move was not constructed from an invalid
+         * pair (word, coord)
+         */
+        const wstring & getBadWord() const;
+
+        /**
+         * Return the coordinates of the (incorrect) word played at this move,
+         * or throw an exception if this move was not constructed from an
+         * invalid pair (cord, coord)
+         */
+        const wstring & getBadCoord() const;
+
+        /**
+         * Return the changed letters (possibly an empty string if the player
+         * simply wanted to pass the turn), or throw an exception if this move
+         * does not correspond to a passed turn
+         */
+        const wstring & getChangedLetters() const;
+
+        /// To help debugging
+        wstring toString() const;
+
+    private:
+        /// Type of move
+        Type m_type;
+
+        /// Score associated with this move
+        int m_score;
+
+        /// Round played at this turn
+        Round m_round;
+
+        /// Word played (incorrectly)
+        wstring m_word;
+
+        /// Coordinates of the word played (incorrectly)
+        wstring m_coord;
+
+        /// Changed letters (or empty string for passed turn)
+        wstring m_letters;
+};
+
+#endif
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]