File indexing completed on 2024-04-21 04:04:05

0001 /***************************************************************************
0002                           aiplayer.cpp  -  description
0003                              -------------------
0004     begin                : sam sep 14 2002
0005     copyright            : (C) 2002 by Gael de Chalendar
0006     email                : kleag@free.fr
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *   This program is free software; you can redistribute it and/or modify  *
0012  *   it under the terms of the GNU General Public License as published by  *
0013  *   the Free Software Foundation; either either version 2
0014    of the License, or (at your option) any later version.of the License, or     *
0015  *   (at your option) any later version.                                   *
0016  *                                                                         *
0017  *   You should have received a copy of the GNU General Public License
0018  *   along with this program; if not, write to the Free Software
0019  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0020  *   02110-1301, USA
0021  ***************************************************************************/
0022 
0023 /* Local includes */
0024 #include "aiplayer.h"
0025 #include "aiplayerio.h"
0026 #include "dice.h"
0027 #include "nationality.h"
0028 #include "onu.h"
0029 #include "kgamewin.h"
0030 #include "gameautomaton.h"
0031 
0032 #define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API
0033 #include <libkdegamesprivate/kgame/kplayer.h>
0034 
0035 
0036 /* Includes for KDE */
0037 #include "ksirk_debug.h"
0038 #include <KLocalizedString>
0039 #include <KMessageBox>
0040 #include <QUuid>
0041 #include <QMutexLocker>
0042 #include <QMap>
0043 
0044 
0045 /* Includes for the STL */
0046 // #include <utility>
0047 // #include <map>
0048 
0049 // #include <stdlib.h>
0050 
0051 namespace Ksirk
0052 {
0053 
0054 namespace GameLogic
0055 {
0056 
0057 /**
0058   * Constructor with simple initializations
0059   */
0060 AIPlayer :: AIPlayer(
0061         const QString & nomPlayer,
0062         unsigned int nbArmies,
0063          Nationality * myNation,
0064          PlayersArray& players,
0065          ONU* world,
0066          GameAutomaton* game ) :
0067     Player(game, nomPlayer, nbArmies, myNation) ,
0068   allPlayers(players),
0069   m_world(world),
0070   m_game(game),
0071   m_src(nullptr), m_dest(nullptr),
0072   m_toMove(std::numeric_limits< unsigned int>::max()),
0073   m_hasVoted(false),
0074   m_actionWaitingStart(false),
0075   m_thread(*this)
0076 {
0077   m_thread.setStopMe(true);
0078 //   qCDebug(KSIRK_LOG) << "AIPlayer constructor";
0079 }
0080 
0081 AIPlayer::~AIPlayer()
0082 {
0083   qCDebug(KSIRK_LOG) << name();
0084   m_thread.terminate();
0085   m_thread.wait();
0086 }
0087 
0088 /**
0089   * This function is called whenever the player should choose an action (
0090   * attack, defense, etc.). It has the responsibility to choose the correct
0091   * action depending on the state of the game.
0092   */
0093 void AIPlayer::actionChoice(GameLogic::GameAutomaton::GameState state)
0094 {
0095   if (m_game && m_game->currentPlayer())
0096   {
0097     qCDebug(KSIRK_LOG) << name() << ": (state is " << m_game-> stateName() << ", current player is "
0098       << m_game-> currentPlayer()->name()<<")";
0099   }
0100   if (m_game->m_aicannotrunhack)
0101   {
0102     qCDebug(KSIRK_LOG) << "HACK HACK AIPlayer " << name()   
0103         << ": game says AIs cannot run...";
0104     return;
0105   }
0106   if (m_game->game()->haveAnimFighters() )
0107   {
0108     return;
0109   }
0110   if (!m_waitedAck.isEmpty())
0111   {
0112     qCDebug(KSIRK_LOG) << Player::name() << " waiting to receive ack " << m_waitedAck;
0113     return;
0114   }
0115   QByteArray buffer;
0116   QDataStream stream(&buffer, QIODevice::WriteOnly);
0117   QByteArray buffer2;
0118   QDataStream stream2(&buffer2, QIODevice::WriteOnly);
0119   if ( (m_game-> currentPlayer() == this)
0120     || (state == GameLogic::GameAutomaton::WAITDEFENSE && (m_game-> currentPlayer() != this))
0121     ||  (state == GameLogic::GameAutomaton::WAIT_RECYCLING && m_game-> currentPlayer()->isVirtual() ) )
0122   {
0123     qCDebug(KSIRK_LOG) << name()  << " : choosing my action";
0124     switch (state)
0125     {
0126       case GameLogic::GameAutomaton::WAITDEFENSE :
0127         chooseDefenseAction();
0128         break;
0129       case GameLogic::GameAutomaton::WAIT_RECYCLING :
0130         chooseWetherToRecycle();
0131         break;
0132       case GameLogic::GameAutomaton::INVADE :
0133         chooseInvasionAction();
0134         break;
0135       case GameLogic::GameAutomaton::WAIT :
0136 //         qCDebug(KSIRK_LOG) << "WAIT " << name();
0137         if (!m_actionWaitingStart)
0138           chooseAttackMoveArmiesOrNextPlayer();
0139   //if (m_src != 0 && m_dest != 0)
0140         //{
0141     //stream << QString("actionLButtonDown") << m_src->centralPoint();
0142     //aiPlayerIO()->sendInput(stream,true);
0143           
0144   //}
0145         break;
0146       case GameLogic::GameAutomaton::WAIT1:
0147         m_actionWaitingStart = false;
0148 
0149         chooseInvasionAction();
0150         if (m_src != nullptr && m_dest != nullptr
0151             && m_src->owner() == m_dest->owner())
0152         {
0153           stream << QString("actionLButtonUp") << m_dest->centralPoint();
0154           m_src = nullptr;
0155           m_dest = nullptr;
0156           aiPlayerIO()->sendInput(stream,true);
0157           //m_game->state(GameAutomaton::ATTACK2);
0158         }
0159 
0160   
0161     /*stream << QString("actionAttack2") << point;
0162     
0163       qCCritical(KSIRK_LOG) << "The attacker tries to attack with a number of armies different of 1, 2 or 3: that's impossible!";
0164       //exit();*/
0165   
0166         break;
0167       case GameLogic::GameAutomaton::INIT: 
0168         break;
0169       case GameLogic::GameAutomaton::INTERLUDE: ;
0170       case GameLogic::GameAutomaton::NEWARMIES :
0171         placeArmiesAction();
0172         break;
0173       case GameLogic::GameAutomaton::ATTACK2 :
0174         /*if (m_dest != 0)
0175         {
0176           //stream << QString("actionLButtonUp") << m_dest->centralPoint();
0177           m_src = 0;
0178           m_dest = 0;
0179           //aiPlayerIO()->sendInput(stream,true);
0180         }*/
0181         break;
0182       case GameLogic::GameAutomaton::SHIFT1 :
0183         if (m_src != nullptr && m_dest != nullptr)
0184         {
0185           /*stream << QString("actionLButtonDown") << m_src->centralPoint();
0186           aiPlayerIO()->sendInput(stream,true);
0187           stream2 << QString("actionLButtonUp") << m_dest->centralPoint();
0188   //         m_toMove = 0;
0189           aiPlayerIO()->sendInput(stream2,true);*/
0190         }
0191         break;
0192       case GameLogic::GameAutomaton::SHIFT2 :
0193         if (m_dest != nullptr)
0194         {
0195           chooseNbToMoveOrStop();
0196         }
0197         break;
0198       case GameLogic::GameAutomaton::GAME_OVER :
0199         stop();
0200         break;
0201       default :;
0202 //         qCDebug(KSIRK_LOG) << "OTHER STATE:" << state << " "  << name();
0203     }
0204     requestAck();
0205     if (m_game-> currentPlayer() != this)
0206       m_actionWaitingStart = false;
0207   }
0208 //    qCDebug(KSIRK_LOG) << "OUT";
0209 }
0210 
0211 /**
0212   * Chooses the next action. In the current basic setting, chooses at random
0213   * between the three possibilities. For each, chooses randomly the parameters.
0214   * If the randomly chosen parameters end by an impossible action,  continue
0215   * with next player.
0216   */
0217 void AIPlayer::chooseAttackMoveArmiesOrNextPlayer()
0218 {
0219 //     qCDebug(KSIRK_LOG) << "AIPlayer::chooseAttackMoveArmiesOrNextPlayer() ";
0220   m_actionWaitingStart = true;
0221   if ( m_game->game()->haveMovingArmies())
0222   {
0223     return;
0224   }
0225   unsigned int dice = Dice::roll(12);
0226 //     qCDebug(KSIRK_LOG) << "AIPlayer Dice rolled on " << dice ;
0227   switch ( dice )
0228   {
0229     case 1: ; case 2:; case 3:; case 4:;case 5: ; case 6:;case 7:;case 8:;case 9: ;case 10: ; case 11: // attack
0230     {
0231       if (!attackAction())
0232       {
0233         nextPlayerAction();
0234       }
0235     }
0236     break;
0237 /*        case 11 : // next player
0238             nextPlayerAction();
0239         break;
0240 */
0241     case 12 : // move armies
0242       moveArmiesAction();
0243     break;
0244   }
0245 //    qCDebug(KSIRK_LOG) <<"OUT AIPlayer::chooseAttackMoveArmiesOrNextPlayer()";
0246 }
0247 
0248 /**
0249   * Returns a pair of countries where the attacker have enough armies to attack
0250   * and the defender is a ennemy neighbour of the attacker
0251   */
0252 QPair<const Country*, const Country*> AIPlayer::chooseBelligerant()
0253 {
0254   QMultiMap<const Country*, const Country*> candidates;
0255 
0256 //     qCDebug(KSIRK_LOG) << name() << " : AIPlayer::chooseBelligerant()";
0257     // Builds the list of countries of the player that have enough armies and a good neighbour
0258   QList<Country*> list = countries();
0259   if ( ! list.empty() )
0260   {
0261     QList<Country*>::iterator outer = list.begin();
0262     const Country* candidateSource;
0263 //        qCDebug(KSIRK_LOG) << name() << "  choosing belligerants, candidate sources ";
0264     while ( ( outer != list.end()) && ( (candidateSource = *outer) != nullptr ) )
0265     {
0266 //            qCDebug(KSIRK_LOG) << name() << "  choosing belligerants, looking at candidate source : " << candidateSource-> name();
0267             // Enough armies
0268       if ( candidateSource-> nbArmies() > 1 )
0269       {
0270 //                qCDebug(KSIRK_LOG) << name() << "  choosing belligerants, candidate source has enough armies.";
0271 //                qCDebug(KSIRK_LOG) << name() << "  choosing belligerants, candidate targets ";
0272         for ( int inner = 0; inner < m_world-> getCountries().size(); inner++)
0273         {
0274           const Country* candidateTarget = m_world-> getCountries().at(inner);
0275 //                    qCDebug(KSIRK_LOG) << name() << "  choosing belligerants, looking at candidate target : " << candidateTarget-> name();
0276                     // Enemy neigbour
0277           if (            ( candidateTarget != candidateSource ) 
0278                   &&     (candidateSource-> owner() != candidateTarget-> owner())
0279                   &&     (candidateSource-> communicateWith(candidateTarget) )
0280                   &&     !(candidateTarget->name().contains("NULL") ) )
0281           {
0282 //                        qCDebug(KSIRK_LOG) << name() << "  choosing belligerants, adding target / source : "
0283 //                                << candidateSource-> name() << " / " << candidateTarget-> name();
0284               candidates.insert(candidateSource, candidateTarget);
0285           }
0286         }
0287       }
0288       ++outer;
0289     }
0290     if ( candidates.size() == 0 )
0291     {
0292 //            qCDebug(KSIRK_LOG) << name() << " OUT AIPlayer::chooseBelligerant() ; map size = 0 ; it isn't possible to attack.";
0293       return (qMakePair<const Country*, const Country*>(static_cast< Country*>(nullptr), static_cast< Country*>(nullptr)));
0294     }
0295     uint which = Dice::roll(candidates.size()) - 1;
0296 //        qCDebug(KSIRK_LOG) << "Which = " << which;
0297     QMultiMap<const Country*, const Country*>::const_iterator it;
0298     unsigned int i = 0;
0299     for ( it = candidates.constBegin(); it != candidates.constEnd() ; it++, i++ )
0300     {
0301       if (which == i )
0302       {
0303 //                qCDebug(KSIRK_LOG) << "OUT AIPlayer::chooseBelligerant() : " << endl ;
0304          return qMakePair(it.key(),it.value());
0305       }
0306     }
0307   }
0308 //    qCDebug(KSIRK_LOG) << "OUT AIPlayer::chooseBelligerant() : do I own no country ???";
0309   return (qMakePair<const Country*, const Country*>(static_cast< Country*>(nullptr), static_cast< Country*>(nullptr)));
0310 }
0311 
0312 /**
0313   * Chooses a country to receive a new army in dotation. random choice in the 
0314   * list of the player countries that have at least one neigbour belonging to 
0315   * someone else
0316   */
0317 Country* AIPlayer::chooseReceivingCountry()
0318 {
0319 //     qCDebug(KSIRK_LOG) << "AIPlayer::chooseReceivingCountry()";
0320   QList<Country*> myCountries = countries();
0321   if (myCountries.size() == 0)
0322   {
0323     qCCritical(KSIRK_LOG) << "AIPlayer::chooseReceivingCountry() EMPTY LIST";
0324     return nullptr;
0325   }
0326   QList<Country*> withNeighbours;
0327   
0328   for (int i = 0 ; i < myCountries.size(); i++)
0329   {
0330     if ( ( m_world-> neighboursNotBelongingTo(*(myCountries.at(i)), static_cast< const Player * >(this) ) ).size() )
0331         withNeighbours.push_back(myCountries.at(i));
0332   }
0333 
0334   int which = Dice::roll(withNeighbours.size()) - 1;
0335   if (which == -1)
0336   {
0337     qCDebug(KSIRK_LOG) << Player::name() << " has no enemy neighbour... should not happen.";
0338   }
0339 //    qCDebug(KSIRK_LOG) << "\tChoosed: " << list.at(which)-> name();
0340     
0341   return withNeighbours.at(which);
0342 //    qCDebug(KSIRK_LOG) << "OUT AIPlayer::chooseReceivingCountry()";
0343 }
0344 
0345 /** 
0346   * Returns true (an AIPlayer is an AI)
0347   */
0348 bool AIPlayer::isAI() const
0349 {
0350   return true;
0351 }
0352 
0353 void AIPlayer::MyThread::run()
0354 {
0355   qCDebug(KSIRK_LOG) << me.name();
0356   stopMe = false;
0357   while ( ! stopMe )
0358   {
0359     me.actionChoice(me.m_game->state());
0360     msleep( 500 );
0361   }
0362   qCDebug(KSIRK_LOG) << "OUT";
0363 }
0364 
0365 /** set stopMe to true in order for the run method to return */
0366 void AIPlayer::stop()
0367 {
0368   m_thread.setStopMe(true);
0369 }
0370 
0371 /**
0372   * make all what is necessary to prepare and launch an attack
0373   */
0374 bool AIPlayer::attackAction() 
0375 {
0376 //   qCDebug(KSIRK_LOG) << "AIPlayer::attackAction";
0377   QPair<const Country* , const Country* > srcDest = chooseBelligerant();
0378   if ( (srcDest.first == nullptr) || (srcDest.second == nullptr) )
0379   {
0380 //     qCDebug(KSIRK_LOG) << "AIPlayer::attackAction: no attack available";
0381 //       nextPlayerAction(); 
0382       return false;
0383   }
0384   m_src = srcDest.first;
0385   m_dest = srcDest.second;
0386 
0387   QByteArray buffer;
0388   QDataStream stream(&buffer, QIODevice::WriteOnly);
0389   stream << QString("actionLButtonDown") << m_src->centralPoint();
0390   aiPlayerIO()->sendInput(stream,true);
0391 
0392   QByteArray buffer2;
0393   QDataStream stream2(&buffer2, QIODevice::WriteOnly);
0394   stream2 << QString("actionLButtonUp") << m_dest->centralPoint();
0395   aiPlayerIO()->sendInput(stream2,true);
0396 
0397   uint srcNbArmies = m_src->nbArmies();
0398   qCDebug(KSIRK_LOG) << Player::name()  << " : ATTACK";
0399   qCDebug(KSIRK_LOG) << "    " << Player::name()  << " : attacks from "  << m_src-> name() 
0400                   << " (" << srcNbArmies << " armies)";
0401   qCDebug(KSIRK_LOG) << "    " << Player::name()  << " : attacks " << m_dest-> name();
0402       
0403   uint nbAttack = 0;
0404   if (srcNbArmies == 1)
0405   {
0406     qCCritical(KSIRK_LOG) << "AI player " << Player::name() << " country " << m_src->nbArmies() << "have only one army. Should not be chosen to attack.";
0407     m_thread.exit();
0408   }
0409   if (srcNbArmies >= 2) {nbAttack = 1;}
0410   if (srcNbArmies >= 3) {nbAttack = 2;}
0411   if (srcNbArmies >= 4) {nbAttack = 3;}
0412   m_nbAttack = nbAttack;
0413   qCDebug(KSIRK_LOG) << "    " << Player::name()  << " : attacks with " << nbAttack << " armies.";
0414 
0415   QPointF point;
0416   QByteArray buffer3;
0417   QDataStream stream3(&buffer3, QIODevice::WriteOnly);
0418   switch (nbAttack)
0419   {
0420     case 1: 
0421     stream3 << QString("actionAttack1") << point;
0422     break;
0423     case 2: 
0424     stream3 << QString("actionAttack2") << point;
0425     break;
0426     case 3: 
0427     stream3 << QString("actionAttack3") << point;
0428     break;
0429     default:
0430       qCCritical(KSIRK_LOG) << "The attacker tries to attack with a number of armies different of 1, 2 or 3: that's impossible!";
0431       m_thread.exit();
0432   }
0433   aiPlayerIO()->sendInput(stream3,true);
0434 //   requestAck();
0435 
0436   qCDebug(KSIRK_LOG) << "AIPlayer " << Player::name()  << " : attackAction : "  << m_src-> name() << " " << m_dest-> name()
0437     << " " << nbAttack ;
0438   stop();
0439   return true;
0440 }
0441 
0442 /**
0443   * makes all what is necessary to prepare and start the moving of armies
0444   */
0445 bool AIPlayer::moveArmiesAction()
0446 {
0447   qCDebug(KSIRK_LOG) << "AIPlayer::moveArmiesAction";
0448   QList<Country*> srcList = countries() ;
0449   if (srcList.size() == 0) 
0450   {
0451     nextPlayerAction(); 
0452     return false;
0453   }
0454   uint which = Dice::roll(srcList.size()) - 1;
0455   Country* osrc =  srcList.at(which);
0456 //    qCDebug(KSIRK_LOG) << "AIPlayer::moveArmiesAction() MOVEARMIES 1";
0457   if (osrc-> nbArmies() <= 1) 
0458   {
0459     nextPlayerAction();
0460     return false;
0461   }
0462 //    qCDebug(KSIRK_LOG) << "AIPlayer::moveArmiesAction() MOVEARMIES 2";
0463   QList<Country*> destList( m_world-> neighboursBelongingTo(*osrc, this) );
0464 //    qCDebug(KSIRK_LOG) << "AIPlayer::moveArmiesAction() MOVEARMIES 3";
0465   if (destList.size() == 0) 
0466   {
0467     nextPlayerAction();
0468     return false;
0469   }
0470   which = Dice::roll(destList.size()) - 1 ;
0471 //    qCDebug(KSIRK_LOG) << "AIPlayer::moveArmiesAction() MOVEARMIES 4";
0472   Country* odest =  destList.at(which);
0473   m_src = osrc;
0474   m_dest = odest;
0475 
0476   QByteArray buffer;
0477   QDataStream stream(&buffer, QIODevice::WriteOnly);
0478   stream << QString("actionLButtonDown") << osrc->centralPoint();
0479   aiPlayerIO()->sendInput(stream,true);
0480 
0481   QByteArray buffer2;
0482   QDataStream stream2(&buffer2, QIODevice::WriteOnly);
0483   stream2 << QString("actionLButtonUp") << odest->centralPoint();
0484   aiPlayerIO()->sendInput(stream2,true);
0485 //   requestAck();
0486   
0487   qCDebug(KSIRK_LOG) << "AIPlayer ****************" << Player::name()  << " : moveAction : "  << osrc-> name() << " " << odest-> name();
0488 
0489   return true;
0490 }
0491 
0492 /**
0493  * chooses a country where to place a new army
0494  */
0495 void AIPlayer::placeArmiesAction() 
0496 {
0497   qCDebug(KSIRK_LOG) << "AIPlayer::placeArmiesAction " << Player::name() << " ; nb to place: " << getNbAvailArmies();
0498   if (getNbAvailArmies() > 0)
0499   {
0500     m_hasVoted = false;
0501     const Country* receiver = chooseReceivingCountry();
0502     if (receiver == nullptr)
0503     {
0504       QString msg = i18np("Error - No receiving country selected while computer player %2 had still 1 army to place. This is bug probably #2232 at www.gna.org.", "Error - No receiving country selected while computer player %2 had still %1 armies to place. This is bug probably #2232 at www.gna.org.", getNbAvailArmies(), Player::name());
0505       qCCritical(KSIRK_LOG) << msg;
0506       KMessageBox::error(nullptr, msg, i18n("Fatal Error"));
0507       m_thread.exit();
0508       m_thread.wait();
0509     }
0510     qCDebug(KSIRK_LOG) << "Placing an army in " << receiver->name() 
0511         << " ; point=" << receiver->centralPoint();
0512     QByteArray buffer;
0513     QDataStream stream(&buffer, QIODevice::WriteOnly);
0514     stream << QString("actionLButtonDown") << receiver->centralPoint();
0515     aiPlayerIO()->sendInput(stream,true);
0516 
0517 //     requestAck();
0518   }
0519   else if (m_game->state() != GameAutomaton::INTERLUDE)
0520   {
0521     qCDebug(KSIRK_LOG) << "No more armies to place: next player";
0522     stop();
0523     QPointF point;
0524     m_game->gameEvent("actionNextPlayer", point);
0525   }
0526   else
0527   {
0528     chooseWetherToRecycle();
0529   }
0530   
0531 }
0532 
0533 /**
0534  * Takes the decision to recycle armies or not
0535  */
0536 void AIPlayer::chooseWetherToRecycle() 
0537 {
0538   qCDebug(KSIRK_LOG) << Player::name();
0539   if (m_game->allLocalPlayersComputer())
0540   {
0541     if (!m_hasVoted)
0542     {
0543       qCDebug(KSIRK_LOG) << "Voting for end of recycling";
0544       QPointF p;
0545       m_game->gameEvent( "actionRecyclingFinished", p );
0546       m_hasVoted = true;
0547     }
0548     else
0549     {
0550       qCDebug(KSIRK_LOG) << "Has already voted";
0551     }
0552   }
0553   else
0554   {
0555     qCDebug(KSIRK_LOG) << "There is local non computer players; let them vote.";
0556   }
0557   stop();
0558 }
0559 
0560 /**
0561  * chooses to continue invasion with a certain amount of armies or to stop it
0562  */
0563 void AIPlayer::chooseInvasionAction()
0564 {
0565   QByteArray buffer;
0566   QDataStream stream(&buffer, QIODevice::WriteOnly);
0567   qCDebug(KSIRK_LOG) << QString("AIPlayer::chooseInvasionAction");
0568   int nbArmiesToMove = Dice::roll(m_game->game()-> firstCountry()-> nbArmies()) - 1;
0569   QPointF point;
0570   while (nbArmiesToMove >= 10) 
0571   {
0572     stop(); 
0573     stream << QString("actionInvade10") << point;
0574     nbArmiesToMove -= 10;
0575   }
0576   while (nbArmiesToMove >= 5) 
0577   { 
0578     stop();
0579     stream << QString("actionInvade5") << point;
0580     nbArmiesToMove -= 5;
0581   }
0582   while (nbArmiesToMove >= 1) 
0583   { 
0584     stop();
0585     stream << QString("actionInvade1") << point;
0586     nbArmiesToMove--;
0587   }
0588   stream << QString("actionInvasionFinished") << point;
0589   stop();
0590   aiPlayerIO()->sendInput(stream,true);
0591 //   requestAck();
0592 }
0593 
0594 /**
0595   * chooses whether to defend with one or two armies. Always chooses the maximum possible
0596   */
0597 void AIPlayer::chooseDefenseAction()
0598 {
0599   QByteArray buffer;
0600   QDataStream stream(&buffer, QIODevice::WriteOnly);
0601   QPointF point;
0602   if ((m_game-> currentPlayer() == this) && ((!m_game->isDefenseAuto()) || (m_game->game()->secondCountry() != m_game->getDefCountry())))
0603   {
0604     qCDebug(KSIRK_LOG) << "AIPlayer::chooseDefenseAction waiting defense of another one; nothing to do.";
0605     m_game->setDefenseAuto(false);
0606   }
0607   else
0608   {
0609     qCDebug(KSIRK_LOG) << "AIPlayer::chooseDefenseAction " << Player::name();
0610     switch (m_game-> currentPlayer()-> getNbAttack())
0611     {
0612       case 1:
0613       stream << QString("slotDefense1") << point;
0614 //         m_game->slotDefense1();
0615       break;
0616       case 2: ; case 3:
0617         if (m_game-> game()-> secondCountry()-> nbArmies() > 1)
0618           stream << QString("slotDefense2") << point;
0619 //       m_game->slotDefense2();
0620         else
0621           stream << QString("slotDefense1") << point;
0622 //       m_game->slotDefense1();
0623       break;
0624       default:
0625         qCCritical(KSIRK_LOG) << "The attacker attacks with a number of armies different of 1, 2 or 3: that's impossible!";
0626         m_thread.exit();
0627     }
0628     stop();
0629     aiPlayerIO()->sendInput(stream,true);
0630 //     requestAck();
0631   }
0632 }
0633 
0634 /**
0635  * makes what is necessary to finish my turn
0636  */
0637 void AIPlayer::nextPlayerAction()
0638 {
0639   qCDebug(KSIRK_LOG) << "AIPlayer::nextPlayerAction";
0640   QPointF point;
0641   QByteArray buffer;
0642   QDataStream stream(&buffer, QIODevice::WriteOnly);
0643   stream << QString("actionNextPlayer") << point;
0644   aiPlayerIO()->sendInput(stream,true);
0645 //   requestAck();
0646   stop();
0647 }
0648 
0649 void AIPlayer::saveXml(QTextStream& xmlStream)
0650 {
0651   xmlStream << "<player ai=\"true\" ";
0652   innerSaveXml(xmlStream);
0653   xmlStream << " />";
0654 }
0655 
0656 /** 
0657  * Makes the choice of nb armies to move during an invasion or an end of turn
0658  * moving 
0659  */
0660 void AIPlayer::chooseNbToMoveOrStop()
0661 {
0662   QByteArray buffer;
0663   QDataStream stream(&buffer, QIODevice::WriteOnly);
0664   QPointF point;
0665   if (m_toMove == std::numeric_limits< unsigned int>::max())
0666   {
0667     if (m_src == nullptr)
0668     {
0669       m_toMove = 0;
0670     }
0671     else
0672     {
0673       m_toMove = Dice::roll(m_src->nbArmies() - 1);
0674     }
0675   }
0676   if (m_toMove >= 10)
0677   {
0678     stream << QString("actionInvade10") << point;
0679     m_toMove -= 10;
0680   }
0681   else if (m_toMove >= 5)
0682   {
0683     stream << QString("actionInvade5") << point;
0684     m_toMove -= 5;
0685   }
0686   else if (m_toMove >= 1)
0687   {
0688     stream << QString("actionInvade1") << point;
0689     m_toMove -= 1;
0690   }
0691   else // m_toMove == 0
0692   {
0693     stream << QString("actionInvasionFinished") << point;
0694     m_toMove = std::numeric_limits< unsigned int>::max();
0695     stop();
0696   }
0697   aiPlayerIO()->sendInput(stream,true);
0698 }
0699 
0700 AIPlayerIO* AIPlayer::aiPlayerIO()
0701 {
0702   KGameIOList* iolist = ioList();
0703   for ( int i = 0; i < iolist->count(); ++i )
0704     if ( iolist->at(i) && iolist->at(i)->rtti() == AIPLAYERIO )
0705       return dynamic_cast<AIPlayerIO*>(iolist->at(i));
0706   
0707   return nullptr;
0708 }
0709 
0710 void AIPlayer::requestAck()
0711 {
0712   QMutexLocker locker(&m_waitedAckMutex);
0713   m_waitedAck = QUuid::createUuid().toString();
0714   QByteArray buffer;
0715   QDataStream stream(&buffer, QIODevice::WriteOnly);
0716   QPointF p;
0717   qCDebug(KSIRK_LOG) << name() << " sending a request for ack " << m_waitedAck ;
0718   stream << QString("requestForAck") << p << m_waitedAck;
0719   aiPlayerIO()->sendInput(stream,true);
0720 }
0721 
0722 } // closing namespace GameLogic
0723 } // closing namespace Ksirk
0724 
0725 #include "moc_aiplayer.cpp"