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"