/***************************************************************************** * Copyright (C) 1999-2005 Eliot * Authors: Antoine Fraboulet * Olivier Teuliere * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ /* $Id: game_io.cpp,v 1.1.2.1 2005/10/23 18:38:18 afrab Exp $ */ /** * \file game_io.cpp * \brief Eliot game class file load/save handling * \author Antoine Fraboulet & Olivier Teuliere * \date 2002 - 2005 */ #include "pldrack.h" #include "round.h" #include "turn.h" #include "player.h" #include "game.h" #include "game_factory.h" /************************* * Ident string used to identify saved Eliot games *************************/ #define IDENT_STRING "Eliot" #define IDENT_FORMAT_14 "" #define IDENT_FORMAT_15 "1.5" /******************************************************** * * Loading games * ********************************************************/ 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; /* checks for IDENT_STRING and file format */ if (std::string(token) != IDENT_STRING) return NULL; if ((token = strtok(NULL, delim)) == NULL) { //std::cerr << "loading file format 1.4\n"; return Game::gameLoadFormat_14(fin,iDic); } if (std::string(token) == std::string(IDENT_FORMAT_15)) { //std::cerr << "loading file format 1.5\n"; return Game::gameLoadFormat_15(fin,iDic); } return NULL; } Game* Game::gameLoadFormat_14(FILE *fin, const Dictionary iDic) { Tile tile; char buff[4096]; char rack[20]; char word[20]; char pos [5]; char delim[]=" \t\n"; char *token; Game *pGame = NULL; pGame = GameFactory::Instance()->createTraining(iDic); pGame->start(); while(fgets(buff,sizeof(buff),fin)) { token = strtok(buff,delim); if (token != NULL) { if (strcmp(token,"total")==0) { break; } /* rack */ strncpy(rack,token,sizeof(rack)); ((Training*)pGame)->setRack(PlayedRack::RACK_MANUAL,false,std::string(rack)); /* word */ token = strtok(NULL,delim); if (!token || strcmp(token,"total")==0) { //std::cerr << "break2" << endl; break; } strncpy(word,token,sizeof(word)); //std::cerr << "\t" << word << " "; /* bonus */ if ((token = strtok(NULL,delim)) == NULL) break; /* points */ if (token[0]=='*') { //std::cerr << token << " \t"; if ((token = strtok(NULL,delim)) == NULL) break; } /* pos 1 */ if ((token = strtok(NULL,delim)) == NULL) break; //std::cerr << "(" << token << " "; strncpy(pos,token,sizeof(pos)); /* pos 2 */ if ((token = strtok(NULL,delim)) == NULL) break; //std::cerr << token << ")"; strncat(pos,token,sizeof(pos)); //std::cerr << pos << endl; pGame->play(0,std::string(pos),std::string(word)); } } return pGame; } Game* Game::gameLoadFormat_15(FILE *fin, const Dictionary iDic) { Game *pGame = NULL; #if 0 char buff[4096]; int num; char rack[20]; char word[20]; char ref[4]; int pts; int player; char *pos; Tile tile; 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 (pGame->getMode() != kTRAINING) { if (std::string(type) == "Human") pGame->addHumanPlayer(); else if (std::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 (std::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.setPoints(pts); if (bonus == '*') round.setBonus(1); if (isalpha(ref[0])) { // Horizontal word round.setDir(HORIZONTAL); round.setRow(ref[0] - 'A' + 1); round.setCol(atoi(ref + 1)); for (unsigned int i = 0; i < strlen(word); i++) { tile = Tile(word[i]); if (!pGame->m_board.getTile(round.getRow(), round.getCol() + i).isEmpty()) { round.addRightFromBoard(tile); } else { round.addRightFromRack(tile, islower(word[i])); pGame->m_bag.takeTile((islower(word[i])) ? Tile::Joker() : tile); } } } else { // Vertical word round.setDir(VERTICAL); round.setRow(ref[strlen(ref) - 1] - 'A' + 1); round.setCol(atoi(ref)); for (unsigned int i = 0; i < strlen(word); i++) { tile = Tile(word[i]); if (!pGame->m_board.getTile(round.getRow() + i, round.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]->playRound(num - 1, round); // 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->m_players[i]->isHuman()) { pGame->m_currPlayer = i; break; } } } #endif return pGame; } /******************************************************** * * Loading games * ********************************************************/ void Game::save(std::ostream &out) const { if (getNPlayers() == 1) { gameSaveFormat_14(out); } else { gameSaveFormat_15(out); } } void Game::gameSaveFormat_14(std::ostream &out) const { int i; char buff[100]; const char decal[]=" "; out << IDENT_STRING << std::endl << std::endl; for(i = 0; i < m_history.getSize(); i++) { Turn t = m_history.getTurn(i); out << decal << t.toString() << std::endl; } out << std::endl; out << decal << "total" << std::string(24,' '); sprintf(buff,"%4d", m_players[0]->getPoints()); out << buff << std::endl; } void Game::gameSaveFormat_15(std::ostream &out) const { #if 0 const std::string decal = " "; // "Header" of the game out << IDENT_STRING << " " << IDENT_FORMAT_15 << std::endl << std::endl; // Game type out << "Game type: " << getModeAsString() << std::endl; // Player list for (int i = 0; i < getNPlayers(); i++) { out << "Player " << i << ": "; if (m_players[i]->isHuman()) out << "Human" << std::endl; else out << "Computer" << std::endl; } out << std::endl; // Title of the columns char line[100]; out << decal << " N | RACK | SOLUTION | REF | PTS | P | BONUS" << std::endl; out << decal << "===|==========|=================|=====|=====|===|======" << std::endl; // Print the game itself for (int i = 0; i < getNRounds(); i++) { std::string word = getPlayedWord(i); std::string coord = getPlayedCoords(i); sprintf(line, "%2d | %8s | %s%s | %3s | %3d | %1d | %c", i + 1, getPlayedRack(i).c_str(), /* pldrack */ word.c_str(), /* word */ std::string(15 - word.size(), ' ').c_str(), /* fill spaces */ coord.c_str(), /* coord */ getPlayedPoints(i), getPlayedPlayer(i), getPlayedBonus(i) ? '*' : ' '); out << decal << line << std::endl; } // A game has no points in total (should it be the sum of all player's points) // out << std::endl << decal << "Total: " << m_points << std::endl; // Print current rack for all the players out << std::endl; for (int i = 0; i < getNPlayers(); i++) { std::string rack = m_players[i]->getCurrentRack().toString(); out << "Rack " << i << ": " << rack << std::endl; } #endif } /// Local Variables: /// mode: hs-minor /// c-basic-offset: 4 /// End: