aiinput.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 <QPixmap>
00023 #include <QTimer>
00024 
00025 // KDE includes
00026 #include <kdebug.h>
00027 
00028 // Local includes
00029 #include "lskatglobal.h"
00030 #include "aiinput.h"
00031 #include "player.h"
00032 #include "deck.h"
00033 
00034 
00035 // Constructor for the engine
00036 AiInput::AiInput(EngineTwo* engine, QObject* parent)
00037     : AbstractInput(parent)
00038 {
00039   // Store engine
00040   mEngine = engine;
00041 }
00042 
00043 
00044 // Allow or disallow input with this device 
00045 void AiInput::setInputAllowed(bool allowed)
00046 {
00047   AbstractInput::setInputAllowed(allowed);
00048   if (allowed) QTimer::singleShot(1000, this, SLOT(aiTurn()));
00049 }
00050 
00051 
00052 // Calculate and send out AI turn
00053 void AiInput::aiTurn()
00054 {
00055   // Turn was stopped meanwhile
00056   if (!mInputAllowed) return;
00057 
00058   if (global_debug > 5) kDebug() << "==================================================="<<endl;
00059   if (global_debug > 5) kDebug() << "AI TURN START " <<mInputAllowed<< endl;
00060 
00061   // Check we are the right player
00062   if (mId != mEngine->currentPlayer())
00063   {
00064     kFatal() << "AI plays for wrong player " << endl;
00065     return;
00066   }
00067 
00068   // Retrieve game board
00069   AiInput::Board board = getBoardFromEngine();
00070   AiInput::Move move;
00071 
00072   // Initiate move
00073   if (mEngine->currentMovePhase() == EngineTwo::FirstPlayerTurn)
00074   {
00075     if (global_debug > 5) kDebug() << "Performing initiual move "<<mId << endl;
00076     move = initiateMove(mId, board);
00077   }
00078   // Respond to move
00079   else
00080   {
00081     if (global_debug > 5) kDebug() << "Performing answer move "<<mId << endl;
00082     move = answerMove(mId, board);
00083   }
00084 
00085 
00086   // Send out move
00087   if (global_debug > 5) kDebug() << "AI player " << mId << " moves to " << move.move << endl;
00088   if (move.move>=0) emit signalPlayerInput(mId, mId, move.move);
00089   else kError() << "Illegal AI Move ??? " << endl;
00090 }
00091 
00092 
00093 // Extract the current game board from the engine
00094 AiInput::Board AiInput::getBoardFromEngine()
00095 {
00096   Board b;
00097   for (int i=0; i<2; i++)
00098   {
00099     Player* p = mEngine->player(i);
00100     for (int c=0; c<16; c++)
00101     {
00102       int card = p->getCard(c);
00103       b.cards[i][c] = card;
00104       b.points[i]  = p->points();
00105     }
00106   }
00107   b.whoseTurn = mEngine->currentPlayer();
00108   b.firstPlay = mEngine->currentMovePhase() == EngineTwo::FirstPlayerTurn;
00109   b.playedCard = mEngine->playedCard(0);
00110   return b;
00111 }
00112 
00113 
00114 // Game evaluation ratings
00115 #define RATING_SCHWARZ      100000.0
00116 #define RATING_SCHNEIDER     70000.0
00117 #define RATING_WON           50000.0
00118 #define RATING_REMIS         20000.0
00119 #define RATING_ONE_POINT       500.0
00120 
00121 // Evaluate the current game board and return a rating
00122 double AiInput::evaluteGame(int p, const AiInput::Board current)
00123 {
00124   double rating = 0.0;
00125   // Check for won games of our side
00126   if (current.points[p] == 120) rating += RATING_SCHWARZ;
00127   else if (current.points[p] >= 90) rating += RATING_SCHNEIDER;
00128   else if (current.points[p] > 60) rating += RATING_WON;
00129   else if (current.points[p] == 60) rating += RATING_REMIS;
00130   // Check for won games of other side
00131   if (current.points[1-p] == 120) rating -= RATING_SCHWARZ;
00132   else if (current.points[1-p] >= 90) rating -= RATING_SCHNEIDER;
00133   else if (current.points[1-p] > 60) rating -= RATING_WON;
00134   else if (current.points[1-p] == 60) rating -= RATING_REMIS;
00135 
00136   // Evaluate points
00137   rating += (current.points[p]-current.points[1-p])*RATING_ONE_POINT;
00138   return rating;
00139 }   
00140 
00141 
00142 // Initiate a new move as first player
00143 AiInput::Move AiInput::initiateMove(int p, const AiInput::Board& board)
00144 {
00145   AiInput::Move maxMove;
00146   maxMove.move  = -1;
00147   maxMove.value = -100.0*RATING_SCHWARZ; // Absolut minimum score
00148   
00149   // Loop all moves
00150   for (int m=0; m<8; m++)
00151   {
00152     AiInput::Board current(board);
00153     int card = current.cards[p][m];  // 1st card
00154     current.cards[p][m] = -1; // Can do in any case
00155     if (card < 0)
00156     {
00157       card = current.cards[p][m+8]; // 2nd card
00158       current.cards[p][m+8] = -1; // Can do in any case
00159     }
00160     if (card < 0) continue; // Illegal move
00161     // Store move
00162     current.playedCard = card;
00163     if (global_debug > 5) kDebug() << "First mover try move on " << m << " ("<<Deck::name(card) <<endl;
00164     AiInput::Move answer = answerMove(1-p, current);
00165     // Negate answering moves value to get our rating
00166     double rating = -answer.value;
00167     if (global_debug > 5) kDebug() << "First mover yields rating of " << rating << endl;
00168     // New best move?
00169     if (rating > maxMove.value)
00170     {
00171       maxMove.value = rating;
00172       maxMove.move  = m;
00173     }
00174   }
00175   
00176   return maxMove;
00177 }
00178 
00179 
00180 // Answer a move as second player
00181 AiInput::Move AiInput::answerMove(int p, const AiInput::Board& board)
00182 {
00183   AiInput::Move maxMove;
00184   maxMove.move  = -1;
00185   maxMove.value = -100.0*RATING_SCHWARZ; // Absolut minimum score
00186   
00187   // Loop all moves
00188   for (int m=0; m<8; m++)
00189   {
00190     AiInput::Board current(board);
00191    // kDebug() << "CARD "<<m<< " is " 
00192     //          << Deck::name(current.cards[p][m]) << " on top of " 
00193     //          << Deck::name(current.cards[p][m+8]) << endl;
00194 
00195     int card = current.cards[p][m];  // 1st card
00196     current.cards[p][m] = -1; // Can do in any case
00197     if (card < 0)
00198     {
00199       card = current.cards[p][m+8]; // 2nd card
00200       current.cards[p][m+8] = -1; // Can do in any case
00201     }
00202     if (card < 0) continue; // Illegal move
00203 
00204     // Check validity of move
00205     if (!mEngine->isLegalMove(current.playedCard, card, p)) continue;
00206 
00207     // Check move winner
00208     int winner = mEngine->whoWonMove(current.playedCard, card);
00209     if (global_debug > 5)
00210       kDebug() << "   Card " << m<< " (" << Deck::name(card) << ") is valid " 
00211                 << " countering " << Deck::name(current.playedCard)<<" with "
00212                 << " winner (0:other, 1:we) " << winner << endl;
00213     int deltaPoints = 0;
00214     deltaPoints += Deck::getCardValue(current.playedCard);
00215     deltaPoints += Deck::getCardValue(card);
00216     // The first mover won
00217     if (winner == 0)
00218     {
00219       current.points[1-p] += deltaPoints;
00220     }
00221     // The second mover won (us)
00222     else
00223     {
00224       current.points[p] += deltaPoints;
00225     }
00226 
00227     double rating = evaluteGame(p, current);
00228 
00229 
00230     if (global_debug > 5)
00231       kDebug() << "   Points after 2nd move "<<m<<" would be we: " 
00232                 << current.points[p] << " other: " << current.points[1-p] 
00233                 << " rating is thus " << rating << endl;
00234     // New best move?
00235     if (rating > maxMove.value)
00236     {
00237       maxMove.value = rating;
00238       maxMove.move  = m;
00239     }
00240   }
00241   return maxMove;
00242 }
00243 
00244 
00245 // Board copy constructor
00246 AiInput::Board::Board(const AiInput::Board& board)
00247 {
00248    for (int i=0;i<2;i++)
00249    {
00250      points[i] = board.points[i];
00251      for (int j=0;j<16;j++)
00252      {
00253        cards[i][j] = board.cards[i][j];
00254      }
00255    }
00256    playedCard = board.playedCard;
00257    whoseTurn = board.whoseTurn;
00258    firstPlay = board.firstPlay;     
00259 }
00260 
00261 
00262 #include "aiinput.moc"

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