00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "dic.h"
00022 #include "dic_search.h"
00023 #include "tile.h"
00024 #include "rack.h"
00025 #include "round.h"
00026 #include "pldrack.h"
00027 #include "results.h"
00028 #include "player.h"
00029 #include "ai_percent.h"
00030 #include "game.h"
00031 #include "game_factory.h"
00032 #include "turn.h"
00033
00034 #include "debug.h"
00035
00036
00037 const int Game::RACK_SIZE = 7;
00038
00039
00040 Game::Game(const Dictionary &iDic):
00041 m_dic(&iDic)
00042 {
00043 m_variant = kNONE;
00044 m_points = 0;
00045 m_currPlayer = -1;
00046 m_finished = false;
00047 }
00048
00049
00050 Game::~Game()
00051 {
00052 for (int i = 0; i < getNPlayers(); i++)
00053 {
00054 delete m_players[i];
00055 }
00056 }
00057
00058
00059 const Player& Game::getPlayer(int iNum) const
00060 {
00061 ASSERT(0 <= iNum && iNum < (int)m_players.size(), "Wrong player number");
00062 return *(m_players[iNum]);
00063 }
00064
00065
00066
00067 int Game::helperPlayRound(const Round &iRound)
00068 {
00069
00070
00071
00072
00073
00074
00075
00076
00077 m_history.setCurrentRack(getCurrentPlayer().getLastRack());
00078 m_history.playRound(m_currPlayer, m_history.getSize(), iRound);
00079
00080 m_points += iRound.getPoints();
00081
00082
00083
00084
00085 if (m_variant == kJOKER)
00086 {
00087 for (int i = 0; i < iRound.getWordLen(); i++)
00088 {
00089 if (iRound.isPlayedFromRack(i) && iRound.isJoker(i))
00090 {
00091
00092
00093 Tile t(toupper(iRound.getTile(i).toChar()));
00094 Bag bag;
00095 realBag(bag);
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 vector<Tile> tiles;
00109 getPlayer(m_currPlayer).getCurrentRack().getAllTiles(tiles);
00110 for (unsigned int j = 0; j < tiles.size(); j++)
00111 {
00112 bag.replaceTile(tiles[j]);
00113 }
00114 getPlayer(m_currPlayer).getLastRack().getAllTiles(tiles);
00115 for (unsigned int j = 0; j < tiles.size(); j++)
00116 {
00117 bag.takeTile(tiles[j]);
00118 }
00119
00120 if (bag.in(t))
00121 {
00122
00123 const_cast<Round&>(iRound).setTile(i, t);
00124
00125
00126
00127 const_cast<Round&>(iRound).setJoker(i, false);
00128 }
00129 }
00130 }
00131 }
00132
00133
00134 for (int i = 0; i < iRound.getWordLen(); i++)
00135 {
00136 if (iRound.isPlayedFromRack(i))
00137 {
00138 if (iRound.isJoker(i))
00139 {
00140 m_bag.takeTile(Tile::Joker());
00141 }
00142 else
00143 m_bag.takeTile(iRound.getTile(i));
00144 }
00145 }
00146 m_board.addRound(*m_dic, iRound);
00147
00148 return 0;
00149 }
00150
00151
00152 int Game::back(int n)
00153 {
00154 int i, j;
00155 Player *player;
00156
00157 if (n < 0)
00158 {
00159 debug("Game::back negative argument\n");
00160 n = -n;
00161 }
00162 debug("Game::back %d\n",n);
00163 for (i = 0; i < n; i++)
00164 {
00165 if (m_history.getSize() > 0)
00166 {
00167 prevPlayer();
00168 player = m_players[m_currPlayer];
00169 const Round &lastround = m_history.getPreviousTurn().getRound();
00170 debug("Game::back last round %s\n",lastround.toString().c_str());
00171
00172
00173 m_board.removeRound(*m_dic, lastround);
00174 for (j = 0; j < lastround.getWordLen(); j++)
00175 {
00176 if (lastround.isPlayedFromRack(j))
00177 {
00178 if (lastround.isJoker(j))
00179 m_bag.replaceTile(Tile::Joker());
00180 else
00181 m_bag.replaceTile(lastround.getTile(j));
00182 }
00183 }
00184
00185 player->addPoints(- lastround.getPoints());
00186 m_points -= lastround.getPoints();
00187
00188 player->removeLastTurn();
00189 m_history.removeLastTurn();
00190 }
00191 else
00192 {
00193 return 1;
00194 }
00195 }
00196 return 0;
00197 }
00198
00199
00200
00201
00202
00203 void Game::realBag(Bag &ioBag) const
00204 {
00205 vector<Tile> tiles;
00206
00207
00208 ioBag = m_bag;
00209
00210
00211 if (getMode() == kFREEGAME)
00212 {
00213
00214 for (int i = 0; i < getNPlayers(); i++)
00215 {
00216 getPlayer(i).getCurrentRack().getAllTiles(tiles);
00217 for (unsigned int j = 0; j < tiles.size(); j++)
00218 {
00219 ioBag.takeTile(tiles[j]);
00220 }
00221 }
00222 }
00223 else
00224 {
00225
00226
00227 getPlayer(m_currPlayer).getCurrentRack().getAllTiles(tiles);
00228 for (unsigned int j = 0; j < tiles.size(); j++)
00229 {
00230 ioBag.takeTile(tiles[j]);
00231 }
00232 }
00233 }
00234
00235
00236 bool Game::rackInBag(const Rack &iRack, const Bag &iBag) const
00237 {
00238 const list<Tile>& allTiles = Tile::getAllTiles();
00239 list<Tile>::const_iterator it;
00240 for (it = allTiles.begin(); it != allTiles.end(); it++)
00241 {
00242 if (iRack.in(*it) > iBag.in(*it))
00243 return false;
00244 }
00245 return true;
00246 }
00247
00248
00249 int Game::helperSetRackRandom(int p, bool iCheck, set_rack_mode mode)
00250 {
00251 ASSERT(0 <= p && p < getNPlayers(), "Wrong player number");
00252
00253 int nold, min;
00254
00255
00256 PlayedRack pld = getPlayer(p).getCurrentRack();
00257 nold = pld.nOld();
00258
00259
00260
00261 Bag bag;
00262 realBag(bag);
00263
00264
00265
00266 if (mode == RACK_NEW && nold != 0)
00267 {
00268 vector<Tile> tiles;
00269 pld.getNewTiles(tiles);
00270 for (unsigned int i = 0; i < tiles.size(); i++)
00271 {
00272 bag.replaceTile(tiles[i]);
00273 }
00274 pld.resetNew();
00275 }
00276 else
00277 {
00278
00279 pld.reset();
00280
00281 nold = 0;
00282 }
00283
00284
00285 if (bag.nTiles() == 0 && pld.nTiles() == 0)
00286 {
00287 return 1;
00288 }
00289
00290
00291
00292
00293
00294
00295 min = 0;
00296 if (iCheck)
00297 {
00298 int oldc, oldv;
00299
00300 if (bag.nVowels() == 0 || bag.nConsonants() == 0)
00301 {
00302 return 1;
00303 }
00304
00305 if (bag.nVowels() > 1 && bag.nConsonants() > 1
00306 && m_history.getSize() < 15)
00307 min = 2;
00308 else
00309 min = 1;
00310
00311
00312 vector<Tile> tiles;
00313 pld.getOldTiles(tiles);
00314 oldc = 0;
00315 oldv = 0;
00316 for (unsigned int i = 0; i < tiles.size(); i++)
00317 {
00318 if (tiles[i].isConsonant())
00319 oldc++;
00320 if (tiles[i].isVowel())
00321 oldv++;
00322 }
00323
00324
00325 if (min > oldc + RACK_SIZE - nold ||
00326 min > oldv + RACK_SIZE - nold)
00327 {
00328
00329 return 3;
00330 }
00331 }
00332
00333
00334 if (m_variant == kJOKER)
00335 {
00336
00337 bool jokerFound = false;
00338 vector<Tile> tiles;
00339 pld.getOldTiles(tiles);
00340 for (unsigned int i = 0; i < tiles.size(); i++)
00341 {
00342 if (tiles[i].isJoker())
00343 {
00344 jokerFound = true;
00345 break;
00346 }
00347 }
00348
00349
00350 if (!jokerFound && bag.in(Tile::Joker()))
00351 {
00352 bag.takeTile(Tile::Joker());
00353 pld.addNew(Tile::Joker());
00354 }
00355
00356
00357 Tile l;
00358 while (bag.nTiles() != 0 && pld.nTiles() != RACK_SIZE)
00359 {
00360 l = bag.selectRandom();
00361 if (!l.isJoker())
00362 {
00363 bag.takeTile(l);
00364 pld.addNew(l);
00365 }
00366 }
00367 }
00368 else
00369 {
00370
00371 Tile l;
00372 while (bag.nTiles() != 0 && pld.nTiles() != RACK_SIZE)
00373 {
00374 l = bag.selectRandom();
00375 bag.takeTile(l);
00376 pld.addNew(l);
00377 }
00378 }
00379
00380 if (iCheck && !pld.checkRack(min))
00381 return 2;
00382
00383 m_players[p]->setCurrentRack(pld);
00384
00385 return 0;
00386 }
00387
00388
00389 int Game::helperSetRackManual(int p, bool iCheck, const string &iLetters)
00390 {
00391 unsigned int i;
00392 int min;
00393
00394 PlayedRack pld = getPlayer(p).getCurrentRack();
00395 pld.reset();
00396
00397 if (iLetters.size() == 0)
00398 {
00399 return 0;
00400 }
00401
00402 for (i = 0; i < iLetters.size() && iLetters[i] != '+'; i++)
00403 {
00404 Tile tile(iLetters[i]);
00405 if (tile.isEmpty())
00406 {
00407 return 1;
00408 }
00409 pld.addOld(tile);
00410 }
00411
00412 if (i < iLetters.size() && iLetters[i] == '+')
00413 {
00414 for (i++; i < iLetters.size(); i++)
00415 {
00416 Tile tile(iLetters[i]);
00417 if (tile.isEmpty())
00418 {
00419 return 1;
00420 }
00421 pld.addNew(tile);
00422 }
00423 }
00424
00425 Rack rack;
00426 pld.getRack(rack);
00427 if (!rackInBag(rack, m_bag))
00428 {
00429 pld.reset();
00430 return 1;
00431 }
00432
00433 if (iCheck)
00434 {
00435 if (m_bag.nVowels() > 1 && m_bag.nConsonants() > 1
00436 && m_history.getSize() < 15)
00437 min = 2;
00438 else
00439 min = 1;
00440 if (!pld.checkRack(min))
00441 return 2;
00442 }
00443
00444 m_players[p]->setCurrentRack(pld);
00445
00446 return 0;
00447 }
00448
00449
00450
00451
00452 string Game::getPlayerRack(int num, PlayedRack::display_mode mode) const
00453 {
00454 return getPlayer(num).getCurrentRack().toString(mode);
00455 }
00456
00457
00458 int Game::getNHumanPlayers() const
00459 {
00460 int count = 0;
00461 for (int i = 0; i < getNPlayers(); i++)
00462 count += (getPlayer(i).isHuman() ? 1 : 0);
00463 return count;
00464 }
00465
00466
00467 void Game::addHumanPlayer()
00468 {
00469
00470 m_players.push_back(new HumanPlayer(getNPlayers()));
00471 }
00472
00473
00474 void Game::addAIPlayer()
00475 {
00476 m_players.push_back(new AIPercent(getNPlayers(), 0));
00477 }
00478
00479
00480 void Game::prevPlayer()
00481 {
00482 ASSERT(getNPlayers() != 0, "Expected at least one player");
00483
00484 if (m_currPlayer == 0)
00485 m_currPlayer = getNPlayers() - 1;
00486 else
00487 m_currPlayer--;
00488 }
00489
00490
00491 void Game::nextPlayer()
00492 {
00493 ASSERT(getNPlayers() != 0, "Expected at least one player");
00494
00495 if (m_currPlayer == getNPlayers() - 1)
00496 m_currPlayer = 0;
00497 else
00498 m_currPlayer++;
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520 int Game::checkPlayedWord(const string &iCoord,
00521 const string &iWord, Round &oRound)
00522 {
00523 ASSERT(getNPlayers() != 0, "Expected at least one player");
00524
00525 int res;
00526 vector<Tile> tiles;
00527 Tile t;
00528
00529
00530 oRound.init();
00531 oRound.accessCoord().setFromString(iCoord);
00532 if (!oRound.getCoord().isValid())
00533 return 2;
00534
00535
00536 if (Dic_search_word(*m_dic, iWord.c_str()) == 0)
00537 return 3;
00538
00539
00540
00541
00542
00543 for (unsigned int i = 0; i < iWord.size(); i++)
00544 {
00545 tiles.push_back(Tile(iWord[i]));
00546 }
00547 oRound.setWord(tiles);
00548 for (unsigned int i = 0; i < iWord.size(); i++)
00549 {
00550 if (islower(iWord[i]))
00551 oRound.setJoker(i);
00552 }
00553
00554
00555
00556 res = m_board.checkRound(oRound, m_history.getSize() == 0);
00557 if (res != 0)
00558 return res + 4;
00559
00560
00561
00562
00563 Rack rack;
00564 Player *player = m_players[m_currPlayer];
00565 player->getCurrentRack().getRack(rack);
00566
00567 for (int i = 0; i < oRound.getWordLen(); i++)
00568 {
00569 if (oRound.isPlayedFromRack(i))
00570 {
00571 if (oRound.isJoker(i))
00572 t = Tile::Joker();
00573 else
00574 t = oRound.getTile(i);
00575
00576 if (!rack.in(t))
00577 {
00578 return 4;
00579 }
00580 rack.remove(t);
00581 }
00582 }
00583
00584 return 0;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595