File indexing completed on 2024-04-14 03:59:23

0001 /******************************************************************************
0002 *   KBlocks, a falling blocks game by KDE                                     *
0003 *   SPDX-FileCopyrightText: 2010-2021 Zhongjie Cai <squall.leonhart.cai@gmail.com>      *
0004 *                           Julian Helfferich <julian.helfferich@mailbox.org> *
0005 *                                                                             *
0006 *   SPDX-License-Identifier: GPL-2.0-or-later
0007 ******************************************************************************/
0008 #include "KBlocksGameLogic.h"
0009 #include <QRandomGenerator>
0010 
0011 
0012 KBlocksGameLogic::KBlocksGameLogic(int capacity, bool record)
0013 {
0014     mGameCount = 0;
0015     mGameMax = capacity;
0016 
0017     mGameSeed = 0;
0018     mPunishFlag = true;
0019 
0020     mStandbyMode = false;
0021     mGameInterval = 0;
0022 
0023     mInitialInterval = 0;
0024     mLevelUpInterval = 0;
0025 
0026     maGameList = new KBlocksSingleGame*[capacity];
0027 
0028     if (record) {
0029         mpGameRecorder = new KBlocksGameRecorder();
0030     } else {
0031         mpGameRecorder = nullptr;
0032     }
0033     mpGameReplayer = nullptr;
0034 }
0035 
0036 KBlocksGameLogic::KBlocksGameLogic(KBlocksGameReplayer *p)
0037 {
0038     mGameCount = 0;
0039     mGameMax = p->getGameCount();
0040 
0041     mGameSeed = 0;
0042     mPunishFlag = true;
0043 
0044     mStandbyMode = false;
0045     mGameInterval = 0;
0046 
0047     mInitialInterval = 0;
0048     mLevelUpInterval = 0;
0049 
0050     maGameList = new KBlocksSingleGame*[mGameMax];
0051 
0052     mpGameRecorder = nullptr;
0053     mpGameReplayer = p;
0054 }
0055 
0056 KBlocksGameLogic::~KBlocksGameLogic()
0057 {
0058     if (mpGameRecorder) {
0059         delete mpGameRecorder;
0060     }
0061     delete [] maGameList;
0062 }
0063 
0064 int KBlocksGameLogic::getActiveGameCount()
0065 {
0066     int result = 0;
0067     for (int i = 0; i < mGameCount; i++) {
0068         if (maGameList[i]->isGameRunning()) {
0069             result++;
0070         }
0071     }
0072     return result;
0073 }
0074 
0075 KBlocksSingleGame *KBlocksGameLogic::getSingleGame(int index)
0076 {
0077     if ((index < 0) || (index >= mGameCount)) {
0078         return nullptr;
0079     }
0080     return maGameList[index];
0081 }
0082 
0083 bool KBlocksGameLogic::playRecordOneStep(int *changedPiece)
0084 {
0085     int tmpCount;
0086     vector<KBlocksReplayData> tmpData;
0087     *changedPiece = 0;
0088     if (mpGameReplayer->getNextRecords(&tmpData)) {
0089         for (size_t i = 0; i < tmpData.size(); i++) {
0090             switch (tmpData[i].type) {
0091             case RecordDataType_MovePieceLeft:
0092                 maGameList[tmpData[i].index]->setCurrentPiece(-1, 0, 0);
0093 //                    printf("[%d] - Move Left\n", tmpData[i].index);
0094                 break;
0095             case RecordDataType_MovePieceRight:
0096                 maGameList[tmpData[i].index]->setCurrentPiece(1, 0, 0);
0097 //                    printf("[%d] - Move Right\n", tmpData[i].index);
0098                 break;
0099             case RecordDataType_MovePieceUp:
0100                 maGameList[tmpData[i].index]->setCurrentPiece(0, -1, 0);
0101 //                    printf("[%d] - Move Up\n", tmpData[i].index);
0102                 break;
0103             case RecordDataType_MovePieceDown:
0104                 maGameList[tmpData[i].index]->setCurrentPiece(0, 1, 0);
0105 //                    printf("[%d] - Move Down\n", tmpData[i].index);
0106                 break;
0107             case RecordDataType_RotatePieceCW:
0108                 maGameList[tmpData[i].index]->setCurrentPiece(0, 0, -1);
0109 //                    printf("[%d] - Rotate Left\n", tmpData[i].index);
0110                 break;
0111             case RecordDataType_RotatePieceCCW:
0112                 maGameList[tmpData[i].index]->setCurrentPiece(0, 0, 1);
0113 //                    printf("[%d] - Rotate Right\n", tmpData[i].index);
0114                 break;
0115             case RecordDataType_GameOneStep:
0116                 maGameList[tmpData[i].index]->forceUpdateGame();
0117                 *changedPiece |= (1 << tmpData[i].index);
0118 //                    printf("[%d] - Game Stepped\n", tmpData[i].index);
0119                 break;
0120             case RecordDataType_PunishLineCount:
0121                 tmpCount = tmpData[i].value;
0122                 ++i;
0123                 if (tmpData[i].type == RecordDataType_PunishLineSeed) {
0124                     maGameList[tmpData[i].index]->punishGame(tmpCount, tmpData[i].value);
0125 //                        printf("[%d] - Punish %d(%d)\n", tmpData[i].index, tmpCount, tmpData[i].value);
0126                 }
0127                 break;
0128             case RecordDataType_Skipped:
0129 //                    printf("[%d] - A skipper step\n", tmpData[i].index);
0130                 break;
0131             default:
0132 //                    printf("[%d] - Error default\n", tmpData[i].index);
0133                 break;
0134             }
0135         }
0136         return true;
0137     } else {
0138         return false;
0139     }
0140 }
0141 
0142 void KBlocksGameLogic::saveRecord(const char *fileName, bool binaryMode)
0143 {
0144     if (mpGameRecorder) {
0145         mpGameRecorder->save(fileName, binaryMode);
0146     }
0147 }
0148 
0149 int KBlocksGameLogic::levelUpGame(int level)
0150 {
0151     mGameInterval -= (mLevelUpInterval * level);
0152     if (mGameInterval < (mLevelUpInterval * 2)) {
0153         mGameInterval = mLevelUpInterval;
0154     }
0155     setGameInterval(mGameInterval);
0156     return mGameInterval;
0157 }
0158 
0159 int KBlocksGameLogic::updateGame(int *lineList)
0160 {
0161     for (int i = 0; i < mGameCount; i++) {
0162         int tmpTotal = 0;
0163         int tmpValue = 0;
0164         int tmpPunishCount = 0;
0165 
0166         while (maGameList[i]->pickGameResult(&tmpValue)) {
0167             if (tmpValue < 0) {
0168                 tmpTotal = -1;
0169                 tmpPunishCount = 0;
0170                 break;
0171             }
0172             tmpTotal += tmpValue;
0173             tmpPunishCount += (tmpValue - 1);
0174         }
0175 
0176         lineList[i] = tmpTotal;
0177 
0178         if ((mPunishFlag) && (tmpPunishCount > 0)) {
0179             int punishSeed = QRandomGenerator::global()->bounded(256);
0180             for (int j = 0; j < i; j++) {
0181                 maGameList[j]->punishGame(tmpPunishCount, punishSeed);
0182             }
0183             for (int j = i + 1; j < mGameCount; j++) {
0184                 maGameList[j]->punishGame(tmpPunishCount, punishSeed);
0185             }
0186         }
0187     }
0188 
0189     return getActiveGameCount();
0190 }
0191 
0192 void KBlocksGameLogic::setGameSeed(int seed)
0193 {
0194     mGameSeed = (seed % 256);
0195 }
0196 
0197 void KBlocksGameLogic::setGamePunish(bool flag)
0198 {
0199     mPunishFlag = flag;
0200 }
0201 
0202 void KBlocksGameLogic::setGameStandbyMode(bool flag)
0203 {
0204     mStandbyMode = flag;
0205     for (int i = 0; i < mGameCount; i++) {
0206         maGameList[i]->setGameStandbyMode(mStandbyMode);
0207     }
0208 }
0209 
0210 void KBlocksGameLogic::setGameInterval(int interval)
0211 {
0212     mGameInterval = interval;
0213     for (int i = 0; i < mGameCount; i++) {
0214         maGameList[i]->setGameInterval(mGameInterval);
0215     }
0216 }
0217 
0218 void KBlocksGameLogic::setInitInterval(int interval)
0219 {
0220     mInitialInterval = interval;
0221 }
0222 
0223 void KBlocksGameLogic::setLevelUpInterval(int interval)
0224 {
0225     mLevelUpInterval = interval;
0226 }
0227 
0228 bool KBlocksGameLogic::startGame(int gameCount)
0229 {
0230     if (mGameCount != 0) {
0231         return false;
0232     }
0233     mGameInterval = mInitialInterval;
0234     createSingleGames(gameCount);
0235     return true;
0236 }
0237 
0238 bool KBlocksGameLogic::stopGame()
0239 {
0240     if (mGameCount == 0) {
0241         return false;
0242     }
0243 
0244     for (int i = 0; i < mGameCount; ++i) {
0245         maGameList[i]->stopGame();
0246     }
0247     Q_EMIT allGamesStopped();
0248 
0249     return true;
0250 }
0251 
0252 void KBlocksGameLogic::pauseGame(bool pauseFlag)
0253 {
0254     for (int i = 0; i < mGameCount; i++) {
0255         maGameList[i]->pauseGame(pauseFlag);
0256     }
0257 }
0258 
0259 void KBlocksGameLogic::continueGame()
0260 {
0261     for (int i = 0; i < mGameCount; i++) {
0262         maGameList[i]->continueGame();
0263     }
0264 }
0265 
0266 bool KBlocksGameLogic::hasSingleGames()
0267 {
0268     return mGameCount != 0;
0269 }
0270 
0271 void KBlocksGameLogic::createSingleGames(int gameCount)
0272 {
0273     if (gameCount > mGameMax) {
0274         gameCount = mGameMax;
0275     }
0276     mGameCount = gameCount;
0277 
0278     if (mpGameRecorder) {
0279         mpGameRecorder->append(0, RecordDataType_GameCount, mGameCount);
0280         if (mGameSeed < 0) {
0281             mpGameRecorder->append(0, RecordDataType_GameSeed, -mGameSeed);
0282         } else {
0283             mpGameRecorder->append(1, RecordDataType_GameSeed, mGameSeed);
0284         }
0285     }
0286 
0287     int *seedList = new int[mGameCount];
0288     if (mGameSeed < 0) {
0289         mGameSeed = -mGameSeed;
0290         QRandomGenerator randomGenerator(mGameSeed);
0291         for (int i = 0; i < mGameCount; i++) {
0292             seedList[i] = randomGenerator.bounded(256);
0293         }
0294     } else {
0295         for (int i = 0; i < mGameCount; i++) {
0296             seedList[i] = mGameSeed;
0297         }
0298     }
0299 
0300     for (int i = 0; i < mGameCount; i++) {
0301         maGameList[i] = new KBlocksSingleGame(i);
0302         connect(maGameList[i], &KBlocksSingleGame::gameStopped,
0303                  this, &KBlocksGameLogic::stopGame);
0304         maGameList[i]->setGameStandbyMode(mStandbyMode);
0305         maGameList[i]->setGameInterval(mGameInterval);
0306         maGameList[i]->setGameRecorder(mpGameRecorder);
0307         maGameList[i]->startGame(seedList[i]);
0308     }
0309 
0310     delete[] seedList;
0311 }
0312 
0313 void KBlocksGameLogic::deleteSingleGames()
0314 {
0315     for (int i = 0; i < mGameCount; i++) {
0316         maGameList[i]->stopGame();
0317         delete maGameList[i];
0318         maGameList[i] = nullptr;
0319     }
0320     mGameCount = 0;
0321 }
0322 
0323 #include "moc_KBlocksGameLogic.cpp"