eliot-dev
[Top][All Lists]
Advanced

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

[Eliot-dev] eliot/game game.h game.cpp


From: eliot-dev
Subject: [Eliot-dev] eliot/game game.h game.cpp
Date: Sun, 01 Jan 2006 19:48:36 +0000

CVSROOT:        /cvsroot/eliot
Module name:    eliot
Branch:         
Changes by:     Antoine Fraboulet <address@hidden>      06/01/01 19:48:36

Modified files:
        game           : game.h game.cpp 

Log message:
        - correct helperSetRackRandom with RACK_ALL (replace tiles in bag)
        - add game_io.cpp to load/save a game

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/eliot/eliot/game/game.h.diff?tr1=1.26&tr2=1.27&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/eliot/eliot/game/game.cpp.diff?tr1=1.27&tr2=1.28&r1=text&r2=text

Patches:
Index: eliot/game/game.cpp
diff -u eliot/game/game.cpp:1.27 eliot/game/game.cpp:1.28
--- eliot/game/game.cpp:1.27    Tue Dec 27 15:01:07 2005
+++ eliot/game/game.cpp Sun Jan  1 19:48:36 2006
@@ -63,269 +63,6 @@
 }
 
 
-Game * Game::load(FILE *fin, const Dictionary &iDic)
-{
-    char buff[4096];
-    char delim[] = " \t\n|";
-    char *token;
-
-    // Check characteristic string
-    if (fgets(buff, sizeof(buff), fin) == NULL)
-        return NULL;
-    if ((token = strtok(buff, delim)) == NULL)
-        return NULL;
-    if (string(token) != IDENT_STRING)
-        return NULL;
-
-    int num;
-    char rack[20];
-    char word[20];
-    char ref[4];
-    int pts;
-    int player;
-    char *pos;
-    Tile tile;
-    Game *pGame = NULL;
-
-    while (fgets(buff, sizeof(buff), fin))
-    {
-        // Indication of game type
-        pos = strstr(buff, "Game type: ");
-        if (pos != NULL)
-        {
-            // No Game object should have been created yet
-            if (pGame != NULL)
-            {
-                delete pGame;
-                return NULL;
-            }
-            // Create the correct Game object
-            if (strstr(buff, "Training"))
-                pGame = GameFactory::Instance()->createTraining(iDic);
-            else if (strstr(buff, "Free game"))
-                pGame = GameFactory::Instance()->createFreeGame(iDic);
-            else if (strstr(buff, "Duplicate"))
-                pGame = GameFactory::Instance()->createDuplicate(iDic);
-            else
-                return NULL;
-            // Read next line
-            continue;
-        }
-
-        // Players type
-        pos = strstr(buff, "Player ");
-        if (pos != NULL && pGame != NULL)
-        {
-            int nb = 0;
-            char type[20];
-            if (sscanf(pos, "Player %d: %19s", &nb, type) > 1)
-            {
-                if (string(type) == "Human")
-                    pGame->addHumanPlayer();
-                else if (string(type) == "Computer")
-                    pGame->addAIPlayer();
-                else
-                    ;
-            }
-            // Read next line
-            continue;
-        }
-
-        // Last racks
-        pos = strstr(buff, "Rack ");
-        if (pos != NULL && pGame != NULL)
-        {
-            int nb = 0;
-            char letters[20];
-            if (sscanf(pos, "Rack %d: %19s", &nb, letters) > 1)
-            {
-                // Create the played rack
-                PlayedRack pldrack;
-                char *r = letters;
-                if (strchr(r, '+'))
-                {
-                    while (*r != '+')
-                    {
-                        pldrack.addOld(Tile(*r));
-                        r++;
-                    }
-                    r++;
-                }
-                while (*r)
-                {
-                    pldrack.addNew(Tile(*r));
-                    r++;
-                }
-
-                // Give the rack to the player
-                pGame->m_players[nb]->setCurrentRack(pldrack);
-            }
-            // Read next line
-            continue;
-        }
-
-        // Skip columns title
-        if (strstr(buff, "==") != NULL ||
-            strstr(buff, "| PTS | P |") != NULL)
-        {
-            continue;
-        }
-
-        if (string(buff) != "\n" && pGame != NULL)
-        {
-            char bonus = 0;
-            int res = sscanf(buff, "   %2d | %8s | %s | %3s | %3d | %1d | %c",
-                             &num, rack, word, ref, &pts, &player, &bonus);
-            if (res < 6)
-                continue;
-
-            // Integrity checks
-            // TODO: add more checks
-            if (pts < 0)
-                continue;
-            if (player < 0 || player > pGame->getNPlayers())
-                continue;
-            if (bonus && bonus != '*')
-                continue;
-
-            // Build a rack for the correct player
-            PlayedRack pldrack;
-            char *r = rack;
-            if (strchr(r, '+'))
-            {
-                while (*r != '+')
-                {
-                    pldrack.addOld(Tile(*r));
-                    r++;
-                }
-                r++;
-            }
-
-            while (*r)
-            {
-                pldrack.addNew(Tile(*r));
-                r++;
-            }
-
-            // Build a round
-            Round round;
-            round.accessCoord().setFromString(ref);
-            if (!round.getCoord().isValid())
-                continue;
-
-            round.setPoints(pts);
-            if (bonus == '*')
-                round.setBonus(1);
-
-            for (unsigned int i = 0; i < strlen(word); i++)
-            {
-                tile = Tile(word[i]);
-
-                if (round.getCoord().getDir() == Coord::HORIZONTAL)
-                {
-                    if (!pGame->m_board.getTile(round.getCoord().getRow(),
-                                                round.getCoord().getCol() + 
i).isEmpty())
-                    {
-                        round.addRightFromBoard(tile);
-                    }
-                    else
-                    {
-                        round.addRightFromRack(tile, islower(word[i]));
-                        pGame->m_bag.takeTile((islower(word[i])) ? 
Tile::Joker() : tile);
-                    }
-                }
-                else
-                {
-                    if (!pGame->m_board.getTile(round.getCoord().getRow() + i,
-                                                
round.getCoord().getCol()).isEmpty())
-                    {
-                        round.addRightFromBoard(tile);
-                    }
-                    else
-                    {
-                        round.addRightFromRack(tile, islower(word[i]));
-                        pGame->m_bag.takeTile((islower(word[i])) ? 
Tile::Joker() : tile);
-                    }
-                }
-            }
-
-            pGame->m_currPlayer = player;
-            // Update the rack for the player
-            pGame->m_players[player]->setCurrentRack(pldrack);
-            // End the turn for the current player (this creates a new rack)
-            pGame->m_players[player]->endTurn(round, num - 1);
-            // Add the points
-            pGame->m_players[player]->addPoints(pts);
-            // Play the round
-            pGame->helperPlayRound(round);
-        }
-    }
-
-    // Finalize the game
-    if (pGame)
-    {
-        // We don't really know whose turn it is, but at least we know that
-        // the game was saved while a human was to play.
-        for (int i = 0; i < pGame->getNPlayers(); i++)
-        {
-            if (pGame->getPlayer(i).isHuman())
-            {
-                pGame->m_currPlayer = i;
-                break;
-            }
-        }
-    }
-    return pGame;
-}
-
-
-void Game::save(ostream &out) const
-{
-    const string decal = "   ";
-    // "Header" of the game
-    out << IDENT_STRING << endl << endl;
-    out << "Game type: " << getModeAsString() << endl;
-    for (int i = 0; i < getNPlayers(); i++)
-    {
-        out << "Player " << i << ": ";
-        if (getPlayer(i).isHuman())
-            out << "Human" << endl;
-        else
-            out << "Computer" << endl;
-    }
-    out << endl;
-
-    // Title of the columns
-    char line[100];
-    out << decal << " N |   RACK   |    SOLUTION     | REF | PTS | P | BONUS" 
<< endl;
-    out << decal << "===|==========|=================|=====|=====|===|======" 
<< endl;
-
-    // Print the game itself
-    for (int i = 0; i < m_history.getSize(); i++)
-    {
-        const Turn& t = m_history.getTurn(i);
-        string word = t.getRound().getWord();
-        string coord = t.getRound().getCoord().toString();
-        sprintf(line, "%2d | %8s | %s%s | %3s | %3d | %1d | %c",
-                i + 1, t.getPlayedRack().toString().c_str(), word.c_str(),
-                string(15 - word.size(), ' ').c_str(),
-                coord.c_str(), t.getRound().getPoints(),
-                t.getPlayer(), t.getRound().getBonus() ? '*' : ' ');
-
-        out << decal << line << endl;
-    }
-    out << endl << decal << "Total: " << m_points << endl;
-
-    // Print current rack for all the players
-    out << endl;
-    for (int i = 0; i < getNPlayers(); i++)
-    {
-        string rack = getPlayer(i).getCurrentRack().toString();
-        out << "Rack " << i << ": " << rack << endl;
-    }
-}
-
-
 /* This function plays a round on the board */
 int Game::helperPlayRound(const Round &iRound)
 {
@@ -419,10 +156,10 @@
 
     if (n < 0)
     {
-//         debug("Game::back negative argument\n");
-        n = -n;
+       debug("Game::back negative argument\n");
+       n = -n;
     }
-//     debug("Game::back %d\n",n);
+    debug("Game::back %d\n",n);
     for (i = 0; i < n; i++)
     {
         if (m_history.getSize() > 0)
@@ -430,7 +167,7 @@
             prevPlayer();
             player = m_players[m_currPlayer];
             const Round &lastround = m_history.getPreviousTurn().getRound();
-//             debug("Game::back last round 
%s\n",lastround.toString().c_str());
+           debug("Game::back last round %s\n",lastround.toString().c_str());
             /* Remove the word from the board, and put its letters back
              * into the bag */
             m_board.removeRound(*m_dic, lastround);
@@ -447,8 +184,8 @@
             /* Remove the points of this round */
             player->addPoints(- lastround.getPoints());
             m_points -= lastround.getPoints();
-            /* Remove the turns */
-            player->removeLastTurn();
+           /* Remove the turns */
+           player->removeLastTurn();
             m_history.removeLastTurn();
         }
         else
@@ -459,10 +196,11 @@
     return 0;
 }
 
