#pragma once #include #include enum class PieceType { I = 0, O, T, S, Z, J, L, NONE }; struct Point { int x; int y; }; // Coordinates for all 7 Tetromino types in their 4 rotation states (0, 1, 2, 3) // Pivot anchor is (0,0). Screen space has Y-down, X-right. inline const Point TETROMINO_CELLS[7][4][4] = { // 0: I Piece { { {-1, 0}, {0, 0}, {1, 0}, {2, 0} }, // rot 0 { {1, -1}, {1, 0}, {1, 1}, {1, 2} }, // rot 1 { {-1, 1}, {0, 1}, {1, 1}, {2, 1} }, // rot 2 { {0, -1}, {0, 0}, {0, 1}, {0, 2} } // rot 3 }, // 1: O Piece { { {0, 0}, {1, 0}, {0, 1}, {1, 1} }, // rot 0 { {0, 0}, {1, 0}, {0, 1}, {1, 1} }, // rot 1 { {0, 0}, {1, 0}, {0, 1}, {1, 1} }, // rot 2 { {0, 0}, {1, 0}, {0, 1}, {1, 1} } // rot 3 }, // 2: T Piece { { {-1, 0}, {0, 0}, {1, 0}, {0, 1} }, // rot 0 { {0, -1}, {0, 0}, {0, 1}, {-1, 0} }, // rot 1 { {-1, 0}, {0, 0}, {1, 0}, {0, -1} }, // rot 2 { {0, -1}, {0, 0}, {0, 1}, {1, 0} } // rot 3 }, // 3: S Piece { { {0, 0}, {1, 0}, {-1, 1}, {0, 1} }, // rot 0 { {0, -1}, {0, 0}, {1, 0}, {1, 1} }, // rot 1 { {0, -1}, {1, -1}, {-1, 0}, {0, 0} }, // rot 2 { {-1, -1}, {-1, 0}, {0, 0}, {0, 1} } // rot 3 }, // 4: Z Piece { { {-1, 0}, {0, 0}, {0, 1}, {1, 1} }, // rot 0 { {1, -1}, {1, 0}, {0, 0}, {0, 1} }, // rot 1 { {-1, -1}, {0, -1}, {0, 0}, {1, 0} }, // rot 2 { {0, -1}, {0, 0}, {-1, 0}, {-1, 1} } // rot 3 }, // 5: J Piece { { {-1, 0}, {0, 0}, {1, 0}, {-1, 1} }, // rot 0 { {0, -1}, {0, 0}, {0, 1}, {-1, -1} }, // rot 1 { {-1, 0}, {0, 0}, {1, 0}, {1, -1} }, // rot 2 { {0, -1}, {0, 0}, {0, 1}, {1, 1} } // rot 3 }, // 6: L Piece { { {-1, 0}, {0, 0}, {1, 0}, {1, 1} }, // rot 0 { {0, -1}, {0, 0}, {0, 1}, {-1, 1} }, // rot 1 { {-1, 0}, {0, 0}, {1, 0}, {-1, -1} }, // rot 2 { {0, -1}, {0, 0}, {0, 1}, {1, -1} } // rot 3 } }; enum class GameState { START, PLAYING, PAUSED, GAME_OVER }; class Game { public: static constexpr int BOARD_WIDTH = 10; static constexpr int BOARD_HEIGHT = 20; Game(); ~Game() = default; void init(); void reset(); // Core game loop update (handles gravity, lock delay, game states) // Returns true if lines were cleared in this frame bool update(float dt); // Gameplay commands (inputs) bool moveLeft(); bool moveRight(); bool rotate(int dir); // dir = 1 (CW), -1 (CCW) void softDrop(); bool hardDrop(); // Returns true if piece locked void holdPiece(); // Query states GameState getState() const { return mState; } void setState(GameState state) { mState = state; } int getScore() const { return mScore; } int getLinesCleared() const { return mLinesCleared; } int getLevel() const { return mLevel; } int getCombo() const { return mCombo; } PieceType getCell(int x, int y) const { if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) return PieceType::NONE; return mBoard[y][x]; } PieceType getActivePieceType() const { return mActiveType; } int getActiveX() const { return mActiveX; } int getActiveY() const { return mActiveY; } int getActiveRotation() const { return mActiveRot; } // Relative cell coordinates of current falling block std::vector getActiveCells() const; // Absolute cell coordinates of where active piece would land (ghost projection) std::vector getGhostCells() const; PieceType getHoldPieceType() const { return mHoldType; } bool canHold() const { return mCanHold; } std::vector getNextQueue() const { return mNextQueue; } // Inter-thread game sound effects triggers bool flagMoveSFX = false; bool flagRotateSFX = false; bool flagLandSFX = false; bool flagLineClearSFX = false; bool flagTetrisClearSFX = false; bool flagLevelUpSFX = false; bool flagGameOverSFX = false; // Screen shake parameters float getScreenShakeIntensity() const { return mShakeIntensity; } void resetScreenShake() { mShakeIntensity = 0.0f; } // List of lines cleared on the current tick (for particle animations) std::vector mClearedLinesThisTick; std::vector mLastLockedCells; private: GameState mState = GameState::START; // The grid: index y=0 is top, y=19 is bottom PieceType mBoard[BOARD_HEIGHT][BOARD_WIDTH]; // Falling piece details PieceType mActiveType = PieceType::NONE; int mActiveX = 0; int mActiveY = 0; int mActiveRot = 0; // Hold slot details PieceType mHoldType = PieceType::NONE; bool mCanHold = true; // 7-piece bag randomizer std::vector mNextQueue; std::vector mBag; std::mt19937 mRng; // Score metrics int mScore = 0; int mLinesCleared = 0; int mLevel = 1; int mCombo = -1; // Fall & Lock delay timers float mFallTimer = 0.0f; float mLockTimer = 0.0f; bool mIsLocking = false; float mShakeIntensity = 0.0f; float getFallDelay() const; void spawnPiece(); void fillBag(); PieceType popNextPiece(); bool checkCollision(const std::vector& cells, int dx, int dy) const; bool fits(PieceType type, int rot, int cx, int cy) const; void lockPiece(); void clearLines(); };