File indexing completed on 2024-04-21 04:02:08
0001 /*************************************************************************** 0002 * KBlocks, a falling blocks game by KDE * 0003 * SPDX-FileCopyrightText: 2010 Zhongjie Cai <squall.leonhart.cai@gmail.com> * 0004 * * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 ***************************************************************************/ 0007 #include "KBlocksSingleGame.h" 0008 #include "utils.h" 0009 #include <QRandomGenerator> 0010 #include <memory> 0011 0012 KBlocksSingleGame::KBlocksSingleGame(int gameIndex, int fieldWidth, int fieldHeight, int showPieceCount, int messagePoolSize) 0013 { 0014 mGameIndex = gameIndex; 0015 0016 mpField = new KBlocksField(fieldWidth, fieldHeight); 0017 0018 mPieceCount = showPieceCount; 0019 mpPieceList = new KBlocksPiece*[mPieceCount]; 0020 for (int i = 0; i < mPieceCount; i++) { 0021 mpPieceList[i] = new KBlocksPiece(); 0022 } 0023 0024 mpPieceGenerator = new KBlocksPieceGenerator(); 0025 mpGameMessage = new KBlocksGameMessage(messagePoolSize); 0026 mpGameRecorder = nullptr; 0027 0028 mCurrentGameState = GameState_Stop; 0029 0030 mStandbyMode = false; 0031 mStandbyFlag = false; 0032 0033 mGameInterval = 0; 0034 mGameStartTime = 0; 0035 } 0036 0037 KBlocksSingleGame::~KBlocksSingleGame() 0038 { 0039 delete mpGameMessage; 0040 delete mpPieceGenerator; 0041 0042 for (int i = 0; i < mPieceCount; i++) { 0043 delete mpPieceList[i]; 0044 } 0045 delete [] mpPieceList; 0046 0047 delete mpField; 0048 } 0049 0050 KBlocksField *KBlocksSingleGame::getField() 0051 { 0052 return mpField; 0053 } 0054 0055 int KBlocksSingleGame::getPieceCount() 0056 { 0057 return mPieceCount; 0058 } 0059 0060 KBlocksPiece *KBlocksSingleGame::getPiece(int index) 0061 { 0062 if ((index < 0) || (index >= mPieceCount)) { 0063 return nullptr; 0064 } 0065 return mpPieceList[index]; 0066 } 0067 0068 bool KBlocksSingleGame::isActive() 0069 { 0070 if ((mCurrentGameState != GameState_Running) || mStandbyFlag) { 0071 return false; 0072 } 0073 return true; 0074 } 0075 0076 bool KBlocksSingleGame::isGameRunning() 0077 { 0078 if (mCurrentGameState == GameState_Stop) { 0079 return false; 0080 } 0081 return true; 0082 } 0083 0084 void KBlocksSingleGame::setGameStandbyMode(bool flag) 0085 { 0086 mStandbyMode = flag; 0087 } 0088 0089 void KBlocksSingleGame::setGameInterval(int interval) 0090 { 0091 mGameInterval = interval; 0092 } 0093 0094 void KBlocksSingleGame::setGameRecorder(KBlocksGameRecorder *p) 0095 { 0096 mpGameRecorder = p; 0097 } 0098 0099 int KBlocksSingleGame::forceUpdateGame() 0100 { 0101 return doUpdateGame(true); 0102 } 0103 0104 int KBlocksSingleGame::updateGame() 0105 { 0106 return doUpdateGame(false); 0107 } 0108 0109 int KBlocksSingleGame::punishGame(int lineCount, int punishSeed) 0110 { 0111 if (mCurrentGameState == GameState_Stop) { 0112 return GameResult_None; 0113 } 0114 0115 int width = mpField->getWidth(); 0116 0117 int gameResult = GameResult_None; 0118 0119 if (mpGameRecorder) { 0120 mpGameRecorder->append(mGameIndex, RecordDataType_PunishLineCount, lineCount); 0121 mpGameRecorder->append(mGameIndex, RecordDataType_PunishLineSeed, punishSeed); 0122 } 0123 0124 QRandomGenerator randomGenerator(punishSeed); 0125 int punishIndex = 0; 0126 for (int i = 0; i < lineCount; i++) { 0127 setCurrentPiece(0, -1, 0); 0128 punishIndex = randomGenerator.bounded(width); 0129 mpField->addPunishLine(lineCount, punishIndex); 0130 } 0131 0132 if (lineCount > 0) { 0133 mpGameMessage->putGameAction(GameAction_Punish_Line, lineCount); 0134 } 0135 0136 return gameResult; 0137 } 0138 0139 bool KBlocksSingleGame::setCurrentPiece(int xPos, int yPos, int rotation) 0140 { 0141 if ((mCurrentGameState != GameState_Running) || mStandbyFlag) { 0142 return false; 0143 } 0144 0145 std::unique_ptr<KBlocksPiece> tmpPiece(new KBlocksPiece()); 0146 0147 tmpPiece->fromValue(mpPieceList[0]->toValue()); 0148 tmpPiece->setPosX(mpPieceList[0]->getPosX() + xPos); 0149 if (mpPieceList[0]->getPosY() + yPos < 0) { 0150 tmpPiece->setPosY(0); 0151 } else { 0152 tmpPiece->setPosY(mpPieceList[0]->getPosY() + yPos); 0153 } 0154 tmpPiece->setRotation(mpPieceList[0]->getRotation() + rotation); 0155 0156 if (checkPieceTouchGround(tmpPiece.get())) { 0157 return false; 0158 } 0159 0160 mpPieceList[0]->setPosX(tmpPiece->getPosX()); 0161 mpPieceList[0]->setPosY(tmpPiece->getPosY()); 0162 mpPieceList[0]->setRotation(tmpPiece->getRotation()); 0163 0164 if (mpGameRecorder) { 0165 if (xPos < 0) { 0166 mpGameRecorder->append(mGameIndex, RecordDataType_MovePieceLeft, 1); 0167 } 0168 if (xPos > 0) { 0169 mpGameRecorder->append(mGameIndex, RecordDataType_MovePieceRight, 1); 0170 } 0171 if (yPos < 0) { 0172 mpGameRecorder->append(mGameIndex, RecordDataType_MovePieceUp, 1); 0173 } 0174 if (yPos > 0) { 0175 mpGameRecorder->append(mGameIndex, RecordDataType_MovePieceDown, 1); 0176 } 0177 if (rotation < 0) { 0178 mpGameRecorder->append(mGameIndex, RecordDataType_RotatePieceCW, 1); 0179 } 0180 if (rotation > 0) { 0181 mpGameRecorder->append(mGameIndex, RecordDataType_RotatePieceCCW, 1); 0182 } 0183 } 0184 0185 return true; 0186 } 0187 0188 int KBlocksSingleGame::startGame(int seed) 0189 { 0190 if (mCurrentGameState != GameState_Stop) { 0191 return mCurrentGameState; 0192 } 0193 0194 mpPieceGenerator->genList(seed); 0195 0196 for (int i = 0; i < mPieceCount; i++) { 0197 mpPieceList[i]->fromValue(mpPieceGenerator->getPiece()); 0198 } 0199 0200 mpPieceList[0]->setPosX(mpField->getWidth() / 2); 0201 mpPieceList[0]->setPosY(0); 0202 0203 mpPieceList[1]->setPosX(2); 0204 mpPieceList[1]->setPosY(2); 0205 0206 mpGameMessage->clearGameResult(); 0207 mpGameMessage->clearGameAction(); 0208 0209 mCurrentGameState = GameState_Running; 0210 0211 mGameStartTime = Utils::getMillisecOfNow(); 0212 0213 return mCurrentGameState; 0214 } 0215 0216 int KBlocksSingleGame::stopGame() 0217 { 0218 if (mCurrentGameState != GameState_Stop) { 0219 mCurrentGameState = GameState_Stop; 0220 Q_EMIT gameStopped(); 0221 } 0222 0223 return mCurrentGameState; 0224 } 0225 0226 int KBlocksSingleGame::pauseGame(bool flag) 0227 { 0228 if ((mCurrentGameState == GameState_Running) && flag) { 0229 mCurrentGameState = GameState_Pause; 0230 } else if ((mCurrentGameState == GameState_Pause) && (!flag)) { 0231 mCurrentGameState = GameState_Running; 0232 0233 mGameStartTime = Utils::getMillisecOfNow(); 0234 } 0235 0236 return mCurrentGameState; 0237 } 0238 0239 int KBlocksSingleGame::continueGame() 0240 { 0241 if ((mCurrentGameState != GameState_Stop) && mStandbyFlag) { 0242 mStandbyFlag = false; 0243 0244 mGameStartTime = Utils::getMillisecOfNow(); 0245 } 0246 0247 return mCurrentGameState; 0248 } 0249 0250 bool KBlocksSingleGame::pickGameResult(int *result) 0251 { 0252 return mpGameMessage->pickGameResult(result); 0253 } 0254 0255 bool KBlocksSingleGame::pickGameAction(int *type, int *action) 0256 { 0257 return mpGameMessage->pickGameAction(type, action); 0258 } 0259 0260 int KBlocksSingleGame::doUpdateGame(bool force) 0261 { 0262 if (mCurrentGameState == GameState_Stop) { 0263 return GameResult_Game_Over; 0264 } else if ((mCurrentGameState != GameState_Running) || mStandbyFlag) { 0265 return GameResult_None; 0266 } 0267 0268 timeLong tmpCurTime = Utils::getMillisecOfNow(); 0269 0270 int gameResult = GameResult_None; 0271 0272 if (force) { 0273 runGameOneStep(&gameResult); 0274 } else { 0275 if (mGameInterval < 0) { 0276 return gameResult; 0277 } 0278 0279 while (1) { 0280 if (mGameStartTime + mGameInterval > tmpCurTime) { 0281 break; 0282 } 0283 0284 mGameStartTime += mGameInterval; 0285 0286 if (runGameOneStep(&gameResult) || (mGameInterval == 0)) { 0287 break; 0288 } 0289 } 0290 } 0291 0292 return gameResult; 0293 } 0294 0295 bool KBlocksSingleGame::runGameOneStep(int *gameResult) 0296 { 0297 if (!setCurrentPiece(0, 1, 0)) { 0298 *gameResult = GameResult_Next_Piece; 0299 0300 freezePieceToField(mpPieceList[0]); 0301 0302 *gameResult += removeFieldLines(); 0303 0304 if (mStandbyMode) { 0305 mStandbyFlag = true; 0306 } 0307 0308 prepareNextPiece(); 0309 if (checkPieceTouchGround(mpPieceList[0])) { 0310 *gameResult = GameResult_Game_Over; 0311 mpGameMessage->putGameResult(-1); 0312 stopGame(); 0313 } 0314 0315 if (mpGameRecorder) { 0316 mpGameRecorder->append(mGameIndex, RecordDataType_GameOneStep, 1); 0317 } 0318 0319 return true; 0320 } else { 0321 *gameResult = GameResult_One_Step; 0322 0323 return false; 0324 } 0325 } 0326 0327 bool KBlocksSingleGame::checkPieceTouchGround(KBlocksPiece *p) 0328 { 0329 for (int i = 0; i < 4; i++) { 0330 int posX = p->getCellPosX(i); 0331 int posY = p->getCellPosY(i); 0332 if (mpField->getCell(posX, posY)) { 0333 return true; 0334 } 0335 } 0336 return false; 0337 } 0338 0339 void KBlocksSingleGame::freezePieceToField(KBlocksPiece *p) 0340 { 0341 mpGameMessage->putGameAction(GameAction_Freeze_Piece_Color, mpPieceList[0]->getType()); 0342 for (int i = 0; i < 4; i++) { 0343 int posX = p->getCellPosX(i); 0344 int posY = p->getCellPosY(i); 0345 mpField->setCell(posX, posY, true); 0346 mpGameMessage->putGameAction(GameAction_Freeze_Piece_X, posX); 0347 mpGameMessage->putGameAction(GameAction_Freeze_Piece_Y, posY); 0348 } 0349 } 0350 0351 int KBlocksSingleGame::removeFieldLines() 0352 { 0353 int lineCount = 0; 0354 0355 int maxLines = mpField->getHeight(); 0356 for (int i = 0; i < maxLines; i++) { 0357 if (mpField->checkFilledLine(i)) { 0358 mpGameMessage->putGameAction(GameAction_Remove_Line, i); 0359 mpField->removeFilledLine(i); 0360 lineCount++; 0361 } 0362 } 0363 0364 if (lineCount > 0) { 0365 mpGameMessage->putGameResult(lineCount); 0366 } 0367 0368 return lineCount; 0369 } 0370 0371 void KBlocksSingleGame::prepareNextPiece() 0372 { 0373 for (int i = 0; i < mPieceCount - 1; i++) { 0374 mpPieceList[i]->fromValue(mpPieceList[i + 1]->toValue()); 0375 } 0376 0377 int pieceValue = mpPieceGenerator->getPiece(); 0378 mpPieceList[mPieceCount - 1]->fromValue(pieceValue); 0379 0380 mpPieceList[0]->setPosX(mpField->getWidth() / 2); 0381 mpPieceList[0]->setPosY(0); 0382 0383 mpPieceList[1]->setPosX(2); 0384 mpPieceList[1]->setPosY(2); 0385 0386 for (int i = 0; i < 4; i++) { 0387 int posX = mpPieceList[0]->getCellPosX(i); 0388 int posY = mpPieceList[0]->getCellPosY(i); 0389 mpGameMessage->putGameAction(GameAction_New_Piece_X, posX); 0390 mpGameMessage->putGameAction(GameAction_New_Piece_Y, posY); 0391 } 0392 } 0393 0394 #include "moc_KBlocksSingleGame.cpp"