File indexing completed on 2024-04-28 04:02:08

0001 /*
0002     This file is part of the KDE games kwin4 program
0003     SPDX-FileCopyrightText: 2006 Martin Heni <kde@heni-online.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 /* Note: The AI engine of kwin4 does on purpose not implement a perfect
0009  *       Connect-4(tm) engine but tries to play more human as playing against
0010  *       a perfect engine is only frustrating. Connect four is proven to
0011  *       always win for the first player with perfect play.
0012  *       see e.g. the Velena AI Engine http://web.archive.org/web/20180219021151/http://www.ce.unipr.it/~gbe/velena.html
0013  */
0014 
0015 #include "kwin4doc.h"
0016 
0017 // own
0018 #include "config-src.h"
0019 #include "kfourinline_debug.h"
0020 #include "kwin4gamesequence.h"
0021 #include "kwin4view.h"
0022 #include "prefs.h"
0023 #include "score.h"
0024 #include "scoresprite.h"
0025 #include "ui_statuswidget.h"
0026 // KF
0027 #include <KLocalizedString>
0028 // Qt
0029 #include <QDir>
0030 #include <QStandardPaths>
0031 #include <QTimer>
0032 
0033 #define FIELD_SIZE_X 7
0034 #define FIELD_SIZE_Y 6
0035 
0036 // Constructor
0037 KWin4Doc::KWin4Doc(QWidget *parent)
0038     : KGame(1234, parent)
0039     , pView()
0040     , mHintProcess()
0041 {
0042     setGameSequence(new KWin4GameSequence(this));
0043     mStatus = new Score(parent);
0044 
0045     connect(this, &KWin4Doc::signalPropertyChanged, this, &KWin4Doc::gamePropertyChanged);
0046 
0047     dataHandler()->Debug();
0048     // qCDebug(KFOURINLINE_LOG) << "Property 7 policy=" << dataHandler()->find(7)->policy();
0049     setPolicy(KGame::PolicyDirty, true);
0050 
0051     // qCDebug(KFOURINLINE_LOG) << "Property 7 policy=" << dataHandler()->find(7)->policy();
0052 
0053     // Game design
0054     setMaxPlayers(2);
0055     setMinPlayers(2);
0056 
0057     // Game initialization
0058     mField.resize(42);
0059 
0060     // ****************************************
0061     // NOTE: Do not i18n the strings here. They
0062     //       are for debugging only
0063     // ****************************************
0064 
0065     // The field array needs not be updated as any move will change it
0066     // Careful only in new resetGame! Maybe unlocal it there!
0067     //  mField.setPolicy(KGamePropertyBase::PolicyLocal);
0068     mField.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mField"));
0069 
0070     mFieldFilled.resize(7);
0071     mHistory.resize(43);
0072     mHistory.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mHistory"));
0073 
0074     mAmzug.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mAmzug"));
0075     mCurrentMove.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mCurrentMove"));
0076     mMaxMove.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mMaxMove"));
0077     mFieldFilled.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mFieldFilled"));
0078     mHistoryCnt.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mHistoryCnt"));
0079     mLastColumn.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mLastColumn"));
0080     mLastHint.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mLastHint"));
0081     mLastColour.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mLastColour"));
0082     mScore.registerData(dataHandler(), KGamePropertyBase::PolicyLocal, QStringLiteral("mScore"));
0083 
0084     // game startup parameter
0085     mStartPlayer = Yellow;
0086     mStartPlayer.registerData(dataHandler(), KGamePropertyBase::PolicyDirty, QStringLiteral("mStartPlayer"));
0087     setCurrentPlayer((COLOUR)mStartPlayer.value());
0088     if (global_debug > 1)
0089         qCDebug(KFOURINLINE_LOG) << "amZug policy=" << mAmzug.policy();
0090 
0091     mPlayedBy[Yellow] = KGameIO::MouseIO;
0092     mPlayedBy[Red] = KGameIO::MouseIO;
0093 
0094     // AI support
0095     mAIValues.resize(42);
0096 
0097     // last in init
0098     resetGame(false);
0099 
0100     setGameStatus(Intro);
0101 
0102     // Listen to network
0103     connect(this, &KWin4Doc::signalMessageUpdate, this, &KWin4Doc::networkMessageUpdate);
0104     connect(this, &KWin4Doc::signalClientJoinedGame, this, &KWin4Doc::clientConnected);
0105 
0106     // Change global KGame policy
0107     // dataHandler()->setPolicy(KGamePropertyBase::PolicyDirty,false);
0108     dataHandler()->Debug();
0109 }
0110 
0111 // Destructor
0112 KWin4Doc::~KWin4Doc()
0113 {
0114     qCDebug(KFOURINLINE_LOG) << "~KWin4Doc()";
0115     delete mHintProcess;
0116     delete mStatus;
0117     qCDebug(KFOURINLINE_LOG) << "~KWin4Doc() done";
0118 }
0119 
0120 // Player initialization
0121 void KWin4Doc::initPlayers()
0122 {
0123     // Create yellow
0124     KWin4Player *yellow = (KWin4Player *)createPlayer(1, mPlayedBy[Yellow], false);
0125     yellow->setUserId(Yellow);
0126     yellow->setName(Prefs::name1());
0127     addPlayer(yellow);
0128     setPlayedBy(Yellow, mPlayedBy[Yellow]);
0129 
0130     // Create Red
0131     KWin4Player *red = (KWin4Player *)createPlayer(1, mPlayedBy[Red], false);
0132     red->setUserId(Red);
0133     red->setName(Prefs::name1());
0134     addPlayer(red);
0135     setPlayedBy(Red, mPlayedBy[Red]);
0136 }
0137 
0138 // Set the view to the doc
0139 void KWin4Doc::setView(KWin4View *view)
0140 {
0141     pView = view;
0142     connect(pView, &KWin4View::signalMoveDone, this, &KWin4Doc::moveDone);
0143 }
0144 
0145 // Returns colour on the game board
0146 COLOUR KWin4Doc::getColour(int x, int y)
0147 {
0148     return (COLOUR)mField.at(x + y * FIELD_SIZE_X);
0149 }
0150 
0151 // Set the colour on the game board
0152 void KWin4Doc::setColour(int x, int y, COLOUR c)
0153 {
0154     if (x < 0 || x >= FIELD_SIZE_X || y < 0 || y >= FIELD_SIZE_Y) {
0155         qCCritical(KFOURINLINE_LOG) << "ERROR: setColour on wrong position" << x << " " << y;
0156         return;
0157     }
0158     mField.setAt(x + y * FIELD_SIZE_X, c);
0159 }
0160 
0161 // Reset the whole game (and the view)
0162 void KWin4Doc::resetGame(bool initview)
0163 {
0164     // Reset field
0165     for (int x = 0; x < FIELD_SIZE_X; ++x) {
0166         for (int y = FIELD_SIZE_Y - 1; y >= 0; --y) {
0167             setColour(x, y, Nobody);
0168         }
0169     }
0170     mFieldFilled.fill(0);
0171 
0172     // Reset game vars
0173     mHistoryCnt = 0;
0174     mCurrentMove = 0;
0175     mMaxMove = 0;
0176     mLastColumn = -1;
0177     mLastColour = Nobody;
0178     setScore(0);
0179     mLastHint = -1;
0180 
0181     // Reset the view
0182     if (initview) {
0183         pView->initGame(mStatus);
0184     }
0185 
0186     // Who starts this game
0187     setCurrentPlayer((COLOUR)mStartPlayer.value());
0188 }
0189 
0190 // Set current player to setTurn true
0191 void KWin4Doc::activateCurrentPlayer()
0192 {
0193     if (global_debug > 1)
0194         qCDebug(KFOURINLINE_LOG) << "Setting the current player to turn";
0195     getPlayer(getCurrentPlayer())->setTurn(true, true);
0196 }
0197 
0198 // End a game. Update statistic and forward end game to view.
0199 void KWin4Doc::endGame(TABLE mode)
0200 {
0201     setGameStatus(End);
0202     // TODO pView->clearError();
0203     pView->endGame();
0204 
0205     // Increase game statistics
0206     KWin4Player *yellow = getPlayer(Yellow);
0207     KWin4Player *red = getPlayer(Red);
0208     switch (mode) {
0209     case TWin:
0210         yellow->incWin();
0211         red->incLost();
0212         break;
0213     case TLost:
0214         yellow->incLost();
0215         red->incWin();
0216         break;
0217     case TRemis:
0218         yellow->incRemis();
0219         red->incRemis();
0220         break;
0221     default:
0222         // Only break if moves have been made
0223         if (mMaxMove > 0) {
0224             yellow->incBrk();
0225             red->incBrk();
0226         }
0227         break;
0228     }
0229 }
0230 
0231 // Indication that a move has been visually done
0232 void KWin4Doc::moveDone(int /*mode*/)
0233 {
0234     if (playerCount() > 1) {
0235         playerInputFinished(getPlayer(getCurrentPlayer()));
0236     }
0237 
0238     // TODO pView->clearError();
0239 }
0240 
0241 // Calculate the next players to turn. Here the players just swap.
0242 KPlayer *KWin4Doc::doNextPlayer(KPlayer *last, bool /*exclusive*/)
0243 {
0244     if (global_debug > 1)
0245         qCDebug(KFOURINLINE_LOG) << "doNextPlayer last=" << last->id() << "admin=" << isAdmin();
0246 
0247     // Should be enough if the admin sets the turn
0248     if (last->userId() == Yellow)
0249         setCurrentPlayer(Red);
0250     else
0251         setCurrentPlayer(Yellow);
0252     if (global_debug > 1)
0253         qCDebug(KFOURINLINE_LOG) << " Current set to " << getCurrentPlayer();
0254     if (isAdmin())
0255         getPlayer(getCurrentPlayer())->setTurn(true, true);
0256     Q_EMIT signalNextPlayer(int(getCurrentPlayer()));
0257     return getPlayer(getCurrentPlayer());
0258 }
0259 
0260 // Performs a game move on the given x position. Just calls makeMove()
0261 // and transforms the return value so that true indicates a valid move.
0262 bool KWin4Doc::doMove(int x, int id)
0263 {
0264     if (global_debug > 1)
0265         qCDebug(KFOURINLINE_LOG) << " KWin4Doc::Move pos=" << x << " id=" << id << " ";
0266 
0267     return (makeMove(x, 0) == GNormal);
0268 }
0269 
0270 // Make a game move on the given position. Display it in the view.
0271 // mode=0 normal move, =1: redo move
0272 MOVESTATUS KWin4Doc::makeMove(int x, int mode)
0273 {
0274     if (x < 0 || x >= FIELD_SIZE_X) {
0275         qCDebug(KFOURINLINE_LOG) << "ERROR: makeMove auf falsche Position" << x;
0276         return GNotAllowed;
0277     }
0278 
0279     int y = mFieldFilled.at(x);
0280 
0281     if (y >= FIELD_SIZE_Y) {
0282         return GIllMove; // no space left in column
0283     }
0284 
0285     if (mLastHint >= 0) {
0286         int hy;
0287         hy = mFieldFilled.at(mLastHint);
0288         setColour(mLastHint, hy, Nobody);
0289         mLastHint = -1;
0290     }
0291     if (mode == Tip) {
0292         mLastHint = x;
0293         setColour(x, y, Tip);
0294         return GTip; // no real move
0295     }
0296 
0297     mFieldFilled.setAt(x, mFieldFilled.at(x) + 1);
0298     setColour(x, y, getCurrentPlayer());
0299 
0300     mHistory.setAt(getHistoryCnt(), x);
0301     mHistoryCnt = mHistoryCnt.value() + 1;
0302 
0303     mLastColour = getCurrentPlayer();
0304     // if (getCurrentPlayer()==Yellow) setCurrentPlayer(Red);
0305     // else setCurrentPlayer(Yellow);
0306 
0307     mCurrentMove = mCurrentMove.value() + 1;
0308 
0309     // only if a real move isdone the maxmove is raised
0310     if (mode == 0)
0311         mMaxMove = mCurrentMove.value();
0312     mLastColumn = x;
0313 
0314     // Show graphics
0315     pView->displayMove(x, y, mLastColour, x, mLastColour, mCurrentMove - 1, mode == 1 ? false : true);
0316 
0317     return GNormal;
0318 }
0319 
0320 // Undo a move.
0321 bool KWin4Doc::undoMove()
0322 {
0323     if (getHistoryCnt() < 1)
0324         return false;
0325 
0326     if (mLastHint >= 0) {
0327         int hy;
0328         hy = mFieldFilled.at(mLastHint);
0329         setColour(mLastHint, hy, Nobody);
0330         mLastHint = -1;
0331     }
0332     // qCDebug(KFOURINLINE_LOG) << "Undo no="<<mHistoryCnt.value();
0333     mHistoryCnt = mHistoryCnt.value() - 1;
0334     int x = mHistory.at(getHistoryCnt());
0335     mFieldFilled.setAt(x, mFieldFilled.at(x) - 1);
0336     int y = mFieldFilled.at(x);
0337     // qCDebug(KFOURINLINE_LOG) << "Undo x="<<x << "y=" <<y;
0338     setColour(x, y, Nobody);
0339     // We have to remove the piece as well...
0340 
0341     mLastColour = getCurrentPlayer();
0342     if (getCurrentPlayer() == Yellow)
0343         setCurrentPlayer(Red);
0344     else
0345         setCurrentPlayer(Yellow);
0346     mCurrentMove = mCurrentMove.value() - 1;
0347 
0348     // Display move and arrow history
0349     if (getHistoryCnt() > 0) {
0350         pView->displayMove(x, y, Nobody, mHistory.at(getHistoryCnt() - 1), mLastColour.value(), mCurrentMove, false);
0351     } else {
0352         pView->displayMove(x, y, Nobody, -1, Nobody, mCurrentMove, false);
0353     }
0354 
0355     if (getHistoryCnt() > 0)
0356         mLastColumn = mHistory.at(getHistoryCnt() - 1);
0357     else
0358         mLastColumn = -1;
0359 
0360     setScore(0);
0361 
0362     return true;
0363 }
0364 
0365 // Redo a move
0366 bool KWin4Doc::redoMove()
0367 {
0368     if (getHistoryCnt() >= mMaxMove)
0369         return false;
0370 
0371     int x = mHistory.at(getHistoryCnt());
0372     // qCDebug(KFOURINLINE_LOG) << "Redo x=" << x;
0373     makeMove(x, 1);
0374     if (getCurrentPlayer() == Yellow)
0375         setCurrentPlayer(Red);
0376     else
0377         setCurrentPlayer(Yellow);
0378     setScore(0);
0379     return true;
0380 }
0381 
0382 // Set the name of the player of the given color
0383 void KWin4Doc::setName(COLOUR col, const QString &n)
0384 {
0385     getPlayer(col)->setName(n);
0386 }
0387 
0388 // Retrieve the name of the player of the given color
0389 QString KWin4Doc::getName(COLOUR col)
0390 {
0391     return getPlayer(col)->name();
0392 }
0393 
0394 // Returns the all time statistics for player of given color
0395 // The mode determines what statistics to access.
0396 int KWin4Doc::getStatistic(COLOUR col, TABLE mode)
0397 {
0398     KWin4Player *player = getPlayer(col);
0399     switch (mode) {
0400     case TWin:
0401         return player->win();
0402         break;
0403     case TRemis:
0404         return player->remis();
0405         break;
0406     case TLost:
0407         return player->lost();
0408         break;
0409     case TBrk:
0410         return player->brk();
0411         break;
0412     case TSum:
0413         return (player->win() + player->remis() + player->lost());
0414     default:
0415         break;
0416     }
0417     return 0;
0418 }
0419 
0420 // Retrieve the color of the i-th player. Player 0 is the start
0421 // player and player 1 the follow up player.
0422 COLOUR KWin4Doc::getPlayerColour(int player)
0423 {
0424     if (player == 0)
0425         return (COLOUR)mStartPlayer.value();
0426 
0427     if (mStartPlayer.value() == Yellow)
0428         return Red;
0429     else
0430         return Yellow;
0431 }
0432 
0433 // Check whether the current game has a game over situation
0434 // return -1: remis, 1:won, 0: continue
0435 int KWin4Doc::doCheckGameOver(KPlayer *p)
0436 {
0437     if (global_debug > 1)
0438         qCDebug(KFOURINLINE_LOG) << "KWin4Doc::doCheckGameOver::" << p->userId();
0439     return checkGameOver(mLastColumn, (COLOUR)(mLastColour.value()));
0440 }
0441 
0442 // Check whether the current game has a game over situation
0443 // return -1: remis, 1:won, 0: continue
0444 int KWin4Doc::checkGameOver(int x, COLOUR col)
0445 {
0446     int y, i;
0447     COLOUR c;
0448     int star = 1;
0449     COLOUR winc = Nobody;
0450 
0451     // Check vertical up
0452     int flag = 0;
0453     for (i = 0; i < 4; ++i) {
0454         y = mFieldFilled.at(x) - 1 - i;
0455         if (y >= 0) {
0456             c = getColour(x, y);
0457             if (c == col)
0458                 ++flag;
0459         }
0460     }
0461     if (flag >= 4) {
0462         // Store win fields
0463         for (i = 0; i < 4; ++i) {
0464             y = mFieldFilled.at(x) - 1 - i;
0465             pView->displayStar(x, y, star++);
0466             winc = getColour(x, y);
0467         }
0468         return 1;
0469     } else if (flag >= 4)
0470         return 1;
0471 
0472     int xx;
0473     // Check horizontal to the right
0474     y = mFieldFilled.at(x) - 1;
0475     flag = 0;
0476     for (i = -3; i <= 3 && flag < 4; ++i) {
0477         xx = x + i;
0478         if (xx >= 0 && xx < FIELD_SIZE_X) {
0479             c = getColour(xx, y);
0480             if (c == col)
0481                 ++flag;
0482             else
0483                 flag = 0;
0484         }
0485     }
0486     if (flag >= 4) {
0487         // Store win fields
0488         y = mFieldFilled.at(x) - 1;
0489         winc = getColour(x, y);
0490         int cnt = 0;
0491         for (i = 0; i < 4; ++i) {
0492             xx = x + i;
0493             if (xx >= 0 && xx < FIELD_SIZE_X) {
0494                 if (getColour(xx, y) != winc)
0495                     break;
0496                 pView->displayStar(xx, y, star++);
0497                 ++cnt;
0498             } else
0499                 break;
0500         }
0501         for (i = -1; i > -4 && cnt < 4; --i) {
0502             xx = x + i;
0503             if (xx >= 0 && xx < FIELD_SIZE_X) {
0504                 if (getColour(xx, y) != winc)
0505                     break;
0506                 pView->displayStar(xx, y, star++);
0507                 ++cnt;
0508             } else
0509                 break;
0510         }
0511         return 1;
0512     } else if (flag >= 4)
0513         return 1;
0514 
0515     // Check dy+
0516     flag = 0;
0517     for (i = -3; i <= 3 && flag < 4; ++i) {
0518         xx = x + i;
0519         if (xx >= 0 && xx < FIELD_SIZE_X) {
0520             y = mFieldFilled.at(x) - 1 - i;
0521             if (y >= 0 && y < FIELD_SIZE_Y) {
0522                 c = getColour(xx, y);
0523                 if (c == col)
0524                     ++flag;
0525                 else
0526                     flag = 0;
0527             }
0528         }
0529     }
0530     if (flag >= 4) {
0531         // Store win fields
0532         y = mFieldFilled.at(x) - 1;
0533         winc = getColour(x, y);
0534         int cnt = 0;
0535         for (i = 0; i < 4; ++i) {
0536             xx = x + i;
0537             if (xx >= 0 && xx < FIELD_SIZE_X) {
0538                 y = mFieldFilled.at(x) - 1 - i;
0539                 if (y < 0)
0540                     break;
0541                 if (getColour(xx, y) != winc)
0542                     break;
0543                 pView->displayStar(xx, y, star++);
0544                 ++cnt;
0545             } else
0546                 break;
0547         }
0548         for (i = -1; i > -4 && cnt < 4; --i) {
0549             xx = x + i;
0550             if (xx >= 0 && xx < FIELD_SIZE_X) {
0551                 y = mFieldFilled.at(x) - 1 - i;
0552                 if (y >= FIELD_SIZE_Y)
0553                     break;
0554                 if (getColour(xx, y) != winc)
0555                     break;
0556                 pView->displayStar(xx, y, star++);
0557                 ++cnt;
0558             } else
0559                 break;
0560         }
0561         return 1;
0562     } else if (flag >= 4)
0563         return 1;
0564 
0565     // Check dy-
0566     flag = 0;
0567     for (i = -3; i <= 3 && flag < 4; ++i) {
0568         xx = x + i;
0569         if (xx >= 0 && xx < FIELD_SIZE_X) {
0570             y = mFieldFilled.at(x) - 1 + i;
0571             if (y >= 0 && y < FIELD_SIZE_Y) {
0572                 c = getColour(xx, y);
0573                 if (c == col)
0574                     ++flag;
0575                 else
0576                     flag = 0;
0577             }
0578         }
0579     }
0580     if (flag >= 4) {
0581         // Store win fields
0582         y = mFieldFilled.at(x) - 1;
0583         winc = getColour(x, y);
0584         int cnt = 0;
0585         for (i = 0; i < 4; ++i) {
0586             xx = x + i;
0587             if (xx >= 0 && xx < FIELD_SIZE_X) {
0588                 y = mFieldFilled.at(x) - 1 + i;
0589                 if (y >= FIELD_SIZE_Y)
0590                     break;
0591                 if (getColour(xx, y) != winc)
0592                     break;
0593                 pView->displayStar(xx, y, star++);
0594                 ++cnt;
0595             } else
0596                 break;
0597         }
0598         for (i = -1; i > -4 && cnt < 4; --i) {
0599             xx = x + i;
0600             if (xx >= 0 && xx < FIELD_SIZE_X) {
0601                 y = mFieldFilled.at(x) - 1 + i;
0602                 if (y < 0)
0603                     break;
0604                 if (getColour(xx, y) != winc)
0605                     break;
0606                 pView->displayStar(xx, y, star++);
0607                 ++cnt;
0608             } else
0609                 break;
0610         }
0611         return 1;
0612     } else if (flag >= 4)
0613         return 1;
0614 
0615     if (mCurrentMove >= 42)
0616         return -1;
0617 
0618     return 0;
0619 }
0620 
0621 // Reset all the player stats
0622 void KWin4Doc::resetStatistic()
0623 {
0624     getPlayer(Yellow)->resetStats();
0625     getPlayer(Red)->resetStats();
0626 }
0627 
0628 // Set computer AI score value
0629 void KWin4Doc::setScore(long value)
0630 {
0631     mScore.setValue(value);
0632 }
0633 
0634 // Load settings from Prefs
0635 void KWin4Doc::loadSettings()
0636 {
0637     qCDebug(KFOURINLINE_LOG) << "++++ KWin4Doc::loadSettings() ";
0638     qCDebug(KFOURINLINE_LOG) << "Level:" << Prefs::level();
0639     qCDebug(KFOURINLINE_LOG) << "Name:" << Prefs::name1();
0640     qCDebug(KFOURINLINE_LOG) << "Name2:" << Prefs::name2();
0641     qCDebug(KFOURINLINE_LOG) << "input0mouse:" << Prefs::input0mouse();
0642     qCDebug(KFOURINLINE_LOG) << "input0key:" << Prefs::input0key();
0643     qCDebug(KFOURINLINE_LOG) << "input0ai:" << Prefs::input0ai();
0644     qCDebug(KFOURINLINE_LOG) << "input1mouse:" << Prefs::input1mouse();
0645     qCDebug(KFOURINLINE_LOG) << "input1key:" << Prefs::input1key();
0646     qCDebug(KFOURINLINE_LOG) << "input1ai:" << Prefs::input1ai();
0647     qCDebug(KFOURINLINE_LOG) << "start red:" << Prefs::startcolourred();
0648     qCDebug(KFOURINLINE_LOG) << "start yellow" << Prefs::startcolouryellow();
0649     qCDebug(KFOURINLINE_LOG) << "Learning     " << Prefs::learning();
0650     qCDebug(KFOURINLINE_LOG) << "Lock         " << Prefs::ailock();
0651 
0652     // Store level for score sprite display
0653     mStatus->setLevel(Prefs::level(), 0);
0654     mStatus->setLevel(Prefs::level(), 1);
0655 
0656     setName(Yellow, Prefs::name1());
0657     setName(Red, Prefs::name2());
0658 
0659     KGameIO::IOMode mode = KGameIO::MouseIO;
0660 
0661     if (Prefs::input0mouse())
0662         mode = KGameIO::MouseIO;
0663     else if (Prefs::input0key())
0664         mode = KGameIO::KeyIO;
0665     else if (Prefs::input0ai())
0666         mode = KGameIO::ProcessIO;
0667     else
0668         qCCritical(KFOURINLINE_LOG) << "Unknown input device for player 0";
0669     if (global_demo_mode)
0670         mode = KGameIO::ProcessIO;
0671     setPlayedBy(Yellow, mode);
0672     qCDebug(KFOURINLINE_LOG) << "Played by Yellow=" << mode;
0673 
0674     if (Prefs::input1mouse())
0675         mode = KGameIO::MouseIO;
0676     else if (Prefs::input1key())
0677         mode = KGameIO::KeyIO;
0678     else if (Prefs::input1ai())
0679         mode = KGameIO::ProcessIO;
0680     else
0681         qCCritical(KFOURINLINE_LOG) << "Unknown input device for player 1";
0682     if (global_demo_mode)
0683         mode = KGameIO::ProcessIO;
0684     setPlayedBy(Red, mode);
0685     qCDebug(KFOURINLINE_LOG) << "Played by Red=" << mode;
0686 
0687     if (Prefs::startcolourred())
0688         mStartPlayer.setValue(Red);
0689     else if (Prefs::startcolouryellow())
0690         mStartPlayer.setValue(Yellow);
0691     else
0692         qCCritical(KFOURINLINE_LOG) << "Unknown start color";
0693     qCDebug(KFOURINLINE_LOG) << "Setting start player to" << mStartPlayer;
0694 }
0695 
0696 // Read config file
0697 void KWin4Doc::readConfig(KConfig *config)
0698 {
0699     qCDebug(KFOURINLINE_LOG) << "++++++++++++++++++++++++++++++++++++ KWin4Doc::ReadConfig";
0700     loadSettings();
0701 
0702     KConfigGroup ygrp = config->group(QStringLiteral("YellowPlayer"));
0703     getPlayer(Yellow)->readConfig(ygrp);
0704 
0705     KConfigGroup rgrp = config->group(QStringLiteral("RedPlayer"));
0706     getPlayer(Red)->readConfig(rgrp);
0707 }
0708 
0709 // Write config file
0710 void KWin4Doc::writeConfig(KConfig *config)
0711 {
0712     KConfigGroup ygrp = config->group(QStringLiteral("YellowPlayer"));
0713     getPlayer(Yellow)->writeConfig(ygrp);
0714 
0715     KConfigGroup rgrp = config->group(QStringLiteral("RedPlayer"));
0716     getPlayer(Red)->writeConfig(rgrp);
0717 
0718     config->sync();
0719 }
0720 
0721 // Returns the current player, resp amzug.
0722 COLOUR KWin4Doc::getCurrentPlayer()
0723 {
0724     return (COLOUR)mAmzug.value();
0725 }
0726 
0727 // Set the current player
0728 void KWin4Doc::setCurrentPlayer(COLOUR no)
0729 {
0730     mAmzug.setValue(no);
0731 }
0732 
0733 // Switch the starting player and return the new started
0734 COLOUR KWin4Doc::switchStartPlayer()
0735 {
0736     if (mStartPlayer.value() == Yellow) {
0737         mStartPlayer.setValue(Red);
0738         Prefs::setStartcolouryellow(false);
0739         Prefs::setStartcolourred(true);
0740         qCDebug(KFOURINLINE_LOG) << "Setting startplayer to RED";
0741     } else {
0742         mStartPlayer.setValue(Yellow);
0743         Prefs::setStartcolouryellow(true);
0744         Prefs::setStartcolourred(false);
0745         qCDebug(KFOURINLINE_LOG) << "Setting startplayer to YELLOW";
0746     }
0747     Prefs::self()->save();
0748 
0749     return (COLOUR)mStartPlayer.value();
0750 }
0751 
0752 // Retrieve the current move number.
0753 int KWin4Doc::getCurrentMove()
0754 {
0755     return mCurrentMove;
0756 }
0757 
0758 // Retrieve the maximum move number before undo
0759 int KWin4Doc::getMaxMove()
0760 {
0761     return mMaxMove;
0762 }
0763 
0764 // Retrieve the amount of history moves stored
0765 int KWin4Doc::getHistoryCnt()
0766 {
0767     return mHistoryCnt;
0768 }
0769 
0770 // Return the filename of the computer player AI process.
0771 QString KWin4Doc::findProcessName()
0772 {
0773 // Try whether we run from a development source dir
0774 #ifndef NDEBUG
0775 #ifdef SRC_DIR
0776     QString srcname = QStringLiteral(SRC_DIR) + QStringLiteral("/src/kfourinlineproc");
0777     QFile fsrc(srcname);
0778     if (fsrc.exists()) {
0779         if (global_debug > 1)
0780             qCDebug(KFOURINLINE_LOG) << "Found SRC_DIR process" << srcname;
0781         return srcname;
0782     }
0783 #endif
0784 #endif
0785 
0786     // First try a local dir override
0787     QDir dir;
0788     // TODO: This local filename is not found!!
0789     QString filename = dir.path() + QStringLiteral("/kwin4/kfourinlineproc");
0790     qCDebug(KFOURINLINE_LOG) << "PROC FILENAME=" << filename;
0791     QFile flocal(filename);
0792     if (flocal.exists()) {
0793         if (global_debug > 1)
0794             qCDebug(KFOURINLINE_LOG) << "Found local process" << filename;
0795         return filename;
0796     }
0797     QString path = QStandardPaths::findExecutable(QStringLiteral("kfourinlineproc"));
0798     if (!path.isNull()) {
0799         if (global_debug > 1)
0800             qCDebug(KFOURINLINE_LOG) << "Found system process" << path;
0801         return path;
0802     }
0803     QString empty;
0804     qCCritical(KFOURINLINE_LOG) << "Could not locate the computer player";
0805     return empty;
0806 }
0807 
0808 // Debug: Listen to messages
0809 void KWin4Doc::networkMessageUpdate(int /*id*/, quint32 /*sender*/, quint32 /*recv*/)
0810 {
0811     //  qCDebug(KFOURINLINE_LOG) << "MSG: id=" << id << "sender=" << sender << "receiver="<<recv;
0812 }
0813 
0814 // Create a KPlayer
0815 KPlayer *KWin4Doc::createPlayer(int /*rtti*/, int io, bool isvirtual)
0816 {
0817     KWin4Player *player = new KWin4Player;
0818     if (!isvirtual)
0819         createIO(player, (KGameIO::IOMode)io);
0820 
0821     connect(player, &KWin4Player::signalPropertyChanged, this, &KWin4Doc::playerPropertyChanged);
0822     player->setStatus(mStatus);
0823     return player;
0824 }
0825 
0826 // Called when a player input is received from the KGame object
0827 // this is e.g. a mouse event, the AI or the network
0828 bool KWin4Doc::playerInput(QDataStream &msg, KPlayer * /*player*/)
0829 {
0830     qint32 move, pl;
0831     msg >> pl >> move;
0832     qCDebug(KFOURINLINE_LOG) << "KWin4Doc::playerInput: ================ pl=" << pl << " and move=" << move << "====================";
0833 
0834     // Perform move and check for success
0835     if (!doMove(move, pl)) {
0836         // Repeat the same input
0837         QTimer::singleShot(0, this, &KWin4Doc::repeatMove);
0838     }
0839 
0840     return false;
0841 }
0842 
0843 // Reactivate player in case of a move which could not pe performed.
0844 void KWin4Doc::repeatMove()
0845 {
0846     getPlayer(getCurrentPlayer())->setTurn(true);
0847 }
0848 
0849 // Query the IO mode of player og the given color.
0850 KGameIO::IOMode KWin4Doc::playedBy(int col)
0851 {
0852     return mPlayedBy[col];
0853 }
0854 
0855 // Sets the input device mode for the given player color.
0856 void KWin4Doc::setPlayedBy(int col, KGameIO::IOMode io)
0857 {
0858     if (global_debug > 1)
0859         qCDebug(KFOURINLINE_LOG) << "  KWin4Doc::setPlayedBy(int " << col << ",KGameIO::IOMode " << io << ")";
0860 
0861     KWin4Player *player = getPlayer((COLOUR)col);
0862 
0863     // Modes for the score sprite
0864     player->status()->setPlayedBy((int)io, player->userId());
0865 
0866     if (mPlayedBy[col] != io && !player->isVirtual()) {
0867         bool myTurn = player->myTurn();
0868         player->setTurn(false); // turn of move
0869         mPlayedBy[col] = io;
0870         player->removeGameIO(); // remove all IO's
0871         createIO(player, io);
0872         player->setTurn(myTurn); // turn on move
0873     }
0874 }
0875 
0876 // Get the io values right after a load game as the io the playedby
0877 // is not set there.
0878 void KWin4Doc::recalcIO()
0879 {
0880     mPlayedBy[Yellow] = (KGameIO::IOMode)getPlayer(Yellow)->calcIOValue();
0881     mPlayedBy[Red] = (KGameIO::IOMode)getPlayer(Red)->calcIOValue();
0882 }
0883 
0884 // Create player input devicea (KGame)
0885 void KWin4Doc::createIO(KPlayer *player, KGameIO::IOMode io)
0886 {
0887     if (!player)
0888         return;
0889 
0890     if (global_debug > 1)
0891         qCDebug(KFOURINLINE_LOG) << "KWin4Doc::createIO(KPlayer *player(" << player->userId() << "),KGameIO::IOMode " << io << ") ";
0892 
0893     if (io & KGameIO::MouseIO) {
0894         KGameMouseIO *input;
0895         if (global_debug > 1)
0896             qCDebug(KFOURINLINE_LOG) << "Creating MOUSE IO to " << pView;
0897         // We want the player to work over mouse. So please leave the "true" for mouse
0898         // tracking on !!!
0899         input = new KGameMouseIO(pView->viewport(), true);
0900         if (global_debug > 1)
0901             qCDebug(KFOURINLINE_LOG) << "MOUSE IO added";
0902         // Connect mouse input to a function to process the actual input
0903         connect(input, &KGameMouseIO::signalMouseEvent, pView, &KWin4View::mouseInput);
0904         player->addGameIO(input);
0905     } else if (io & KGameIO::ProcessIO) {
0906         QString file = findProcessName();
0907         if (global_debug > 1)
0908             qCDebug(KFOURINLINE_LOG) << "Creating PROCESS IO" << file;
0909 
0910         KGameProcessIO *input;
0911         // We want a computer player
0912         input = new KGameProcessIO(file);
0913         // Connect computer player to the setTurn
0914         connect(input, &KGameProcessIO::signalPrepareTurn, this, &KWin4Doc::prepareAITurn);
0915 
0916         connect(input, &KGameProcessIO::signalProcessQuery, this, &KWin4Doc::processAICommand);
0917 
0918         connect(input, &KGameProcessIO::signalReceivedStderr, this, &KWin4Doc::receivedStderr);
0919         player->addGameIO(input);
0920     } else if (io & KGameIO::KeyIO) {
0921         if (global_debug > 1)
0922             qCDebug(KFOURINLINE_LOG) << "Creating KEYBOARD IO";
0923         // We want the player to work over keyboard
0924         KGameKeyIO *input;
0925         input = new KGameKeyIO(pView->parentWidget());
0926         // Connect keys input to a function to process the actual input
0927         connect((KGameKeyIO *)input, &KGameKeyIO::signalKeyEvent, pView, &KWin4View::keyInput);
0928         player->addGameIO(input);
0929     }
0930 }
0931 
0932 void KWin4Doc::receivedStderr(const QString &s)
0933 {
0934     if (global_debug > 0)
0935         qCDebug(KFOURINLINE_LOG) << "##### AI:" << s;
0936 }
0937 
0938 // This slot is called when a computer move should be generated
0939 void KWin4Doc::prepareAITurn(QDataStream &stream, bool b, KGameIO *input, bool *sendit)
0940 {
0941     if (global_debug > 1)
0942         qCDebug(KFOURINLINE_LOG) << "KWin4Doc::prepareAITurn b=" << b;
0943 
0944     // Set defaults
0945     *sendit = false;
0946 
0947     // Our player
0948     KPlayer *player = input->player();
0949     if (!player->myTurn())
0950         return;
0951     if (!b)
0952         return; // only create move on setTurn(true)
0953 
0954     qint32 pl;
0955     if (global_debug > 1)
0956         qCDebug(KFOURINLINE_LOG) << "slotPrepareComputerTurn for player id=" << player->id();
0957     pl = player->userId();
0958 
0959     // Pack the game into the message
0960     prepareGameMessage(stream, pl);
0961 
0962     // Do send
0963     *sendit = true;
0964 }
0965 
0966 // Sends the current game status to the computer player
0967 // Careful: The data needs to be exactly the same as the computer
0968 // player reading on the other side
0969 void KWin4Doc::prepareGameMessage(QDataStream &stream, qint32 pl)
0970 {
0971     if (global_debug > 1)
0972         qCDebug(KFOURINLINE_LOG) << "          sending col=" << pl;
0973     stream << pl;
0974     // This needs to be the same than the computer player reads!
0975     stream << (qint32)getCurrentMove();
0976     stream << (qint32)getCurrentPlayer();
0977     stream << (qint32)getPlayerColour(0);
0978     stream << (qint32)getPlayerColour(1);
0979     stream << (qint32)Prefs::level();
0980 
0981     bool learning = Prefs::learning();
0982     // Allow learning only for one AI
0983     if (mPlayedBy[Yellow] == KGameIO::ProcessIO && mPlayedBy[Red] == KGameIO::ProcessIO && pl == Yellow)
0984         learning = false;
0985     stream << (qint32)learning;
0986 
0987     // Where to save the learn cache
0988     QString learnPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + QStringLiteral("kwin4");
0989 
0990     stream << learnPath;
0991 
0992     int i, j;
0993     for (i = 0; i < FIELD_SIZE_Y; ++i) {
0994         for (j = 0; j < FIELD_SIZE_X; ++j) {
0995             qint8 col;
0996             col = getColour(j, i);
0997             stream << col;
0998         }
0999         if (global_debug > 1)
1000             qCDebug(KFOURINLINE_LOG) << getColour(0, i) << " " << getColour(1, i) << " " << getColour(2, i) << " " << getColour(3, i) << " " << getColour(4, i)
1001                                      << " " << getColour(5, i) << " " << getColour(6, i);
1002     }
1003     stream << (qint32)421256;
1004 }
1005 
1006 // The AI send a command, e.g. the game value to us
1007 void KWin4Doc::processAICommand(QDataStream &in, KGameProcessIO *io)
1008 {
1009     qint8 cid;
1010 
1011     // Receive command
1012     in >> cid;
1013     switch (cid) {
1014     case 1: // game value
1015     {
1016         AIBoard aiBoard;
1017         qint32 value, moveNo, level;
1018         in >> value >> moveNo >> level >> aiBoard;
1019         if (global_debug > 1)
1020             qCDebug(KFOURINLINE_LOG) << "#### Computer thinks move" << moveNo << "value is" << value;
1021         // Store AI data
1022         mAIValues[moveNo] = value;
1023         setScore(value);
1024 
1025         // Check AI mistakes
1026         if (moveNo >= 2) {
1027             long delta = mAIValues[moveNo] - mAIValues[moveNo - 2];
1028 
1029             // Send game to process
1030             QByteArray buffer;
1031             QDataStream outstream(&buffer, QIODevice::WriteOnly);
1032             // Send last board to learn with current value
1033             outstream << aiBoard << value << (qint32)delta << level;
1034             io->sendMessage(outstream, 3, 0, gameId());
1035         }
1036     } break;
1037     default:
1038         qCCritical(KFOURINLINE_LOG) << "KWin4Doc::processAICommand: Unknown id" << cid;
1039         break;
1040     }
1041 }
1042 
1043 // This slot is called by the signal of KGame to indicated
1044 // that the network connection is done and a new client is
1045 // connected
1046 // cid is the id of the client connected. if this is equal
1047 // gameId() WE are the client
1048 void KWin4Doc::clientConnected(quint32 cid, KGame * /* me */)
1049 {
1050     if (global_debug > 1)
1051         qCDebug(KFOURINLINE_LOG) << "void KWin4Doc::clientConnected id=" << cid << "we=" << gameId() << "we admin=" << isAdmin() << "master)" << isMaster();
1052 
1053     if (playerList()->count() != 2) {
1054         qCCritical(KFOURINLINE_LOG) << "SERIOUS ERROR: We do not have two players...Trying to disconnect!";
1055         disconnect();
1056         return;
1057     }
1058 
1059     // Get the two players - more are not possible
1060     KWin4Player *p1 = (KWin4Player *)playerList()->at(0);
1061     KWin4Player *p2 = (KWin4Player *)playerList()->at(1);
1062     if (!p1->isVirtual()) {
1063         Q_EMIT signalChatChanged(p1);
1064         if (global_debug > 1)
1065             qCDebug(KFOURINLINE_LOG) << "CHAT to player 0";
1066     } else {
1067         Q_EMIT signalChatChanged(p2);
1068         if (global_debug > 1)
1069             qCDebug(KFOURINLINE_LOG) << "CHAT to player 1";
1070     }
1071 
1072     // Now check whose turn it is. The Admin will rule this
1073     if (isAdmin()) {
1074         if (global_debug > 1)
1075             qCDebug(KFOURINLINE_LOG) << "WE are ADMIN == COOL ! ";
1076         // p1 is local
1077         if (!p1->isVirtual()) {
1078             if (global_debug > 1)
1079                 qCDebug(KFOURINLINE_LOG) << "p1 id=" << p1->userId() << "is local turn=" << p1->myTurn();
1080             // Exclusive setting of the turn
1081             p1->setTurn(p1->myTurn(), true);
1082             p2->setTurn(!p1->myTurn(), true);
1083         } else if (!p2->isVirtual()) {
1084             if (global_debug > 1)
1085                 qCDebug(KFOURINLINE_LOG) << "p2 id=" << p2->userId() << "is local turn=" << p2->myTurn();
1086             // Exclusive setting of the turn
1087             p2->setTurn(p2->myTurn(), true);
1088             p1->setTurn(!p2->myTurn(), true);
1089         }
1090     }
1091 }
1092 
1093 // Get the KPlayer from the color by searching all players
1094 // users id's
1095 KWin4Player *KWin4Doc::getPlayer(COLOUR col)
1096 {
1097     for (KGamePlayerList::const_iterator it = playerList()->constBegin(); it != playerList()->constEnd(); ++it) {
1098         if ((*it)->userId() == col)
1099             return (KWin4Player *)(*it);
1100     }
1101     qCCritical(KFOURINLINE_LOG) << "SERIOUS ERROR: Cannot find player with colour" << col << ".  CRASH imminent";
1102     return nullptr;
1103 }
1104 
1105 // We create a process which calculates a computer move which is shown as hint to the player.
1106 void KWin4Doc::calculateHint()
1107 {
1108     // We allocate the hint process only if it is needed
1109     if (!mHintProcess) {
1110         QString file = findProcessName();
1111         if (global_debug > 1)
1112             qCDebug(KFOURINLINE_LOG) << "Creating HINT PROCESS";
1113 
1114         // We want a computer player
1115         mHintProcess = new KGameProcessIO(file);
1116 
1117         connect(mHintProcess, &KGameProcessIO::signalProcessQuery, this, &KWin4Doc::processAIHintCommand);
1118     }
1119 
1120     // Send game to process
1121     qint32 pl;
1122     QByteArray buffer;
1123     QDataStream stream(&buffer, QIODevice::WriteOnly);
1124     pl = getCurrentPlayer();
1125     prepareGameMessage(stream, pl);
1126     mHintProcess->sendMessage(stream, 2, 0, gameId());
1127 }
1128 
1129 // The compute process sent a hint which we show in the game board.
1130 void KWin4Doc::processAIHintCommand(QDataStream &in, KGameProcessIO * /*io*/)
1131 {
1132     qint8 cid;
1133     // Read command
1134     in >> cid;
1135     switch (cid) {
1136     case 2: // Hint
1137     {
1138         qint32 pl;
1139         qint32 move;
1140         qint32 value;
1141         // Read parameters of command
1142         in >> pl >> move >> value;
1143         if (global_debug > 1)
1144             qCDebug(KFOURINLINE_LOG) << "#### Computer thinks pl=" << pl << "move =" << move;
1145         if (global_debug > 1)
1146             qCDebug(KFOURINLINE_LOG) << "#### Computer thinks hint is" << move << "and value is" << value;
1147 
1148         // Display hint
1149         int x = move;
1150         int y = mFieldFilled.at(x);
1151         pView->displayHint(x, y);
1152     } break;
1153     default:
1154         qCCritical(KFOURINLINE_LOG) << "KWin4Doc::processAIHintCommand: Unknown id" << cid;
1155         break;
1156     }
1157 }
1158 
1159 // Called when a player property has changed. We check whether the name
1160 // changed and then update the score widget
1161 // We should maybe do this for the other properties too to update
1162 // the status widget...I am not sure here...we'll see
1163 void KWin4Doc::playerPropertyChanged(KGamePropertyBase *prop, KPlayer *player)
1164 {
1165     if (!pView)
1166         return;
1167 
1168     // Check for name changes
1169     if (prop->id() == KGamePropertyBase::IdName) {
1170         if (global_debug > 1)
1171             qCDebug(KFOURINLINE_LOG) << "Player name id=" << player->userId() << "changed to" << player->name();
1172         mStatus->setPlayerName(player->name(), player->userId());
1173     }
1174 }
1175 
1176 // Called by KGame when a game property has changed.
1177 void KWin4Doc::gamePropertyChanged(KGamePropertyBase *prop, KGame * /* me */)
1178 {
1179     if (!pView)
1180         return;
1181 
1182     // Move number
1183     if (prop->id() == mCurrentMove.id()) {
1184         // TODO pView->scoreWidget()->setMove(mCurrentMove);
1185     }
1186 
1187     // Computer AI value
1188     else if (prop->id() == mScore.id()) {
1189         int sc = mScore / 10000;
1190         if (sc == 0 && mScore.value() > 0)
1191             sc = 1;
1192         else if (sc == 0 && mScore.value() < 0)
1193             sc = -1;
1194         // TODO pView->scoreWidget()->setChance(sc);
1195     }
1196 
1197     // Whose turn is it
1198     else if (prop->id() == mAmzug.id()) {
1199         if (global_debug > 1)
1200             qCDebug(KFOURINLINE_LOG) << "Amzug changed to" << mAmzug.value();
1201         mStatus->setTurn(mAmzug);
1202     }
1203 
1204     // The game status
1205     else if (prop->id() == KGamePropertyBase::IdGameStatus) {
1206         if (gameStatus() == Abort) {
1207             if (global_debug > 1)
1208                 qCDebug(KFOURINLINE_LOG) << "PropertyChanged::status signal game abort +++";
1209             Q_EMIT signalGameOver(2, getPlayer(getCurrentPlayer()), this); // 2 indicates Abort
1210         } else if (gameStatus() == Run) {
1211             if (global_debug > 1)
1212                 qCDebug(KFOURINLINE_LOG) << "PropertyChanged::status signal game run +++";
1213             if (playerList()->count() == 2) {
1214                 activateCurrentPlayer(); // Set the current player to play
1215                 Q_EMIT signalGameRun();
1216             }
1217             if (global_debug > 1)
1218                 qCDebug(KFOURINLINE_LOG) << "PropertyChanged::status signal game run done +++";
1219         } else if (gameStatus() == Init) {
1220             if (global_debug > 1)
1221                 qCDebug(KFOURINLINE_LOG) << "PropertyChanged::status signal game INIT +++";
1222             resetGame(true);
1223         } else if (gameStatus() == End) {
1224             if (global_debug > 1)
1225                 qCDebug(KFOURINLINE_LOG) << "PropertyChanged::status signal game END +++";
1226         } else {
1227             if (global_debug > 1)
1228                 qCDebug(KFOURINLINE_LOG) << "PropertyChanged::other status signal +++";
1229         }
1230     }
1231 }
1232 
1233 // This is an overwritten function of KGame which is called
1234 // when a game is loaded. This can either be via a network
1235 // connect or via a real load from file
1236 bool KWin4Doc::loadgame(QDataStream &stream, bool network, bool reset)
1237 {
1238     if (global_debug > 1)
1239         qCDebug(KFOURINLINE_LOG) << "loadgame() network=" << network << "reset=" << reset;
1240     if (!network)
1241         setGameStatus(End);
1242 
1243     // Clear out the old game
1244     if (global_debug > 1)
1245         qCDebug(KFOURINLINE_LOG) << "loadgame wants to reset the game";
1246     resetGame(true);
1247 
1248     // load the new game
1249     bool res = KGame::loadgame(stream, network, reset);
1250     if (global_debug > 1)
1251         qCDebug(KFOURINLINE_LOG) << "amzug loaded to =" << mAmzug.value();
1252 
1253     // Replay the game be undoing and redoing
1254     if (global_debug > 1)
1255         qCDebug(KFOURINLINE_LOG) << "REDRAW GAME using undo/redo";
1256     if (global_debug > 1)
1257         qCDebug(KFOURINLINE_LOG) << "history cnt=" << mHistoryCnt.value();
1258     if (global_debug > 1)
1259         qCDebug(KFOURINLINE_LOG) << "amzug =" << mAmzug.value();
1260     int cnt = 0;
1261     while (undoMove()) {
1262         ++cnt;
1263         if (global_debug > 1)
1264             qCDebug(KFOURINLINE_LOG) << "Undoing move " << cnt;
1265     }
1266     if (global_debug > 1)
1267         qCDebug(KFOURINLINE_LOG) << "amzug =" << mAmzug.value();
1268     while (cnt > 0) {
1269         redoMove();
1270         --cnt;
1271         if (global_debug > 1)
1272             qCDebug(KFOURINLINE_LOG) << "Redoing move " << cnt;
1273     }
1274     if (global_debug > 1)
1275         qCDebug(KFOURINLINE_LOG) << "amzug =" << mAmzug.value();
1276 
1277     // Set the input devices
1278     recalcIO();
1279     // And set the right player to turn
1280     activateCurrentPlayer();
1281 
1282     if (global_debug > 1)
1283         qCDebug(KFOURINLINE_LOG) << "loadgame done +++";
1284     return res;
1285 }
1286 
1287 // This is also an overwritten function of KGame. It is
1288 // Called in the game negotiation upon connect. Here
1289 // the games have to determine what player is remote and
1290 // what is local
1291 // This function is only called in the Admin.
1292 void KWin4Doc::newPlayersJoin(KGamePlayerList * /*oldList*/, KGamePlayerList *newList, QList<int> &inactivate)
1293 {
1294     if (global_debug > 1)
1295         qCDebug(KFOURINLINE_LOG) << "newPlayersJoin: START";
1296 
1297     KWin4Player *yellow = getPlayer(Yellow);
1298     KWin4Player *red = getPlayer(Red);
1299     // Take the master player with the higher priority. Priority is set
1300     // by the network dialog
1301     if (yellow->networkPriority() > red->networkPriority()) {
1302         // Deactivate the lower one
1303         inactivate.append(red->id());
1304         if (global_debug > 1)
1305             qCDebug(KFOURINLINE_LOG) << "ADMIN keeps yellow and kicks red=" << red->id() << " userId/col=" << red->userId();
1306         // loop all client players and deactivate the one which have the color
1307         // yellow
1308         for (KGamePlayerList::const_iterator it = newList->constBegin(); it != newList->constEnd(); ++it) {
1309             KPlayer *player = *it;
1310             if (player->userId() == yellow->userId()) {
1311                 inactivate.append(player->id());
1312                 if (global_debug > 1)
1313                     qCDebug(KFOURINLINE_LOG) << "Deactivate C1" << player->id() << " col=" << player->userId();
1314             }
1315         }
1316     } else {
1317         // Deactivate the lower one
1318         inactivate.append(yellow->id());
1319         if (global_debug > 1)
1320             qCDebug(KFOURINLINE_LOG) << "ADMIN keeps red and kicks yellow=" << yellow->id() << " userId/col=" << yellow->userId();
1321         // loop all client players and deactivate the one which have the color
1322         // red
1323         for (KGamePlayerList::const_iterator it = newList->constBegin(); it != newList->constEnd(); ++it) {
1324             KPlayer *player = *it;
1325             if (player->userId() == red->userId()) {
1326                 inactivate.append(player->id());
1327                 if (global_debug > 1)
1328                     qCDebug(KFOURINLINE_LOG) << "Deactivate C2" << player->id() << " col=" << player->userId();
1329             }
1330         }
1331     }
1332     if (global_debug > 1)
1333         qCDebug(KFOURINLINE_LOG) << "newPlayersJoin: DONE";
1334 }
1335 
1336 #include "moc_kwin4doc.cpp"