engine_two.cpp

Go to the documentation of this file.
00001 /*
00002    This file is part of the KDE games lskat program
00003    Copyright (c) 2006 Martin Heni <kde@heni-online.de>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 // Qt includes
00022 #include <QTimer>
00023 
00024 // KDE includes
00025 #include <kdebug.h>
00026 #include <klocalizedstring.h>
00027 
00028 // Local includes
00029 #include "engine_two.h"
00030 #include "lskatglobal.h"
00031 #include "display_two.h"
00032 
00033 #define TIME_END_MOVE    1000  /* Wait this [ms] after end of move */
00034 
00035 
00036 // Constructor for the game document/engine
00037 EngineTwo::EngineTwo(QWidget* parent, Deck* deck, DisplayTwo* display)
00038                : AbstractEngine(parent)
00039 {
00040   mDisplay       = display;
00041   mDeck          = deck;
00042   mCurrentPlayer = 0;
00043 }
00044 
00045 
00046 // Inital part of the game loop. Prepare new move etc
00047 void EngineTwo::gameLoopStart()
00048 {
00049   if (!isGameRunning()) return;
00050 
00051   // Switch to the current player
00052   activatePlayer(mCurrentPlayer);
00053 }
00054 
00055 
00056 // Middle part of the game loop. Receive input of a player
00057 // Here: inputId == playerNumber
00058 void EngineTwo::playerInput(int inputId, int playerNumber, int cardNumber)
00059 {
00060   if (global_debug > 0)
00061     kDebug() << "Engine got player input: card= " << cardNumber
00062               << " Player= " << playerNumber << " Id=" << inputId << endl;
00063   if (playerNumber != mCurrentPlayer)
00064   {
00065     if (global_debug > 0)
00066       kDebug() << "EngineTwo::playerInput: Input from wrong player" << endl;
00067     return;
00068   }
00069 
00070   Player* player = mPlayers[playerNumber];
00071   int height = 0;
00072   int card = player->getCard(cardNumber);
00073   // Check whether top card is still available - if not try bottom one
00074   if (card < 0) 
00075   {
00076     height = 1;
00077     card = player->getCard(cardNumber + 8* height);
00078   }
00079 
00080 
00081 
00082   // Check whether player still has this card
00083   if (card < 0)
00084   {
00085     if (global_debug > 0)
00086       kDebug() << "EngineTwo::playerInput: Card " << cardNumber + 8*height
00087                 << " not available anymore "<< endl;
00088     return;
00089   }
00090 
00091   // Remove this, Debug current card 
00092   if (global_debug > 0)
00093   {
00094     Suite   suite = mDeck->getSuite(card);
00095     CardType type = mDeck->getCardType(card);
00096     kDebug() << "Gameloop "<<mCurrentPlayer <<" plays " << mDeck->name(suite, type) << endl;
00097   }
00098 
00099 
00100 
00101   // Check for legal move (first player always ok)
00102   if (mCurrentMovePhase == SecondPlayerTurn) 
00103   {
00104     //   Check (card of player 1), (card of player 2), (player 2)
00105     if (!isLegalMove(mCurrentMoveCards[FirstPlayerTurn], card, playerNumber))
00106     {
00107       if (global_debug > 0)
00108         kDebug() << "EngineTwo::playerInput: Card " << cardNumber + 8*height
00109                   << " is not a valid move "<< endl;
00110       return;
00111     }
00112   }
00113 
00114   // Delete card from player
00115   player->deleteCard(cardNumber + 8*height);
00116 
00117 
00118   // Finish input from player
00119   player->stopTurn();
00120 
00121   // Play out card
00122   mDisplay->play(card, playerNumber, mCurrentMovePhase);
00123 
00124   // Turn back card if top card is played
00125   if (height == 0)
00126   {
00127     int backcard = player->getCard(cardNumber + 8);
00128     mDisplay->turn(backcard);
00129   }
00130 
00131 
00132   // Store currently played card
00133   mCurrentMoveCards[mCurrentMovePhase] = card;
00134 
00135   // Finish game loop
00136   if (mCurrentMovePhase == SecondPlayerTurn)
00137   {
00138     QTimer::singleShot(TIME_END_MOVE, this, SLOT(gameLoopFinish()) );
00139   }
00140   else
00141   {
00142     QTimer::singleShot(0, this, SLOT(gameLoopFinish()) );
00143   }
00144 
00145 }
00146 
00147 
00148 // Final part of the game loop. Switch player etc.
00149 void EngineTwo::gameLoopFinish()
00150 {
00151   if (!isGameRunning()) return;
00152 
00153   // If second move phase, remove cards
00154   if (mCurrentMovePhase == SecondPlayerTurn)
00155   {
00156 
00157     // Switch the current player if second player one
00158     int winner = whoWonMove(mCurrentMoveCards[FirstPlayerTurn],
00159                             mCurrentMoveCards[SecondPlayerTurn]);
00160     // The first mover won. This means to switch the current player back
00161     // to him.  Otherwise the current player stays untouched, that is the
00162     // second player plays again.
00163     if (winner == 0)
00164     {
00165       mCurrentPlayer = 1- mCurrentPlayer; 
00166     }
00167     
00168     // Move both cards away from play area. Move them to the winning mover's side
00169     Player* player = mPlayers[mCurrentPlayer];
00170     mDisplay->remove(mCurrentPlayer,
00171                      mCurrentMoveCards[FirstPlayerTurn],
00172                      player->noOfMovesWon());
00173     mDisplay->remove(mCurrentPlayer, 
00174                      mCurrentMoveCards[SecondPlayerTurn],
00175                      player->noOfMovesWon()+1);
00176     player->increaseMovesWon();
00177     player->addWonCard(mCurrentMoveCards[FirstPlayerTurn]);
00178     player->addWonCard(mCurrentMoveCards[SecondPlayerTurn]);
00179     
00180     if (global_debug > 0)
00181     {
00182       kDebug() << "Winner = " << winner << " current = " << mCurrentPlayer <<endl;
00183       kDebug() << "   He has won " << player->noOfMovesWon() << " moves." << endl;
00184       kDebug() << "   He has " << player->points() << " points." << endl;
00185     }
00186     // Switch move phase (half moves)
00187     mCurrentMovePhase = FirstPlayerTurn;
00188   }
00189   // For the first part of a half move always swap players
00190   else if (mCurrentMovePhase == FirstPlayerTurn)
00191   {
00192     mCurrentPlayer = 1- mCurrentPlayer; 
00193     // Switch move phase (half moves)
00194     mCurrentMovePhase = SecondPlayerTurn;
00195   }
00196 
00197   // Check whether the game is over
00198   if (gameOver())
00199   {
00200     if (global_debug > 0) kDebug()  << "GAME OVER " << endl;
00201     mGameStatus = Stopped;
00202     mDisplay->showMove(-1);
00203     int winner = evaluateGame();
00204     emit signalGameOver(winner);
00205   }
00206   // Game continues
00207   else
00208   {
00209     // Increase move number
00210     mMoveNumber++;
00211 
00212     // Delayed call to game loop start
00213     QTimer::singleShot(0, this, SLOT(gameLoopStart()) );
00214   }
00215 }
00216 
00217 
00218 // Check whether the game is over
00219 bool EngineTwo::gameOver()
00220 {
00221   if (global_debug > 0) kDebug() << "Move number in game over " << mMoveNumber << endl;
00222   // Check number of moves. If all moves are done game is over.
00223   if (mMoveNumber >= 31) return true;
00224   return false;
00225 }
00226 
00227 
00228 // Called after game ends..give points to players
00229 int EngineTwo::evaluateGame()
00230 {
00231   int winner = -1;
00232   Player* player1 = mPlayers[0];
00233   Player* player2 = mPlayers[1];
00234 
00235   // Points in game
00236   int points1 = player1->points();
00237   int points2 = player2->points();
00238 
00239   // Score awarded
00240   int score1 = 0;
00241   int score2 = 0;
00242 
00243   QString text;
00244 
00245   // Increase number of games
00246   player1->addGame(1);
00247   player2->addGame(1);
00248   
00249   // Game was aborted
00250   if (points1 + points2 != 120)
00251   {
00252     text = i18n("Game was aborted - no winner");
00253     winner = -2;
00254   }
00255   // Drawn
00256   else if (points1 == points2)
00257   {
00258     // Add score
00259     score1 = 1;
00260     score2 = 1;
00261     text = i18n("Game is drawn");
00262     winner = -1;
00263   }
00264   // First player won
00265   else if (points1 > points2)
00266   {
00267     text = i18n("Player %1 won ", player1->name());
00268 
00269     score1 = 2;
00270     player1->addWonGame(1);
00271     if (points1 >= 90)
00272     {  
00273       score1 += 1;  // Schneider
00274       text = i18n("%1 won with 90 points. Super!", player1->name());
00275     }
00276     // Do not use 'else if' here !
00277     if (points1 >= 120)
00278     {
00279       score1 += 1; // Schwarz
00280       text = i18n("%1 won to nil. Congratulations!", player1->name());
00281     }
00282     winner = 0;
00283   }
00284   // Second player won
00285   else
00286   {
00287     text = i18n("Player 2 - %1 won ", player2->name());
00288 
00289     score2 = 2;
00290     player2->addWonGame(1);
00291     if (points2 >= 90)
00292     {
00293       score2 += 1;  // Schneider
00294       text = i18n("%1 won with 90 points. Super!", player2->name());
00295     }
00296     // Do not use 'else if' here !
00297     if (points2 >= 120)
00298     {
00299       score2 += 1; // Schwarz
00300       text = i18n("%1 won to nil. Congratulations!", player2->name());
00301     }
00302     winner = 1;
00303   }
00304 
00305   // Add score to players
00306   player1->addScore(score1);
00307   player2->addScore(score2);
00308 
00309   // Display game over data
00310   mDisplay->showText(text);
00311   mDisplay->showScore(0, score1);
00312   mDisplay->showScore(1, score2);
00313 
00314   return winner;
00315 }
00316 
00317 
00318 // Start a new game
00319 void EngineTwo::startGame(Suite trump, int startPlayer)
00320 {
00321   // Set the new trump
00322   mTrump = trump;
00323 
00324   // Set game status to running
00325   mGameStatus    = Running;
00326 
00327   // Switch to the start player
00328   mCurrentPlayer = startPlayer;
00329 
00330   // Set first player to move
00331   mCurrentMovePhase = FirstPlayerTurn;
00332 
00333   // Game starts, reset moves
00334   mMoveNumber = 0;
00335 
00336   // Loop players to deal cards
00337   for (int p=0; p<2; p++)
00338   {
00339       Player* player = mPlayers[p];
00340       player->addGame(1); // Increase games of player
00341       mDisplay->deal(player, p);
00342   }
00343 
00344   // Delayed call to game loop start
00345   QTimer::singleShot(mDisplay->shuffleTime(), this, SLOT(gameLoopStart()) );
00346 }
00347 
00348 
00349 // Stop a game
00350 void EngineTwo::stopGame()
00351 {
00352   // Disable inputs for two players
00353   for (int i=0;i<2;i++)
00354   {
00355     mPlayers[i]->stopTurn();
00356   }
00357 
00358   mDisplay->showMove(-1);
00359 
00360   if (isGameRunning())
00361   {
00362     // Display game over data
00363     QString text = i18n("Game aborted");
00364     mDisplay->showText(text);
00365 
00366     // Set game status to stopped
00367     mGameStatus    = Stopped;
00368     emit signalGameOver(-2);
00369   }
00370 }
00371 
00372 
00373 // Switch the current player to the given player number.
00374 void EngineTwo::activatePlayer(int playerNumber)
00375 {
00376   
00377   // Disable inputs for two players
00378   for (int i=0;i<2;i++)
00379   {
00380     mPlayers[i]->stopTurn();
00381   }
00382   // enable input of current player
00383   Player* player = mPlayers[playerNumber];
00384   player->startTurn();
00385   mDisplay->showMove(playerNumber);
00386   mCurrentPlayer = playerNumber;
00387 
00388   emit signalNextPlayer(player);
00389 }
00390 
00391 
00392 // Check whether the two cards played are legal, supposed the
00393 // given player is the second one (as the first player always
00394 // plays a legal card)
00395 bool EngineTwo::isLegalMove(int card1, int card2, int playerNumber)
00396 {
00397   Suite suite1   = mDeck->getSuite(card1);
00398   Suite suite2   = mDeck->getSuite(card2);
00399   CardType type1 = mDeck->getCardType(card1);
00400   CardType type2 = mDeck->getCardType(card2);
00401 
00402   // Force trump colour as Jacks count as Trump
00403   if (type1 == Jack) suite1 = mTrump;
00404   if (type2 == Jack) suite2 = mTrump;
00405 
00406   // Same suite is always ok
00407   if (suite1 == suite2) return true;
00408 
00409   // Search if current player has a card of the same colour
00410   // but didn't play it (if it was played we checked already
00411   // above)
00412   Player* p= player(playerNumber);
00413   bool validMove = true;
00414   for (int i=0;i<8;i++)
00415   {
00416     int card = p->getCard(i);
00417     // Ignore played card
00418     if (card == card2) continue;
00419 
00420     // Check whether top card is still available - if not try bottom one
00421     if (card < 0) 
00422     {
00423       card = p->getCard(i + 8);
00424     }
00425     // This card is not available anymore
00426     if (card < 0) continue;
00427 
00428     // Analyse card
00429     Suite suite   = mDeck->getSuite(card);
00430     CardType type = mDeck->getCardType(card);
00431 
00432     // Force trump colour as Jacks count as Trump
00433     if (type == Jack) suite = mTrump;
00434 
00435     // Check whether current card matches the first player card
00436     if (suite == suite1)
00437     {
00438       validMove = false;
00439       break;
00440     }
00441   }
00442   return validMove;
00443 }
00444 
00445 
00446 // Check who won a move, the first or the second card.
00447 // The first card was played first and take precendence
00448 // when possible. The function returns 0 if the first
00449 // card won, 1 if the second card won.
00450 int EngineTwo::whoWonMove(int card1,int card2)
00451 {
00452   Suite suite1   = mDeck->getSuite(card1);
00453   Suite suite2   = mDeck->getSuite(card2);
00454   CardType type1 = mDeck->getCardType(card1);
00455   CardType type2 = mDeck->getCardType(card2);
00456 
00457   // Two jacks
00458   if (type1 == Jack && type2 == Jack)
00459   {
00460     if (suite1 < suite2) return 0;
00461     else return 1;
00462   }
00463   // One Jack wins always
00464   if ((int)type1 == (int)Jack) return 0;
00465   if ((int)type2 == (int)Jack) return 1;
00466 
00467   // Higher card wins if both have same suite
00468   if (suite1 == suite2)
00469   {
00470     // Check Ten because it is not in the right card
00471     // sequence. Ten is only beaten by Ace
00472     if (type1 == Ten)
00473     {
00474       if (type2 == Ace) return 1;
00475       else return 0;
00476     }
00477     if (type2 == Ten)
00478     {
00479       if (type1 == Ace) return 0;
00480       return 1;
00481     }
00482 
00483     // Otherwise the higher card wins
00484     if ((int)card1 < (int)card2) return 0;
00485     return 1;
00486   }
00487 
00488   if (global_debug > 0)
00489   {
00490     if (suite1 == mTrump) kDebug() << "FIRST card wins TRUMP" << endl;
00491     if (suite2 == mTrump) kDebug() << "SECOND card wins TRUMP" << endl;
00492   }
00493 
00494   // If cards are not of the same suite a trump wins
00495   if (suite1 == mTrump) return 0;
00496   if (suite2 == mTrump) return 1;
00497 
00498   // In all other cases the first card wins
00499   return 0;
00500 }
00501 
00502 
00503 #include "engine_two.moc"

Generated on Tue May 1 09:34:40 2007 for LSkat by  doxygen 1.4.6