From f525c00662375c5cf9831963a7b049a18182b67a Mon Sep 17 00:00:00 2001 From: zulianc Date: Sat, 1 Mar 2025 22:21:43 +0100 Subject: [PATCH] =?UTF-8?q?const=20everywhere=20+=20l=C3=A9g=C3=A8rement?= =?UTF-8?q?=20changer=20format=20fichiers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/pieces_storage.md | 5 ++-- src/Core/Game.cpp | 26 +++++++++---------- src/Core/Game.h | 28 ++++++++++---------- src/Core/GameParameters.cpp | 26 +++++++++---------- src/Core/GameParameters.h | 26 +++++++++---------- src/Core/Menu.cpp | 6 ++--- src/Core/Menu.h | 8 +++--- src/Core/PiecesList.cpp | 8 +++--- src/Core/PiecesList.h | 8 +++--- src/Core/Player.cpp | 6 ++--- src/Core/Player.h | 6 ++--- src/Core/main.cpp | 52 +++++++++++++++++++++++++++++++++---- src/Pieces/Generator.cpp | 1 + src/Pieces/PiecesFiles.cpp | 40 ++++++++++++---------------- src/Pieces/Polyomino.cpp | 18 ++++++------- 15 files changed, 151 insertions(+), 113 deletions(-) diff --git a/doc/pieces_storage.md b/doc/pieces_storage.md index c3a6a6d..5d69cf7 100644 --- a/doc/pieces_storage.md +++ b/doc/pieces_storage.md @@ -6,15 +6,14 @@ If you don't know what a polyomino is, check [this other file](Pieces_representa Generating polyominos of size n is exponential in regard to n. Because of this, we will store the pieces beforehand and load them upon launching the game. -We want the pieces to be always sorted in the same order, always attributed the same block type, and always set at the same spawn position, no matter how they were generated. We also want them to be separated in 3 categories : convex, not convex but without a hole, and with a hole. Theses problematics are already resolved internally, but will be calculated before storage as to not need extra calculcations upon load. +We want the pieces to be always sorted in the same order, always attributed the same block type, and always set at the same spawn position, no matter how they were generated. We also want them to be separated in 3 categories : convex, not convex but without a hole, and with a hole. Theses problematics are already resolved internally, but will be calculated before storage as to not need extra calculcations upon load (except for the block type which is trivially computed). ## How is it stored Pieces are stored in binary files. Each file simply contains every polyomino of one size, one after the other. Since each file contains all polyominos of the same size, we know how much stuff to read and don't need delimiters. We know we've read all pieces simply when we reach the end of file character. Each piece is stored as follows: -- 1 byte for the length of the piece -- 1 byte for the other characteristics of the piece: ``ABCCCCCC`` where A indicates if the piece is convex, B indicates if it has a hole, and C is the block number of the piece +- 1 byte for the characteristics of the piece: ``ABCCCCCC`` where A indicates if the piece is convex, B indicates if it has a hole, and C is the length of the piece - 1 byte for each position: ``XXXXYYYY`` where X is the x coordinate of the position and Y is the y coordinate of the position The current implementation only allows to generate polyominos up to size 16, but can be upgraded by storing coordinates on 8 bits instead of 4. diff --git a/src/Core/Game.cpp b/src/Core/Game.cpp index fa095f6..d1bc6b7 100644 --- a/src/Core/Game.cpp +++ b/src/Core/Game.cpp @@ -259,54 +259,54 @@ void Game::lockPiece() { } } -bool Game::hasWon() { +bool Game::hasWon() const { return this->parameters.hasWon(this->framesPassed); } -bool Game::hasLost() { +bool Game::hasLost() const { return this->lost; } -int Game::getClearedLines() { +int Game::getClearedLines() const { return this->parameters.getClearedLines(); } -int Game::getLevel() { +int Game::getLevel() const { return this->parameters.getLevel(); } -int Game::getFramesPassed() { +int Game::getFramesPassed() const { return this->framesPassed; } -int Game::getScore() { +int Game::getScore() const { return this->score; } -bool Game::isOnB2BChain() { +bool Game::isOnB2BChain() const { return this->B2BChain; } -bool Game::areBlocksBones() { +bool Game::areBlocksBones() const { return this->parameters.getBoneBlocks(); } -Board Game::getBoard() { +Board Game::getBoard() const { return this->board.getBoard(); } -Piece Game::getActivePiece() { +Piece Game::getActivePiece() const { return this->board.getActivePiece(); } -Position Game::getActivePiecePosition() { +Position Game::getActivePiecePosition() const { return this->board.getActivePiecePosition(); } -Piece Game::getHeldPiece() { +Piece Game::getHeldPiece() const { return this->board.getHeldPiece(); } -std::vector Game::getNextPieces() { +std::vector Game::getNextPieces() const { return this->board.getNextPieces(); } diff --git a/src/Core/Game.h b/src/Core/Game.h index 0509c9d..61fac3e 100644 --- a/src/Core/Game.h +++ b/src/Core/Game.h @@ -61,7 +61,7 @@ class Game { private: /** - * Movse the piece in the specified direction + * Move the piece in the specified direction */ void movePiece(int movement, bool resetDirection); @@ -74,65 +74,65 @@ class Game { /** * @return If the player has won */ - bool hasWon(); + bool hasWon() const; /** * @return If the player has lost */ - bool hasLost(); + bool hasLost() const; /** * @return The current level */ - int getLevel(); + int getLevel() const; /** * @return The current number of cleared lines */ - int getClearedLines(); + int getClearedLines() const; /** * @return The number of frames passed since the start of the game */ - int getFramesPassed(); + int getFramesPassed() const; /** * @return The current score */ - int getScore(); + int getScore() const; /** * @return If the player is currently on a B2B chain */ - bool isOnB2BChain(); + bool isOnB2BChain() const; /** * @return If all blocks are currently bone blocks */ - bool areBlocksBones(); + bool areBlocksBones() const; /** * @return A copy of the board */ - Board getBoard(); + Board getBoard() const; /** * @return A copy of the active piece */ - Piece getActivePiece(); + Piece getActivePiece() const; /** * @return A copy of the active piece position */ - Position getActivePiecePosition(); + Position getActivePiecePosition() const; /** * @return A copy of the held piece */ - Piece getHeldPiece(); + Piece getHeldPiece() const; /** * @return A copy of the next pieces queue */ - std::vector getNextPieces(); + std::vector getNextPieces() const; }; diff --git a/src/Core/GameParameters.cpp b/src/Core/GameParameters.cpp index 23cbe7a..2f7009b 100644 --- a/src/Core/GameParameters.cpp +++ b/src/Core/GameParameters.cpp @@ -52,7 +52,7 @@ void GameParameters::clearLines(int lineNumber) { } } -bool GameParameters::hasWon(int framesPassed) { +bool GameParameters::hasWon(int framesPassed) const { switch (this->gamemode) { // win once 40 lines have been cleared case SPRINT : return this->clearedLines >= 40; @@ -198,50 +198,50 @@ void GameParameters::updateStats() { } } -int GameParameters::getClearedLines() { +int GameParameters::getClearedLines() const { return this->clearedLines; } -int GameParameters::getLevel() { +int GameParameters::getLevel() const { return this->level; } -int GameParameters::getNextQueueLength() { +int GameParameters::getNextQueueLength() const { return this->nextQueueLength; } -bool GameParameters::getBoneBlocks() { +bool GameParameters::getBoneBlocks() const { return this->boneBlocks; } -int GameParameters::getGravity() { +int GameParameters::getGravity() const { return this->gravity; } -int GameParameters::getLockDelay() { +int GameParameters::getLockDelay() const { return this->lockDelay; } -int GameParameters::getForcedLockDelay() { +int GameParameters::getForcedLockDelay() const { return this->forcedLockDelay; } -int GameParameters::getARE() { +int GameParameters::getARE() const { return this->ARE; } -int GameParameters::getLineARE() { +int GameParameters::getLineARE() const { return this->lineARE; } -int GameParameters::getDAS() { +int GameParameters::getDAS() const { return this->DAS; } -int GameParameters::getARR() { +int GameParameters::getARR() const { return this->ARR; } -int GameParameters::getSDR() { +int GameParameters::getSDR() const { return this->SDR; } diff --git a/src/Core/GameParameters.h b/src/Core/GameParameters.h index c06eabc..ed6b0f6 100644 --- a/src/Core/GameParameters.h +++ b/src/Core/GameParameters.h @@ -45,7 +45,7 @@ class GameParameters { * Checks if the game ended based on the current states and time passed, accorind to the gamemode * @return If the player has won */ - bool hasWon(int framesPassed); + bool hasWon(int framesPassed) const; private: /** @@ -57,60 +57,60 @@ class GameParameters { /** * @return The current number of cleared line */ - int getClearedLines(); + int getClearedLines() const; /** * @return The current level */ - int getLevel(); + int getLevel() const; /** * @return The length of the next queue */ - int getNextQueueLength(); + int getNextQueueLength() const; /** * Returns wheter the blocks are currently bone blocks */ - bool getBoneBlocks(); + bool getBoneBlocks() const; /** * @return The current gravity for a 20-line high board */ - int getGravity(); + int getGravity() const; /** * @return The current lock delay */ - int getLockDelay(); + int getLockDelay() const; /** * @return The current forced lock delay */ - int getForcedLockDelay(); + int getForcedLockDelay() const; /** * @return The current ARE */ - int getARE(); + int getARE() const; /** * @return The current line ARE */ - int getLineARE(); + int getLineARE() const; /** * @return The current DAS */ - int getDAS(); + int getDAS() const; /** * @return The current ARR */ - int getARR(); + int getARR() const; /** * @return The current SDR */ - int getSDR(); + int getSDR() const; }; diff --git a/src/Core/Menu.cpp b/src/Core/Menu.cpp index 24c6037..a4feba6 100644 --- a/src/Core/Menu.cpp +++ b/src/Core/Menu.cpp @@ -11,7 +11,7 @@ Menu::Menu() { this->boardWidth = 10; } -Game Menu::startGame(Gamemode gamemode) { +Game Menu::startGame(Gamemode gamemode) const { return Game(gamemode, this->playerControls, this->boardWidth, this->boardHeight, std::make_shared(this->piecesList)); } @@ -29,11 +29,11 @@ bool Menu::setBoardHeight(int height) { return true; } -int Menu::getBoardWidth() { +int Menu::getBoardWidth() const { return this->boardWidth; } -int Menu::getBoardHeight() { +int Menu::getBoardHeight() const { return this->boardHeight; } diff --git a/src/Core/Menu.h b/src/Core/Menu.h index 2b3e203..41331bc 100644 --- a/src/Core/Menu.h +++ b/src/Core/Menu.h @@ -4,6 +4,8 @@ #include "Player.h" #include "Game.h" +static const int FRAMES_PER_SECOND = 60; // the number of frames per second, all the values in the game were choosen with this number in mind + /** * The interface between the UI and the core of the game @@ -25,7 +27,7 @@ class Menu { * Starts a new game with the current settings * @return The game that has been created */ - Game startGame(Gamemode gamemode); + Game startGame(Gamemode gamemode) const; /** * Sets the width of the board, which must be greater than 0 @@ -42,12 +44,12 @@ class Menu { /** * @return The width of the board */ - int getBoardWidth(); + int getBoardWidth() const; /** * @return The height of the board */ - int getBoardHeight(); + int getBoardHeight() const; /** * @return A reference to the player's controls diff --git a/src/Core/PiecesList.cpp b/src/Core/PiecesList.cpp index 059ebc8..4e639d3 100644 --- a/src/Core/PiecesList.cpp +++ b/src/Core/PiecesList.cpp @@ -87,21 +87,21 @@ void PiecesList::unselectAll() { this->selectedPieces.clear(); } -int PiecesList::getHighestLoadedSize() { +int PiecesList::getHighestLoadedSize() const { return this->highestLoadedSize; } -int PiecesList::getNumberOfPieces(int size) { +int PiecesList::getNumberOfPieces(int size) const { if (size < 1 || size > this->highestLoadedSize) return 0; return this->loadedPieces.at(size).size(); } -std::vector> PiecesList::getSelectedPieces() { +std::vector> PiecesList::getSelectedPieces() const { return this->selectedPieces; } -Piece PiecesList::getPiece(std::pair pieceIndex) { +Piece PiecesList::getPiece(std::pair pieceIndex) const { return this->loadedPieces.at(pieceIndex.first).at(pieceIndex.second); } diff --git a/src/Core/PiecesList.h b/src/Core/PiecesList.h index 99f7328..bd524e8 100644 --- a/src/Core/PiecesList.h +++ b/src/Core/PiecesList.h @@ -69,22 +69,22 @@ class PiecesList { /** * @return The highest loaded size of pieces */ - int getHighestLoadedSize(); + int getHighestLoadedSize() const; /** * @return The number of pieces of the specified size */ - int getNumberOfPieces(int size); + int getNumberOfPieces(int size) const; /** * @return The indexes of all selected pieces */ - std::vector> getSelectedPieces(); + std::vector> getSelectedPieces() const; /** * @return The piece corresponding to the specified index */ - Piece getPiece(std::pair pieceIndex); + Piece getPiece(std::pair pieceIndex) const; private: /** diff --git a/src/Core/Player.cpp b/src/Core/Player.cpp index 9bd77f5..7b6f68a 100644 --- a/src/Core/Player.cpp +++ b/src/Core/Player.cpp @@ -36,14 +36,14 @@ bool Player::setSDR(int SDR) { return true; } -int Player::getDAS() { +int Player::getDAS() const { return this->DAS; } -int Player::getARR() { +int Player::getARR() const { return this->ARR; } -int Player::getSDR() { +int Player::getSDR() const { return this->SDR; } diff --git a/src/Core/Player.h b/src/Core/Player.h index a790d53..69e0033 100644 --- a/src/Core/Player.h +++ b/src/Core/Player.h @@ -37,15 +37,15 @@ class Player { /** * @return DAS value */ - int getDAS(); + int getDAS() const; /** * @return ARR value */ - int getARR(); + int getARR() const; /** * @return SDR value */ - int getSDR(); + int getSDR() const; }; diff --git a/src/Core/main.cpp b/src/Core/main.cpp index 33cdafa..cf36506 100644 --- a/src/Core/main.cpp +++ b/src/Core/main.cpp @@ -10,6 +10,8 @@ void testGeneratorForOneSize(int size); void testGeneratorByprintingAllNminos(int n); void testStoringAndRetrievingPieces(int size); void generateFilesForAllSizes(int amount); +void generateFilesForOneSize(int size); +void loadFromFilesForOneSize(int size); void readStatsFromFilesForAllSizes(int amount); @@ -107,8 +109,8 @@ void generateFilesForAllSizes(int amount) { using std::chrono::duration_cast; using std::chrono::duration; using std::chrono::milliseconds; - PiecesFiles piecesFiles; + for (int i = 1; i <= amount; i++) { auto t1 = high_resolution_clock::now(); piecesFiles.savePieces(i); @@ -118,12 +120,12 @@ void generateFilesForAllSizes(int amount) { std::cout << "Generated pieces files for size " << i << " in " << ms_double.count() << "ms" << std::endl; } + std::vector pieces; + std::vector convexPieces; + std::vector holelessPieces; + std::vector otherPieces; for (int i = 1; i <= amount; i++) { auto t1 = high_resolution_clock::now(); - std::vector pieces; - std::vector convexPieces; - std::vector holelessPieces; - std::vector otherPieces; piecesFiles.loadPieces(i, pieces, convexPieces, holelessPieces, otherPieces); auto t2 = high_resolution_clock::now(); @@ -132,6 +134,46 @@ void generateFilesForAllSizes(int amount) { } } +void generateFilesForOneSize(int size) { + using std::chrono::high_resolution_clock; + using std::chrono::duration_cast; + using std::chrono::duration; + using std::chrono::milliseconds; + PiecesFiles piecesFiles; + + std::cout << "Generating " << size << "-minos files" << std::endl; + for (int i = 0; i < 10; i++) { + auto t1 = high_resolution_clock::now(); + piecesFiles.savePieces(size); + auto t2 = high_resolution_clock::now(); + + duration ms_double = t2 - t1; + std::cout << ms_double.count() << "ms" << std::endl; + } +} + +void loadFromFilesForOneSize(int size) { + using std::chrono::high_resolution_clock; + using std::chrono::duration_cast; + using std::chrono::duration; + using std::chrono::milliseconds; + PiecesFiles piecesFiles; + + std::vector pieces; + std::vector convexPieces; + std::vector holelessPieces; + std::vector otherPieces; + std::cout << "Loading " << size << "-minos from files" << std::endl; + for (int i = 0; i < 10; i++) { + auto t1 = high_resolution_clock::now(); + piecesFiles.loadPieces(size, pieces, convexPieces, holelessPieces, otherPieces); + auto t2 = high_resolution_clock::now(); + + duration ms_double = t2 - t1; + std::cout << ms_double.count() << "ms" << std::endl; + } +} + void readStatsFromFilesForAllSizes(int amount) { PiecesFiles piecesFiles; for (int i = 1; i <= amount; i++) { diff --git a/src/Pieces/Generator.cpp b/src/Pieces/Generator.cpp index b681d8c..3e1db47 100644 --- a/src/Pieces/Generator.cpp +++ b/src/Pieces/Generator.cpp @@ -33,6 +33,7 @@ void Generator::generate(int polyominoSize, int lastAddedPositionNumber, int nex // we sort the rotations of the polyominos std::vector candidateRotations; + candidateRotations.reserve(4); for (int i = 0; i < 4; i++) { candidate.normalize(); candidateRotations.push_back(candidate); diff --git a/src/Pieces/PiecesFiles.cpp b/src/Pieces/PiecesFiles.cpp index 9966fbd..a457b15 100644 --- a/src/Pieces/PiecesFiles.cpp +++ b/src/Pieces/PiecesFiles.cpp @@ -32,20 +32,10 @@ bool PiecesFiles::savePieces(int polyominoSize) const { nMino.goToSpawnPosition(); } std::sort(nMinos.begin(), nMinos.end()); - - Block pieceblock = firstPieceBlockType(); - for (int i = 0; i < polyominoSize; i++) { - nextPieceBlockType(pieceblock); - } for (const Polyomino& nMino : nMinos) { - // write polyomino length - char lengthByte = nMino.getLength(); - piecesFile.write(&lengthByte, 1); - - // write the type and block of the piece - char infoByte = (nMino.isConvex() << 7) + (nMino.hasHole() << 6) + pieceblock; - nextPieceBlockType(pieceblock); + // write the characteristics of the piece + char infoByte = (nMino.isConvex() << 7) + (nMino.hasHole() << 6) + nMino.getLength(); piecesFile.write(&infoByte, 1); // write the positions of the piece @@ -74,37 +64,41 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector& pieces, std: holelessPieces.clear(); otherPieces.clear(); + Block pieceBlock = firstPieceBlockType(); + for (int i = 0; i < polyominoSize; i++) { + nextPieceBlockType(pieceBlock); + } + char convexMask = 0b1000'0000; char holeMask = 0b0100'0000; - char blockMask = 0b0011'1111; + char lengthMask = 0b0011'1111; char xMask = 0b1111'0000; char yMask = 0b0000'1111; - char lengthByte; + char infoByte; int i = 0; - // read piece length - while (piecesFile.get(lengthByte)) { + while (piecesFile.get(infoByte)) { if (piecesFile.eof()) break; - + // read piece infos - char infoByte; - piecesFile.get(infoByte); bool isConvex = (infoByte & convexMask) >> 7; bool hasHole = (infoByte & holeMask) >> 6; - Block block = Block(infoByte & blockMask); + int length = (infoByte & lengthMask); // read positions - std::set piecepositions; + std::set piecePositions; char positionByte; for (int i = 0; i < polyominoSize; i++) { piecesFile.get(positionByte); int x = (positionByte & xMask) >> 4; int y = positionByte & yMask; - piecepositions.insert(Position{x, y}); + piecePositions.insert(Position{x, y}); } // create piece - Piece readPiece(Polyomino(piecepositions, lengthByte), block); + Piece readPiece(Polyomino(piecePositions, length), pieceBlock); + nextPieceBlockType(pieceBlock); + pieces.push_back(readPiece); if (isConvex) { convexPieces.push_back(i); diff --git a/src/Pieces/Polyomino.cpp b/src/Pieces/Polyomino.cpp index 0d1a0aa..016fd62 100644 --- a/src/Pieces/Polyomino.cpp +++ b/src/Pieces/Polyomino.cpp @@ -27,7 +27,7 @@ Polyomino::Polyomino(const std::set& positions) { for (Position position : positions) { newPositions.insert(Position{position.x - minX, position.y - minY}); } - this->positions = newPositions; + this->positions = std::move(newPositions); // set polyomino length this->length = std::max(maxX - minX + 1, maxY - minY + 1); @@ -52,7 +52,7 @@ void Polyomino::normalize() { for (Position position : this->positions) { newPositions.insert(Position{position.x - minX, position.y - minY}); } - this->positions = newPositions; + this->positions = std::move(newPositions); } void Polyomino::rotateCW() { @@ -60,7 +60,7 @@ void Polyomino::rotateCW() { for (Position position : this->positions) { newPositions.insert(Position{position.y, (length - 1) - (position.x)}); } - this->positions = newPositions; + this->positions = std::move(newPositions); } void Polyomino::rotate180() { @@ -68,7 +68,7 @@ void Polyomino::rotate180() { for (Position position : this->positions) { newPositions.insert(Position{(length - 1) - (position.x), (length - 1) - (position.y)}); } - this->positions = newPositions; + this->positions = std::move(newPositions); } void Polyomino::rotateCCW() { @@ -76,7 +76,7 @@ void Polyomino::rotateCCW() { for (Position position : this->positions) { newPositions.insert(Position{(length - 1) - (position.y), position.x}); } - this->positions = newPositions; + this->positions = std::move(newPositions); } void Polyomino::goToSpawnPosition() { @@ -169,7 +169,7 @@ void Polyomino::goToSpawnPosition() { for (Position position : positions) { newPositions.insert(Position{(position.x - minX) + (verticalEmptyLines / 2), (position.y - minY) + ((horizontalEmptyLines + 1) / 2)}); } - this->positions = newPositions; + this->positions = std::move(newPositions); } void Polyomino::checkForFlattestSide(const std::vector>& linesCompleteness, bool currentFlattestSides[4], int& sideToBeOn, bool checkLeftSide) const { @@ -285,9 +285,9 @@ bool Polyomino::operator<(const Polyomino& other) const { // we check for all positions from left to right and top to bottom, until one has a square that the other doesn't for (int y = this->length - 1; y >= 0; y--) { for (int x = 0; x < this->length; x++) { - bool hasThisposition = this->positions.contains(Position{x, y}); - bool hasOtherposition = other.positions.contains(Position{x, y}); - if (hasThisposition != hasOtherposition) return hasThisposition; + bool hasThisPosition = this->positions.contains(Position{x, y}); + bool hasOtherPosition = other.positions.contains(Position{x, y}); + if (hasThisPosition != hasOtherPosition) return hasThisPosition; } } return false;