Compare commits
5 Commits
13ee43167e
...
f525c00662
| Author | SHA1 | Date | |
|---|---|---|---|
| f525c00662 | |||
| 8088894073 | |||
| d443b25de1 | |||
| 03281a6d70 | |||
| 66c2cf1013 |
@@ -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.
|
||||
|
||||
@@ -19,8 +19,21 @@ Bag::Bag(std::shared_ptr<PiecesList> piecesList) :
|
||||
this->prepareNext();
|
||||
}
|
||||
|
||||
void Bag::jumpToNextBag() {
|
||||
// if the bag is empty switch to the next bag
|
||||
if (this->currentBag.empty()) {
|
||||
std::swap(this->currentBag, this->nextBag);
|
||||
}
|
||||
|
||||
// get the already used pieces back to the current bag
|
||||
for (const std::pair<int, int>& pieceIndex : this->nextBag) {
|
||||
this->currentBag.emplace_back(pieceIndex);
|
||||
}
|
||||
this->nextBag.clear();
|
||||
}
|
||||
|
||||
Piece Bag::lookNext() {
|
||||
return *this->piecesList->getPiece(this->next.first, this->next.second);
|
||||
return this->piecesList->getPiece(this->next);
|
||||
}
|
||||
|
||||
Piece Bag::getNext() {
|
||||
@@ -31,7 +44,7 @@ Piece Bag::getNext() {
|
||||
this->prepareNext();
|
||||
|
||||
// return the next piece
|
||||
return *this->piecesList->getPiece(nextIndex.first, nextIndex.second);
|
||||
return this->piecesList->getPiece(nextIndex);
|
||||
}
|
||||
|
||||
void Bag::prepareNext() {
|
||||
|
||||
@@ -25,6 +25,11 @@ class Bag {
|
||||
*/
|
||||
Bag(std::shared_ptr<PiecesList> piecesList);
|
||||
|
||||
/**
|
||||
* Ignores the remaining pieces in the current bag and startd fresh from a new bag
|
||||
*/
|
||||
void jumpToNextBag();
|
||||
|
||||
/**
|
||||
* Looks at what the next picked piece will be, without removing it from the bag
|
||||
* @return The next piece
|
||||
|
||||
@@ -16,14 +16,10 @@ Board::Board(int width, int height) :
|
||||
this->emptyRow.push_back(NOTHING);
|
||||
}
|
||||
|
||||
// initialize grid
|
||||
this->grid.clear();
|
||||
for (int j = 0; j < height; j++) {
|
||||
this->grid.push_back(this->emptyRow);
|
||||
}
|
||||
this->clearBoard();
|
||||
}
|
||||
|
||||
void Board::addBlock(const Position& position, Block block) {
|
||||
void Board::changeBlock(const Position& position, Block block) {
|
||||
// if the block is out of bounds we discard it
|
||||
if (position.x < 0 || position.x >= this->width || position.y < 0) return;
|
||||
|
||||
@@ -37,6 +33,20 @@ void Board::addBlock(const Position& position, Block block) {
|
||||
this->grid.at(position.y).at(position.x) = block;
|
||||
}
|
||||
|
||||
void Board::insertRow(int height, int holePosition, Block blockType) {
|
||||
std::vector<Block> insertedRow;
|
||||
for (int i = 0; i < this->width; i++) {
|
||||
if (i == holePosition) {
|
||||
insertedRow.push_back(NOTHING);
|
||||
}
|
||||
else {
|
||||
insertedRow.push_back(blockType);
|
||||
}
|
||||
}
|
||||
|
||||
this->grid.insert(this->grid.begin() + height, insertedRow);
|
||||
}
|
||||
|
||||
int Board::clearRows() {
|
||||
// check from top to bottom, so that erasing lines don't screw up the looping
|
||||
int clearedLines = 0;
|
||||
@@ -62,6 +72,13 @@ int Board::clearRows() {
|
||||
return clearedLines;
|
||||
}
|
||||
|
||||
void Board::clearBoard() {
|
||||
this->grid.clear();
|
||||
for (int j = 0; j < height; j++) {
|
||||
this->grid.push_back(this->emptyRow);
|
||||
}
|
||||
}
|
||||
|
||||
Block Board::getBlock(const Position& position) const {
|
||||
if (position.x < 0 || position.x >= this->width || position.y < 0) return OUT_OF_BOUNDS;
|
||||
|
||||
@@ -74,6 +91,10 @@ std::vector<std::vector<Block>> Board::getBlocks() const {
|
||||
return this->grid;
|
||||
}
|
||||
|
||||
int Board::getWidth() const {
|
||||
return this->width;
|
||||
}
|
||||
|
||||
int Board::getGridHeight() const {
|
||||
return this->grid.size();
|
||||
}
|
||||
@@ -82,10 +103,6 @@ int Board::getBaseHeight() const {
|
||||
return this->height;
|
||||
}
|
||||
|
||||
int Board::getWidth() const {
|
||||
return this->width;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Board& board) {
|
||||
for (int y = board.grid.size() - 1; y >= 0; y--) {
|
||||
for (int x = 0; x < board.width; x++) {
|
||||
|
||||
@@ -14,7 +14,7 @@ class Board {
|
||||
std::vector<std::vector<Block>> grid; // the grid, (0,0) is downleft
|
||||
std::vector<Block> emptyRow; // an empty row of blocks
|
||||
int width; // the width of the grid
|
||||
int height; // the base height of the grid, which can extends indefinitely
|
||||
int height; // the base height of the grid, which can extend indefinitely
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -23,9 +23,14 @@ class Board {
|
||||
Board(int width, int height);
|
||||
|
||||
/**
|
||||
* Change the block of the specified block, if the block is out of bounds it is simply ignored
|
||||
* Changes the block at the specified position, if the block is out of bounds it is simply ignored
|
||||
*/
|
||||
void addBlock(const Position& position, Block block);
|
||||
void changeBlock(const Position& position, Block block);
|
||||
|
||||
/**
|
||||
* Inserts a row of the specified block type (unless on the specified column that has a hole), at the specified height
|
||||
*/
|
||||
void insertRow(int height, int holePosition, Block blockType);
|
||||
|
||||
/**
|
||||
* Clears any complete row and moves down the rows on top
|
||||
@@ -34,7 +39,12 @@ class Board {
|
||||
int clearRows();
|
||||
|
||||
/**
|
||||
* @return The block of the block at the specified position
|
||||
* Deletes any block currently on the board
|
||||
*/
|
||||
void clearBoard();
|
||||
|
||||
/**
|
||||
* @return A copy of the block at the specified position
|
||||
*/
|
||||
Block getBlock(const Position& position) const;
|
||||
|
||||
@@ -43,6 +53,11 @@ class Board {
|
||||
*/
|
||||
std::vector<std::vector<Block>> getBlocks() const;
|
||||
|
||||
/**
|
||||
* @return The width of the grid
|
||||
*/
|
||||
int getWidth() const;
|
||||
|
||||
/**
|
||||
* @return The actual height of the grid
|
||||
*/
|
||||
@@ -53,11 +68,6 @@ class Board {
|
||||
*/
|
||||
int getBaseHeight() const;
|
||||
|
||||
/**
|
||||
* @return The width of the grid
|
||||
*/
|
||||
int getWidth() const;
|
||||
|
||||
/**
|
||||
* Stream output operator, adds a 2D grid representing the board
|
||||
* @return A reference to the output stream
|
||||
|
||||
@@ -16,20 +16,33 @@ static const int B2B_SCORE_MULTIPLIER = 2; // by how much havaing B2B on mult
|
||||
static const int B2B_MIN_LINE_NUMBER = 4; // the minimum number of lines needed to be cleared at once to gain B2B (without a spin)
|
||||
|
||||
|
||||
Game::Game(Gamemode gamemode, const Player& controls, int boardWidth, int boardHeight, const std::shared_ptr<PiecesList>& bag) :
|
||||
Game::Game(Gamemode gamemode, const Player& controls, int boardWidth, int boardHeight, const std::shared_ptr<PiecesList>& piecesList) :
|
||||
parameters(gamemode, controls),
|
||||
board(boardWidth, boardHeight, bag, parameters.getNextQueueLength()) {
|
||||
board(boardWidth, boardHeight, piecesList, parameters.getNextQueueLength()) {
|
||||
|
||||
// the game has not yet started
|
||||
this->initialize();
|
||||
}
|
||||
|
||||
void Game::start() {
|
||||
this->started = true;
|
||||
this->lost = this->board.spawnNextPiece();
|
||||
}
|
||||
|
||||
void Game::reset() {
|
||||
this->initialize();
|
||||
|
||||
this->parameters.reset();
|
||||
this->board.reset();
|
||||
}
|
||||
|
||||
void Game::initialize() {
|
||||
this->started = false;
|
||||
this->lost = false;
|
||||
|
||||
// initialize stats
|
||||
this->score = 0;
|
||||
this->framesPassed = 0;
|
||||
this->B2BChain = 0;
|
||||
|
||||
// nothing happened yet
|
||||
this->heldActions.clear();
|
||||
this->initialActions.clear();
|
||||
this->heldDAS = 0;
|
||||
@@ -40,11 +53,6 @@ Game::Game(Gamemode gamemode, const Player& controls, int boardWidth, int boardH
|
||||
this->totalForcedLockDelay = 0;
|
||||
}
|
||||
|
||||
void Game::start() {
|
||||
this->started = true;
|
||||
this->lost = this->board.spawnNextPiece();
|
||||
}
|
||||
|
||||
void Game::nextFrame(const std::set<Action>& playerActions) {
|
||||
if (this->lost || this->hasWon()) return;
|
||||
|
||||
@@ -251,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<Piece> Game::getNextPieces() {
|
||||
std::vector<Piece> Game::getNextPieces() const {
|
||||
return this->board.getNextPieces();
|
||||
}
|
||||
|
||||
@@ -33,13 +33,26 @@ class Game {
|
||||
/**
|
||||
* Initialize the parameters and creates a new board
|
||||
*/
|
||||
Game(Gamemode gamemode, const Player& controls, int boardWidth, int boardHeight, const std::shared_ptr<PiecesList>& bag);
|
||||
Game(Gamemode gamemode, const Player& controls, int boardWidth, int boardHeight, const std::shared_ptr<PiecesList>& piecesList);
|
||||
|
||||
/**
|
||||
* Starts the game
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Resets the game
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initializes the game
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Advances to the next frame while excecuting the actions taken by the player,
|
||||
* this is where the main game logic takes place
|
||||
@@ -48,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);
|
||||
|
||||
@@ -61,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<Piece> getNextPieces();
|
||||
std::vector<Piece> getNextPieces() const;
|
||||
};
|
||||
|
||||
@@ -8,17 +8,33 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
GameBoard::GameBoard(int boardWidth, int boardHeight, const std::shared_ptr<PiecesList>& pieceList, int nextQueueLength) :
|
||||
GameBoard::GameBoard(int boardWidth, int boardHeight, const std::shared_ptr<PiecesList>& piecesList, int nextQueueLength) :
|
||||
board(boardWidth, boardHeight),
|
||||
generator(pieceList),
|
||||
generator(piecesList),
|
||||
nextQueueLength(nextQueueLength) {
|
||||
|
||||
this->initialize();
|
||||
}
|
||||
|
||||
void GameBoard::reset() {
|
||||
this->board.clearBoard();
|
||||
this->generator.jumpToNextBag();
|
||||
|
||||
this->initialize();
|
||||
}
|
||||
|
||||
void GameBoard::initialize() {
|
||||
this->nextQueue.clear();
|
||||
for (int i = 0; i < nextQueueLength; i++) {
|
||||
this->nextQueue.push_back(this->generator.getNext());
|
||||
}
|
||||
|
||||
this->activePiece = nullptr;
|
||||
this->heldPiece = nullptr;
|
||||
this->isLastMoveKick = false;
|
||||
}
|
||||
|
||||
bool GameBoard::moveLeft() {
|
||||
@@ -215,12 +231,23 @@ LineClear GameBoard::lockPiece() {
|
||||
&& this->isActivePieceInWall(Position{-1, 0}) && this->isActivePieceInWall(Position{0, -1}));
|
||||
|
||||
for (Position position : this->activePiece->getPositions()) {
|
||||
this->board.addBlock(position + this->activePiecePosition, this->activePiece->getBlockType());
|
||||
this->board.changeBlock(position + this->activePiecePosition, this->activePiece->getBlockType());
|
||||
}
|
||||
|
||||
return LineClear{this->board.clearRows(), isLockedInPlace, (!isLockedInPlace) && this->isLastMoveKick};
|
||||
}
|
||||
|
||||
void GameBoard::addGarbageRows(int number) {
|
||||
int holePosition = std::rand() % this->board.getWidth();
|
||||
|
||||
for (int i = 0; i < number; i++) {
|
||||
this->board.insertRow(0, holePosition, GARBAGE);
|
||||
if (this->touchesGround()) {
|
||||
this->activePiecePosition.y += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Board GameBoard::getBoard() const {
|
||||
return this->board;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,20 @@ class GameBoard {
|
||||
/**
|
||||
* Creates a new board, generator, and next queue
|
||||
*/
|
||||
GameBoard(int boardWidth, int boardHeight, const std::shared_ptr<PiecesList>& bag, int nextQueueLength);
|
||||
GameBoard(int boardWidth, int boardHeight, const std::shared_ptr<PiecesList>& 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
|
||||
@@ -85,6 +97,11 @@ class GameBoard {
|
||||
*/
|
||||
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 A copy of the board
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,10 @@ GameParameters::GameParameters(Gamemode gamemode, const Player& controls) :
|
||||
gamemode(gamemode),
|
||||
controls(controls) {
|
||||
|
||||
this->reset();
|
||||
}
|
||||
|
||||
void GameParameters::reset() {
|
||||
// initialize lines and level
|
||||
this->clearedLines = 0;
|
||||
switch (this->gamemode) {
|
||||
@@ -48,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;
|
||||
@@ -194,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;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@ class GameParameters {
|
||||
*/
|
||||
GameParameters(Gamemode gamemode, const Player& controls);
|
||||
|
||||
/**
|
||||
* Resets all stats and parameters
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Counts the newly cleared lines and update level and stats if needed
|
||||
*/
|
||||
@@ -40,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:
|
||||
/**
|
||||
@@ -52,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;
|
||||
};
|
||||
|
||||
46
src/Core/Menu.cpp
Normal file
46
src/Core/Menu.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "Menu.h"
|
||||
|
||||
#include "PiecesList.h"
|
||||
#include "Player.h"
|
||||
#include "Game.h"
|
||||
|
||||
|
||||
Menu::Menu() {
|
||||
// default board size
|
||||
this->boardHeight = 20;
|
||||
this->boardWidth = 10;
|
||||
}
|
||||
|
||||
Game Menu::startGame(Gamemode gamemode) const {
|
||||
return Game(gamemode, this->playerControls, this->boardWidth, this->boardHeight, std::make_shared<PiecesList>(this->piecesList));
|
||||
}
|
||||
|
||||
bool Menu::setBoardWidth(int width) {
|
||||
if (width < 1) return false;
|
||||
|
||||
this->boardWidth = width;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Menu::setBoardHeight(int height) {
|
||||
if (height < 1) return false;
|
||||
|
||||
this->boardHeight = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Menu::getBoardWidth() const {
|
||||
return this->boardWidth;
|
||||
}
|
||||
|
||||
int Menu::getBoardHeight() const {
|
||||
return this->boardHeight;
|
||||
}
|
||||
|
||||
Player& Menu::getPlayerControls() {
|
||||
return this->playerControls;
|
||||
}
|
||||
|
||||
PiecesList& Menu::getPiecesList() {
|
||||
return this->piecesList;
|
||||
}
|
||||
63
src/Core/Menu.h
Normal file
63
src/Core/Menu.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include "PiecesList.h"
|
||||
#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
|
||||
*/
|
||||
class Menu {
|
||||
private:
|
||||
PiecesList piecesList; // the list of pieces in the game
|
||||
Player playerControls; // the controls of the player
|
||||
int boardHeight; // the height of the board for the next game
|
||||
int boardWidth; // the width of the board for the next game
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initializes the board size and player controls to their default values
|
||||
*/
|
||||
Menu();
|
||||
|
||||
/**
|
||||
* Starts a new game with the current settings
|
||||
* @return The game that has been created
|
||||
*/
|
||||
Game startGame(Gamemode gamemode) const;
|
||||
|
||||
/**
|
||||
* Sets the width of the board, which must be greater than 0
|
||||
* @return If the width has been changed
|
||||
*/
|
||||
bool setBoardWidth(int width);
|
||||
|
||||
/**
|
||||
* Sets the height of the board, which must be greater than 0
|
||||
* @return If the height has been changed
|
||||
*/
|
||||
bool setBoardHeight(int height);
|
||||
|
||||
/**
|
||||
* @return The width of the board
|
||||
*/
|
||||
int getBoardWidth() const;
|
||||
|
||||
/**
|
||||
* @return The height of the board
|
||||
*/
|
||||
int getBoardHeight() const;
|
||||
|
||||
/**
|
||||
* @return A reference to the player's controls
|
||||
*/
|
||||
Player& getPlayerControls();
|
||||
|
||||
/**
|
||||
* @return A reference to the pieces list
|
||||
*/
|
||||
PiecesList& getPiecesList();
|
||||
};
|
||||
@@ -5,58 +5,109 @@
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
|
||||
PiecesList::PiecesList() {
|
||||
this->maximumLoadedSize = 0;
|
||||
this->loadedPieces.clear();
|
||||
this->loadedPieces.push_back(std::vector<Piece>());
|
||||
this->highestLoadedSize = 0;
|
||||
this->selectedPieces.clear();
|
||||
|
||||
// we need to have something at index 0 even if there is no pieces of size 0
|
||||
this->loadedPieces.clear();
|
||||
this->convexPieces.clear();
|
||||
this->holelessPieces.clear();
|
||||
this->otherPieces.clear();
|
||||
this->pushBackEmptyVectors();
|
||||
|
||||
// we always prepare vectors of the next size to be generated
|
||||
this->pushBackEmptyVectors();
|
||||
}
|
||||
|
||||
bool PiecesList::loadPieces(int size) {
|
||||
if (size < 1) return false;
|
||||
|
||||
PiecesFiles piecesFiles;
|
||||
std::vector<int> convexPieces;
|
||||
std::vector<int> holelessPieces;
|
||||
std::vector<int> otherPieces;
|
||||
for (int i = this->highestLoadedSize + 1; i <= size; i++) {
|
||||
|
||||
for (int i = this->maximumLoadedSize + 1; i <= size; i++) {
|
||||
std::vector<Piece> pieces;
|
||||
this->loadedPieces.push_back(pieces);
|
||||
|
||||
if (!piecesFiles.loadPieces(i, this->loadedPieces.at(i), convexPieces, holelessPieces, otherPieces)) {
|
||||
if (!piecesFiles.loadPieces(i, this->loadedPieces.at(i), this->convexPieces.at(i), this->holelessPieces.at(i), this->otherPieces.at(i))) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
this->maximumLoadedSize++;
|
||||
this->highestLoadedSize++;
|
||||
this->pushBackEmptyVectors();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PiecesList::selectPieces(int size, int number) {
|
||||
if (size < 1 || size > this->maximumLoadedSize || number >= this->loadedPieces.at(size).size()) return false;
|
||||
bool PiecesList::selectPiece(int size, int number) {
|
||||
if (size < 1 || size > this->highestLoadedSize || number >= this->loadedPieces.at(size).size()) return false;
|
||||
|
||||
this->selectedPieces.push_back(std::pair<int, int>(size, number));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, int>> PiecesList::getSelectedPieces() {
|
||||
return this->selectedPieces;
|
||||
bool PiecesList::selectAllPieces(int size) {
|
||||
if (size < 1 || size > this->highestLoadedSize) return false;
|
||||
|
||||
for (int i = 0; i < this->loadedPieces.at(size).size(); i++) {
|
||||
this->selectedPieces.push_back(std::pair<int, int>(size, i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int PiecesList::getNumberOfPiecesOfOneSize(int size) {
|
||||
if (size < 1 || size > this->maximumLoadedSize) return 0;
|
||||
bool PiecesList::selectConvexPieces(int size) {
|
||||
if (size < 1 || size > this->highestLoadedSize) return false;
|
||||
|
||||
for (int index : this->convexPieces.at(size)) {
|
||||
this->selectedPieces.push_back(std::pair<int, int>(size, index));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PiecesList::selectHolelessPieces(int size) {
|
||||
if (size < 1 || size > this->highestLoadedSize) return false;
|
||||
|
||||
for (int index : this->holelessPieces.at(size)) {
|
||||
this->selectedPieces.push_back(std::pair<int, int>(size, index));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PiecesList::selectOtherPieces(int size) {
|
||||
if (size < 1 || size > this->highestLoadedSize) return false;
|
||||
|
||||
for (int index : this->otherPieces.at(size)) {
|
||||
this->selectedPieces.push_back(std::pair<int, int>(size, index));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PiecesList::unselectAll() {
|
||||
this->selectedPieces.clear();
|
||||
}
|
||||
|
||||
int PiecesList::getHighestLoadedSize() const {
|
||||
return this->highestLoadedSize;
|
||||
}
|
||||
|
||||
int PiecesList::getNumberOfPieces(int size) const {
|
||||
if (size < 1 || size > this->highestLoadedSize) return 0;
|
||||
|
||||
return this->loadedPieces.at(size).size();
|
||||
}
|
||||
|
||||
std::shared_ptr<Piece> PiecesList::getPiece(int size, int number) {
|
||||
if (size < 1 || size > this->maximumLoadedSize || number >= this->loadedPieces.at(size).size()) return nullptr;
|
||||
|
||||
return std::make_shared<Piece>(this->loadedPieces.at(size).at(number));
|
||||
std::vector<std::pair<int, int>> PiecesList::getSelectedPieces() const {
|
||||
return this->selectedPieces;
|
||||
}
|
||||
|
||||
Piece PiecesList::getPiece(std::pair<int, int> pieceIndex) const {
|
||||
return this->loadedPieces.at(pieceIndex.first).at(pieceIndex.second);
|
||||
}
|
||||
|
||||
void PiecesList::pushBackEmptyVectors() {
|
||||
this->loadedPieces.push_back(std::vector<Piece>());
|
||||
this->convexPieces.push_back(std::vector<int>());
|
||||
this->holelessPieces.push_back(std::vector<int>());
|
||||
this->otherPieces.push_back(std::vector<int>());
|
||||
}
|
||||
|
||||
@@ -4,25 +4,91 @@
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
|
||||
/**
|
||||
* A container for all loaded pieces to prevent loading and copying them multiple times,
|
||||
* also allows for the player to select a list of pieces to be used in a game
|
||||
*/
|
||||
class PiecesList {
|
||||
private:
|
||||
int maximumLoadedSize;
|
||||
std::vector<std::vector<Piece>> loadedPieces;
|
||||
std::vector<std::pair<int, int>> selectedPieces;
|
||||
|
||||
int highestLoadedSize; // the highest size of pieces currently loaded
|
||||
std::vector<std::vector<Piece>> loadedPieces; // every loaded pieces by size
|
||||
std::vector<std::vector<int>> convexPieces; // the list of convex loaded pieces by size
|
||||
std::vector<std::vector<int>> holelessPieces; // the list of holeless loaded pieces by size
|
||||
std::vector<std::vector<int>> otherPieces; // the list of other loaded pieces by size
|
||||
std::vector<std::pair<int, int>> selectedPieces; // the list of all currently selected pieces
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initializes a list of pieces up to size 0 (so no pieces)
|
||||
*/
|
||||
PiecesList();
|
||||
|
||||
/**
|
||||
* Makes the list load all pieces of the specified size
|
||||
* @return If it sucessfully loaded the pieces
|
||||
*/
|
||||
bool loadPieces(int size);
|
||||
|
||||
bool selectPieces(int size, int numbers);
|
||||
/**
|
||||
* Selects the specified piece
|
||||
* @return If the piece could be selected
|
||||
*/
|
||||
bool selectPiece(int size, int number);
|
||||
|
||||
std::vector<std::pair<int, int>> getSelectedPieces();
|
||||
/**
|
||||
* Selects all pieces of the specified size
|
||||
* @return If the pieces could be selected
|
||||
*/
|
||||
bool selectAllPieces(int size);
|
||||
|
||||
int getNumberOfPiecesOfOneSize(int size);
|
||||
/**
|
||||
* Selects all convex pieces of the specified size
|
||||
* @return If the pieces could be selected
|
||||
*/
|
||||
bool selectConvexPieces(int size);
|
||||
|
||||
std::shared_ptr<Piece> getPiece(int size, int number);
|
||||
/**
|
||||
* Selects all holeless pieces of the specified size
|
||||
* @return If the pieces could be selected
|
||||
*/
|
||||
bool selectHolelessPieces(int size);
|
||||
|
||||
/**
|
||||
* Selects all other pieces of the specified size
|
||||
* @return If the pieces could be selected
|
||||
*/
|
||||
bool selectOtherPieces(int size);
|
||||
|
||||
/**
|
||||
* Unselects all previously selected pieces
|
||||
*/
|
||||
void unselectAll();
|
||||
|
||||
/**
|
||||
* @return The highest loaded size of pieces
|
||||
*/
|
||||
int getHighestLoadedSize() const;
|
||||
|
||||
/**
|
||||
* @return The number of pieces of the specified size
|
||||
*/
|
||||
int getNumberOfPieces(int size) const;
|
||||
|
||||
/**
|
||||
* @return The indexes of all selected pieces
|
||||
*/
|
||||
std::vector<std::pair<int, int>> getSelectedPieces() const;
|
||||
|
||||
/**
|
||||
* @return The piece corresponding to the specified index
|
||||
*/
|
||||
Piece getPiece(std::pair<int, int> pieceIndex) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Adds empty vectors at the end of every pieces list
|
||||
*/
|
||||
void pushBackEmptyVectors();
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
#include "../Pieces/PiecesFiles.h"
|
||||
#include "Menu.h"
|
||||
#include "../Pieces/Generator.h"
|
||||
#include "GameBoard.h"
|
||||
#include "PiecesList.h"
|
||||
#include "../Pieces/PiecesFiles.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
void testGeneratorForAllSizes(int amount);
|
||||
@@ -15,27 +10,19 @@ 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);
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::srand(std::time(NULL));
|
||||
|
||||
int sizeSelected = 3;
|
||||
|
||||
PiecesList pli;
|
||||
std::shared_ptr<PiecesList> pl = std::make_shared<PiecesList>(pli);
|
||||
pl->loadPieces(sizeSelected);
|
||||
for (int i = 0; i < pl->getNumberOfPiecesOfOneSize(sizeSelected); i++) {
|
||||
pl->selectPieces(sizeSelected, i);
|
||||
}
|
||||
|
||||
GameBoard gb(10, 4, pl, 1);
|
||||
|
||||
for (int i = 0; i < pl->getNumberOfPiecesOfOneSize(sizeSelected) * 3; i++) {
|
||||
gb.spawnNextPiece();
|
||||
std::cout << gb << std::endl;
|
||||
}
|
||||
Menu menu;
|
||||
menu.getPiecesList().loadPieces(4);
|
||||
menu.getPiecesList().selectAllPieces(4);
|
||||
Game game = menu.startGame(SPRINT);
|
||||
game.start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -122,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);
|
||||
@@ -133,12 +120,12 @@ void generateFilesForAllSizes(int amount) {
|
||||
std::cout << "Generated pieces files for size " << i << " in " << ms_double.count() << "ms" << std::endl;
|
||||
}
|
||||
|
||||
std::vector<Piece> pieces;
|
||||
std::vector<int> convexPieces;
|
||||
std::vector<int> holelessPieces;
|
||||
std::vector<int> otherPieces;
|
||||
for (int i = 1; i <= amount; i++) {
|
||||
auto t1 = high_resolution_clock::now();
|
||||
std::vector<Piece> pieces;
|
||||
std::vector<int> convexPieces;
|
||||
std::vector<int> holelessPieces;
|
||||
std::vector<int> otherPieces;
|
||||
piecesFiles.loadPieces(i, pieces, convexPieces, holelessPieces, otherPieces);
|
||||
auto t2 = high_resolution_clock::now();
|
||||
|
||||
@@ -147,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<double, std::milli> 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<Piece> pieces;
|
||||
std::vector<int> convexPieces;
|
||||
std::vector<int> holelessPieces;
|
||||
std::vector<int> 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<double, std::milli> 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++) {
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
Generator::Generator() {
|
||||
}
|
||||
|
||||
std::vector<Polyomino> Generator::generatePolyominos(unsigned int polyominoSize) {
|
||||
std::vector<Polyomino> Generator::generatePolyominos(int polyominoSize) {
|
||||
this->validPolyominos.clear();
|
||||
this->currentTestedShape.clear();
|
||||
|
||||
// no polyomino of size 0
|
||||
if (polyominoSize == 0) return this->validPolyominos;
|
||||
// a polyomino has at least 1 square
|
||||
if (polyominoSize < 1) return this->validPolyominos;
|
||||
|
||||
// start generating from the monomino
|
||||
this->currentTestedShape.insert(Position{0, 0});
|
||||
@@ -26,13 +26,14 @@ std::vector<Polyomino> Generator::generatePolyominos(unsigned int polyominoSize)
|
||||
return this->validPolyominos;
|
||||
}
|
||||
|
||||
void Generator::generate(unsigned int polyominoSize, int lastAddedPositionNumber, int nextAvaibleNumber, std::map<Position, int> candidatePositions) {
|
||||
void Generator::generate(int polyominoSize, int lastAddedPositionNumber, int nextAvaibleNumber, std::map<Position, int> candidatePositions) {
|
||||
// recursion stop
|
||||
if (polyominoSize == this->currentTestedShape.size()) {
|
||||
Polyomino candidate(this->currentTestedShape);
|
||||
|
||||
// we sort the rotations of the polyominos
|
||||
std::vector<Polyomino> candidateRotations;
|
||||
candidateRotations.reserve(4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
candidate.normalize();
|
||||
candidateRotations.push_back(candidate);
|
||||
|
||||
@@ -25,13 +25,13 @@ class Generator {
|
||||
* Generates the list of all one-sided polyominos of the specified size
|
||||
* @return The list of polyominos
|
||||
*/
|
||||
std::vector<Polyomino> generatePolyominos(unsigned int polyominoSize);
|
||||
std::vector<Polyomino> generatePolyominos(int polyominoSize);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Generates all one-sided polyominos of the specified size using the current tested shape
|
||||
*/
|
||||
void generate(unsigned int polyominoSize, int lastAddedPositionNumber, int nextAvaibleNumber, std::map<Position, int> candidatePositions);
|
||||
void generate(int polyominoSize, int lastAddedPositionNumber, int nextAvaibleNumber, std::map<Position, int> candidatePositions);
|
||||
|
||||
/**
|
||||
* Checks wheter a candidate position can be added to the current tested shape
|
||||
|
||||
@@ -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<Piece>& 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<Position> piecepositions;
|
||||
std::set<Position> 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);
|
||||
|
||||
@@ -27,7 +27,7 @@ Polyomino::Polyomino(const std::set<Position>& 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<std::vector<int>>& 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;
|
||||
|
||||
Reference in New Issue
Block a user