-
-/*********************************************************
- *********************************************************/
-
+/**
+ * The realBag is the current bag minus all the racks
+ * present in the game. It represents the actual 
+ * letters that are left in the bag.
+ */
 void Game::realBag(Bag &ioBag) const
 {
     vector<Tile> tiles;
@@ -473,7 +211,7 @@
     /* The real content of the bag depends on the game mode */
     if (getMode() == kFREEGAME)
     {
-        /* In freegame mode, replace the letters from all the racks */
+        /* In freegame mode, take the letters from all the racks */
         for (int i = 0; i < getNPlayers(); i++)
         {
             getPlayer(i).getCurrentRack().getAllTiles(tiles);
@@ -485,7 +223,7 @@
     }
     else
     {
-        /* In training or duplicate mode, replace the rack of the current
+        /* In training or duplicate mode, take the rack of the current
          * player only */
         getPlayer(m_currPlayer).getCurrentRack().getAllTiles(tiles);
         for (unsigned int j = 0; j < tiles.size(); j++)
@@ -496,38 +234,26 @@
 }
 
 
-bool Game::rackInBag(const Rack &iRack, const Bag &iBag) const
-{
-    const list<Tile>& allTiles = Tile::getAllTiles();
-    list<Tile>::const_iterator it;
-    for (it = allTiles.begin(); it != allTiles.end(); it++)
-    {
-        if (iRack.in(*it) > iBag.in(*it))
-            return false;
-    }
-    return true;
-}
-
-
 int Game::helperSetRackRandom(int p, bool iCheck, set_rack_mode mode)
 {
     ASSERT(0 <= p && p < getNPlayers(), "Wrong player number");
 
     int nold, min;
 
-    // Make a copy of the player's rack
+    // Make a copy of the current player's rack
     PlayedRack pld = getPlayer(p).getCurrentRack();
     nold = pld.nOld();
 
     // Create a copy of the bag in which we can do everything we want,
-    // and remove from it the tiles of the racks
+    // and take from it the tiles of the players rack so that "bag"
+    // contains the right number of tiles.
     Bag bag;
     realBag(bag);
 
-    // We may have removed too many letters from the bag (i.e. the 'new'
-    // letters of the player)
     if (mode == RACK_NEW && nold != 0)
     {
+        // We may have removed too many letters from the bag (i.e. the 'new'
+        // letters of the player)
         vector<Tile> tiles;
         pld.getNewTiles(tiles);
         for (unsigned int i = 0; i < tiles.size(); i++)
@@ -536,13 +262,24 @@
         }
         pld.resetNew();
     }
-    else
+    else if (mode == RACK_NEW && nold == 0 || mode == RACK_ALL)
     {
+        // Replace all the tiles in the bag before choosing random ones
+        vector<Tile> tiles;
+        pld.getAllTiles(tiles);
+        for (unsigned int i = 0; i < tiles.size(); i++)
+        {
+            bag.replaceTile(tiles[i]);
+        }
         // RACK_NEW with an empty rack is equivalent to RACK_ALL
         pld.reset();
         // Do not forget to update nold, for the RACK_ALL case
         nold = 0;
     }
+    else
+    {
+        debug("Game::helperSetRackRandom not a random mode\n");
+    }
 
     // Nothing in the rack, nothing in the bag --> end of the game
     if (bag.nTiles() == 0 && pld.nTiles() == 0)
@@ -640,7 +377,7 @@
         }
     }
 
