File indexing completed on 2024-10-06 06:48:46
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"