#pragma once #include "../Pieces/Piece.h" #include "Board.h" #include "Bag.h" #include "LineClear.h" #include #include /** * Links a board with the pieces moving in it */ class GameBoard { private: Board board; // the board in which pieces moves, (0, 0) is downleft Bag generator; // the piece generator std::shared_ptr activePiece; // the piece currently in the board Position activePiecePosition; // the position of the piece currently in the board std::shared_ptr heldPiece; // a piece being holded int nextQueueLength; // the number of next pieces seeable at a time std::vector nextQueue; // the list of the next pieces to spawn in the board bool isLastMoveKick; // wheter the last action the piece did was kicking bool movedLeftLast; // wheter the last sideway movement was a left one public: /** * Creates a new board, generator, and next queue */ GameBoard(int boardWidth, int boardHeight, const std::shared_ptr& piecesList, int nextQueueLength); /** * Resets the board as if it was newly created */ void reset(); private: /** * Initializes the board */ void initialize(); public: /** * Tries moving the piece one position to the left * @return If it suceeded */ bool moveLeft(); /** * Tries moving the piece one position to the right * @return If it suceeded */ bool moveRight(); /** * Tries moving the piece one position down * @return If it suceeded */ bool moveDown(); /** * Tries rotating the piece and kicking it if necessary, if it's a 0° rotation, it will forcefully try kicking * @return If it suceeded */ bool rotate(Rotation rotation); private: /** * Tries kicking the piece, testing position either above or below the piece's initial position * @return If it suceeded */ bool tryKicking(bool testingBottom, const std::set& safePositions); /** * Tries fitting the kicked active piece at the specified position * @return If it suceeded */ bool tryFittingKickedPiece(const std::set& safePositions, const Position& shift, bool& overlaps); /** * Check if one of the active piece's positions shifted by a specified position would overlap with a set of positions * @return If the shifted active piece overlaps with one of the position */ bool activePieceOverlaps(const std::set& safePositions, const Position& shift = Position{0, 0}) const; public: /** * Tries holding the active piece or swapping it if one was already stocked, while trying to apply an initial rotation to the newly spawned piece * @return If it suceeded */ bool hold(Rotation initialRotation = NONE); /** * Spawns the next piece from the queue * @return If it spawned in a wall */ bool spawnNextPiece(); /** * Checks if one of the active piece's positions touches a wall in the board * @return If the active piece is in a wall */ bool activePieceInWall(const Position& shift = Position{0, 0}) const; /** * Checks is the active piece as a wall directly below one of its position * @return If it touches a ground */ bool touchesGround() const; /** * Computes what the piece position would be if it were to be dropped down as much as possible * @return The lowest position before hitting a wall */ Position lowestPosition() const; /** * Locks the active piece into the board and clears lines if needed * @return The resulting line clear */ LineClear lockPiece(); /** * Adds a specified number of garbage rows to the bottom of the board, the hole position being random but the same for all of them */ void addGarbageRows(int number); /** * @return The board */ const Board& getBoard() const; /** * @return A pointer to the active piece, can be null */ const std::shared_ptr& getActivePiece() const; /** * @return The position of the active piece */ const Position& getActivePiecePosition() const; /** * @return A pointer to the held piece, can be null */ const std::shared_ptr& getHeldPiece() const; /** * @return The next piece queue, can be empty */ const std::vector& getNextPieces() const; private: /** * Sets the active piece to its spawn position */ void goToSpawnPosition(); public: /** * Stream output operator, adds the board, the hold box and the next queue * @return A reference to the output stream */ friend std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard); };