-    if (iCheck && !pld.checkRack(min))
+    if (iCheck && !pld.checkRack(min,min))
         return 2;
 
     m_players[p]->setCurrentRack(pld);
@@ -649,40 +386,41 @@
 }
 
 
+/**
+ * Check if the players rack can be obtained from the bag.
+ * Since letters are removed from the bag only when the
+ * round is played we need to check that ALL the racks 
+ * are in the bag simultaneously.
+ *
+ * FIXME: since we do not check for all racks it works
+ * for training and duplicate but it won't work for
+ * freegames.
+ */
+bool Game::rackInBag(const Rack &iRack, const Bag &iBag) const
+{
+    const list<Tile>& allTiles = Tile::getAllTiles();
+    list<Tile>::const_iterator it;
+    for (it = allTiles.begin(); it != allTiles.end(); it++)
+    {
+        if (iRack.in(*it) > iBag.in(*it))
+            return false;
+    }
+    return true;
+}
+
+/**
+ * Set the rack of the player p manually.
+ */
 int Game::helperSetRackManual(int p, bool iCheck, const string &iLetters)
 {
-    unsigned int i;
-    int min;
+    int min, ret;
 
     PlayedRack pld = getPlayer(p).getCurrentRack();
     pld.reset();
 
-    if (iLetters.size() == 0)
-    {
-        return 0;
-    }
-
-    for (i = 0; i < iLetters.size() && iLetters[i] != '+'; i++)
+    if ((ret = pld.setManual(iLetters)) > 0)
     {
-        Tile tile(iLetters[i]);
-        if (tile.isEmpty())
-        {
-            return 1;
-        }
-        pld.addOld(tile);
-    }
-
-    if (i < iLetters.size() && iLetters[i] == '+')
-    {
-        for (i++; i < iLetters.size(); i++)
-        {
-            Tile tile(iLetters[i]);
-            if (tile.isEmpty())
-            {
-                return 1;
-            }
-            pld.addNew(tile);
-        }
+        return 1; /* add new tests */
     }
 
     Rack rack;
@@ -700,7 +438,7 @@
             min = 2;
         else
             min = 1;
-        if (!pld.checkRack(min))
+        if (!pld.checkRack(min,min))
             return 2;
     }
 
@@ -849,4 +587,5 @@
 /// mode: c++
 /// mode: hs-minor
 /// c-basic-offset: 4
+/// indent-tabs-mode: nil
 /// End:
Index: eliot/game/game.h
diff -u eliot/game/game.h:1.26 eliot/game/game.h:1.27
--- eliot/game/game.h:1.26      Tue Dec 27 15:01:07 2005
+++ eliot/game/game.h   Sun Jan  1 19:48:36 2006
@@ -93,6 +93,14 @@
     const Player& getCurrentPlayer() const { return getPlayer(currPlayer()); };
 
     /**
+     * Eliot file formats
+     */
+    typedef enum {
+      FILE_FORMAT_STANDARD,
+      FILE_FORMAT_ADVANCED
+    } game_file_format;
+
+    /**
      * Saved games handling.
      *
      * load() returns the loaded game, or NULL if there was a problem
@@ -100,7 +108,16 @@
      * handle "hand written" files
      */
     static Game * load(FILE *fin, const Dictionary &iDic);
-    void save(ostream &out) const;
+
+    /**
+     * Save a game to a File
+     * Standard format is used for training games so that it is compatible
+     * with previous versions of Eliot.
+     *
+     * Saving can be forced to advanced format for training games by 
+     * setting the last parameter to FILE_FORMAT_ADVANCED
+     */
+    void save(ostream &out, game_file_format format=FILE_FORMAT_STANDARD) 
const;
 
     /*************************
      * Playing the game
@@ -128,7 +145,10 @@
     enum set_rack_mode {RACK_ALL, RACK_NEW, RACK_MANUAL};
     int setRack(int player, set_rack_mode mode, bool check, const string& str);
 
-    /** Getter for the history of the game  */
+    /**
+     * Methods to access already played words.
+     * The int parameter should be 0 <= int < getNTurns()
+     */
     const History& getHistory() const { return m_history; }
 
     /**
@@ -194,6 +214,36 @@
     void realBag(Bag &iBag) const;
     int  checkPlayedWord(const string &iCoord,
                          const string &iWord, Round &oRound);
+
+    /**
+     * load games from File using the first format.
+     * This format is used for Training games
+     */
+    static Game* gameLoadFormat_14(FILE *fin, const Dictionary& iDic);
+
+    /**
+     * load games from File using advanced format (since Eliot 1.5)
+     * This format is used for Duplicate, Freegame, ...
+     */
+    static Game* gameLoadFormat_15(FILE *fin, const Dictionary& iDic);
+
+    /**
+     * Training games ares saved using the initial Eliot format
+     */
+    void Game::gameSaveFormat_14(ostream &out) const;
+
+    /**
+     * Advanced game file format output
+     */
+    void Game::gameSaveFormat_15(ostream &out) const;
+
 };
 
 #endif /* _GAME_H_ */
+
+/// Local Variables:
+/// mode: c++
+/// mode: hs-minor
+/// c-basic-offset: 4
+/// indent-tabs-mode: nil
+/// End:




reply via email to

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