Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
de63cd22b6
|
|||
| 07ba9619ed | |||
| 4095103843 | |||
| ecc035c972 | |||
| dd6da58642 | |||
| a3ef52c7a1 | |||
| 72e9f420ab | |||
| 46b9b8dd65 | |||
| d5b51213c8 | |||
| 161c9425ae | |||
| 561b6d76b8 | |||
| b276213794 | |||
| 7b5801e630 | |||
| e676cd19f6 | |||
| 8342bf3969 | |||
| 34d781fcfe | |||
| b17a40fda5 |
77
README.md
77
README.md
@@ -2,12 +2,18 @@
|
|||||||
|
|
||||||
Modern stacker game with every polyominoes from size 1 to 15, made in C++ with [SFML 3](https://www.sfml-dev.org/)!
|
Modern stacker game with every polyominoes from size 1 to 15, made in C++ with [SFML 3](https://www.sfml-dev.org/)!
|
||||||
|
|
||||||
|
- [Download](#download)
|
||||||
|
- [How to play](#how-to-play)
|
||||||
|
- [Features](#features)
|
||||||
|
- [Manual build](#manual-build)
|
||||||
|
- [Benchmarks](#benchmarks)
|
||||||
|
- [Credits](#credits)
|
||||||
|
|
||||||
## Download
|
## Download
|
||||||
|
|
||||||
// TODO when the game is finished //
|
You can download the latest release [here](https://git.ale-pri.com/TetrisNerd/jminos/releases)!
|
||||||
|
This game has been tested on Windows 11 and Linux, and releases are provided for theses two systems.
|
||||||
This game has been tested on and built for Windows 11 and WSL2 Ubuntu.
|
If your OS isn't compatible, you can try [manually building the project](#manual-build).
|
||||||
If your OS isn't compactible with either of theses two, you can try [manually building the project](#manual-build).
|
|
||||||
|
|
||||||
## How to play
|
## How to play
|
||||||
|
|
||||||
@@ -44,22 +50,28 @@ You will find more infos about the Rotation System, the scoring system, or the d
|
|||||||
### Screenshots
|
### Screenshots
|
||||||
|
|
||||||
Pentedecamino jumpscare
|
Pentedecamino jumpscare
|
||||||

|
|
||||||
|

|
||||||
|
|
||||||
Pieces select screen
|
Pieces select screen
|
||||||

|
|
||||||
|

|
||||||
|
|
||||||
AutoRS demonstration
|
AutoRS demonstration
|
||||||

|
|
||||||
|

|
||||||
|
|
||||||
0° spins demonstration
|
0° spins demonstration
|
||||||

|
|
||||||
|

|
||||||
|
|
||||||
## Manual build
|
## Manual build
|
||||||
|
|
||||||
This project uses xmake for compiling, xmake is cross-platform and works in most OS, xmake also automatically install supported librairies.
|
This project uses xmake for compiling, xmake is cross-platform and works in most OS, xmake also automatically install supported librairies.
|
||||||
To be able to build this project, you need to [have xmake installed](https://xmake.io) and have a compiler with C++20 compatibility.
|
To be able to build this project, you need to [have xmake installed](https://xmake.io) and have a compiler with C++20 compatibility.
|
||||||
|
|
||||||
|
If you want to contribute or are simply curious, you can check the [wiki](https://git.ale-pri.com/TetrisNerd/jminos/wiki)!
|
||||||
|
|
||||||
### Build the project
|
### Build the project
|
||||||
|
|
||||||
``cd jminos``
|
``cd jminos``
|
||||||
@@ -69,6 +81,9 @@ To be able to build this project, you need to [have xmake installed](https://xma
|
|||||||
If you need to change the toolchain (for example using gcc):
|
If you need to change the toolchain (for example using gcc):
|
||||||
``xmake f --toolchain=gcc``
|
``xmake f --toolchain=gcc``
|
||||||
|
|
||||||
|
If you want to build for another platform (for example with mingw):
|
||||||
|
``xmake f -p mingw``
|
||||||
|
|
||||||
### Run the project
|
### Run the project
|
||||||
|
|
||||||
``xmake run``
|
``xmake run``
|
||||||
@@ -79,13 +94,20 @@ To switch between debug and release mode:
|
|||||||
``xmake f -m debug``
|
``xmake f -m debug``
|
||||||
``xmake f -m release``
|
``xmake f -m release``
|
||||||
|
|
||||||
If for some reasons you wanna run the command line version (not updated):
|
If for some reasons you wanna run the command line version:
|
||||||
``xmake build text``
|
``xmake build text``
|
||||||
``xmake run text``
|
``xmake run text``
|
||||||
|
The command line version is **not** updated.
|
||||||
|
|
||||||
### Package the project
|
### Package the project
|
||||||
|
|
||||||
// TODO when the game is finished //
|
To package the executable manually properly, follow theses steps:
|
||||||
|
|
||||||
|
1. Clone the project into a new folder.
|
||||||
|
2. If you already have all 15 pieces files, copy them over to the ``data/pieces`` folder, else you will be generating them at the next step.
|
||||||
|
3. Go into release mode (``xmake f -m release``) and run the project once (``xmake`` and ``xmake run``). This is to generate the default config files, close the game immediately after it started.
|
||||||
|
4. Make a new folder named ``jminos`` and copy the executable (should be located somewhere like ``build/linux/x86_64/release/graph``) as well as the ``data/pieces`` and ``data/config`` folders.
|
||||||
|
5. Zip the newly created ``jminos`` folder into a file named ``jminos_{platform}``.
|
||||||
|
|
||||||
## Benchmarks
|
## Benchmarks
|
||||||
|
|
||||||
@@ -93,24 +115,24 @@ If for some reasons you wanna run the command line version (not updated):
|
|||||||
|
|
||||||
| n | Number | Generation | File storing | File retrieving | File size |
|
| n | Number | Generation | File storing | File retrieving | File size |
|
||||||
| -: | -: | :-: | :-: | :-: | -: |
|
| -: | -: | :-: | :-: | :-: | -: |
|
||||||
| 1 | 1 | 0s 0.005622ms | 0s 0.750955ms | 0s 0.014016ms | 2 bytes |
|
| 1 | 1 | 0s 0.005471ms | 0s 0.14436ms | 0s 0.022223ms | 3 bytes |
|
||||||
| 2 | 1 | 0s 0.005758ms | 0s 0.181323ms | 0s 0.012256ms | 3 bytes |
|
| 2 | 1 | 0s 0.006979ms | 0s 0.036624ms | 0s 0.011424ms | 4 bytes |
|
||||||
| 3 | 2 | 0s 0.017525ms | 0s 0.054497ms | 0s 0.006431ms | 8 bytes |
|
| 3 | 2 | 0s 0.018718ms | 0s 0.035885ms | 0s 0.013246ms | 9 bytes |
|
||||||
| 4 | 7 | 0s 0.050554ms | 0s 0.067617ms | 0s 0.010984ms | 35 bytes |
|
| 4 | 7 | 0s 0.060544ms | 0s 0.056277ms | 0s 0.019395ms | 36 bytes |
|
||||||
| 5 | 18 | 0s 0.191971ms | 0s 0.109905ms | 0s 0.021234ms | 108 bytes |
|
| 5 | 18 | 0s 0.220348ms | 0s 0.166593ms | 0s 0.036526ms | 76 bytes |
|
||||||
| 6 | 60 | 0s 0.651757ms | 0s 0.327465ms | 0s 0.04558ms | 420 bytes |
|
| 6 | 60 | 0s 0.773924ms | 0s 0.283423ms | 0s 0.063492ms | 186 bytes |
|
||||||
| 7 | 196 | 0s 3.38847ms | 0s 1.94434ms | 0s 0.258777ms | 1568 bytes |
|
| 7 | 196 | 0s 3.00331ms | 0s 0.827344ms | 0s 0.163653ms | 546 bytes |
|
||||||
| 8 | 704 | 0s 22.7411ms | 0s 10.0103ms | 0s 1.34813ms | 6336 bytes |
|
| 8 | 704 | 0s 13.142ms | 0s 3.68255ms | 0s 0.630044ms | 1 898 bytes |
|
||||||
| 9 | 2500 | 0s 66.2949ms | 0s 20.6137ms | 0s 2.56374ms | 25000 bytes |
|
| 9 | 2500 | 0s 50.9272ms | 0s 16.1929ms | 0s 2.35157ms | 6889 bytes |
|
||||||
| 10 | 9189 | 0s 194.764ms | 0s 84.5884ms | 0s 9.64467ms | 101079 bytes |
|
| 10 | 9189 | 0s 204.031ms | 0s 87.1819ms | 0s 10.5841ms | 25302 bytes |
|
||||||
| 11 | 33896 | 0s 759.182ms | 0s 378.494ms | 0s 44.1424ms | 406752 bytes |
|
| 11 | 33896 | 0s 832.82ms | 0s 412.466ms | 0s 57.6399ms | 93711 bytes |
|
||||||
| 12 | 126759 | 2s 709.277ms | 1s 530.34ms | 0s 155ms | 1647867 bytes |
|
| 12 | 126759 | 3s 425.907ms | 1s 982.715ms | 0s 226.816ms | 350325 bytes |
|
||||||
| 13 | 476270 | 10s 668.308ms | 7s 395.512ms | 0s 765.601ms | 6667780 bytes |
|
| 13 | 476270 | 14s 570.595ms | 9s 945.511ms | 0s 972.036ms | 1327156 bytes |
|
||||||
| 14 | 1802312 | 45s 606.597ms | 32s 28.7977ms | 2s 919.653ms | 27034680 bytes |
|
| 14 | 1802312 | 56s 394.426ms | 41s 675.672ms | 4s 79.0436ms | 5035148 bytes |
|
||||||
| 15 | ~6M | ~5mn | ~5mn | ~10s | ~100 MB |
|
| 15 | 6849777 | 258s 219.666ms | 223s 386.329ms | 16s 483.426ms | 19392417 bytes |
|
||||||
|
|
||||||
_File storing includes type checking and sorting all polyominoes before writing them to the file._
|
_File storing includes type checking and sorting all polyominoes before writing them to the file._
|
||||||
If you want to know more details about the generation and storage of polyominoes, [check the documentation](/doc/)!
|
The files are compressed, they used to be about 5x as large.
|
||||||
|
|
||||||
Run it yourself by typing:
|
Run it yourself by typing:
|
||||||
``xmake f -m release``
|
``xmake f -m release``
|
||||||
@@ -124,3 +146,6 @@ Font used: [Press Start](https://www.zone38.net/font/#pressstart).
|
|||||||
|
|
||||||
Inspired by other modern stacker games such as Techmino, jstris, tetr.io, etc.
|
Inspired by other modern stacker games such as Techmino, jstris, tetr.io, etc.
|
||||||
This game isn't affiliated with any of them.
|
This game isn't affiliated with any of them.
|
||||||
|
|
||||||
|
Special thanks to my friend [Simon](https://git.ale-pri.com/Persson-dev) who did most of the outside stuff (github actions, files compression, asset manager, xmake).
|
||||||
|
All the code in src/Common/, src/Utils/ and xmake/ comes from him.
|
||||||
|
|||||||
BIN
doc/diagrams/class_diagramm_graphicalUI.png
Normal file
BIN
doc/diagrams/class_diagramm_graphicalUI.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
BIN
doc/diagrams/package_diagramm.png
Normal file
BIN
doc/diagrams/package_diagramm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
## Pieces
|
## Pieces
|
||||||
|
|
||||||
If you don't know what a polyomino is, check [this other file](Pieces_representation.md#what-are-polyominoes).
|
_Note: the current algorithm has been adapted to use file compression. There is currently no documentation on how the compression work, but you can check the code in the [src/Common](https://git.ale-pri.com/TetrisNerd/jminos/src/branch/main/src/Common) folder._
|
||||||
|
|
||||||
Generating polyominoes 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.
|
Generating polyominoes 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 (except for the block type which is trivially computed).
|
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 solved internally, but will be calculated before storage as to not need extra calculcations upon load (except for the block type which is trivially computed).
|
||||||
|
|
||||||
Pieces are stored in binary files. Each file simply contains every polyomino of one size, one after the other. Since each file contains all polyominoes 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.
|
Pieces are stored in binary files. Each file simply contains every polyomino of one size, one after the other. Since each file contains all polyominoes 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.
|
||||||
|
|
||||||
@@ -55,5 +55,4 @@ The settings file has the following format:
|
|||||||
- For every single piece, use 1 byte for (the size + encoding that it is a single piece),
|
- For every single piece, use 1 byte for (the size + encoding that it is a single piece),
|
||||||
and 3 bytes to store the number of the piece (allows number up to 16M, size 15 has 6M pieces).
|
and 3 bytes to store the number of the piece (allows number up to 16M, size 15 has 6M pieces).
|
||||||
|
|
||||||
The current file format version is 11.
|
When starting the game, it will verify if the current settings file is in the latest format, if it is not it will be regenerated with default values.
|
||||||
If the file starts with a number lower than that, it will be regenerated upon launching the game.
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Game logic
|
# Game logic
|
||||||
|
|
||||||
This section will detail how the player's action are interpreted into the game.
|
This section will detail how the player's action are interpreted into the game.
|
||||||
We will only talk about pieces and not polyominoes. In this project, pieces are an abstraction of a polyomino. Though if you want to know more the polyominoes in this project, check [this other file](Pieces_representation.md).
|
We will only talk about pieces and not polyominoes. In this project, pieces are an abstraction of a polyomino.
|
||||||
|
|
||||||
## Order of operations
|
## Order of operations
|
||||||
|
|
||||||
|
|||||||
102
src/Benchmark/main.cpp
Normal file
102
src/Benchmark/main.cpp
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#include "../Pieces/Generator.h"
|
||||||
|
#include "../Pieces/PiecesFiles.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
static const int BENCHMARK_PIECES_SIZE = 15;
|
||||||
|
|
||||||
|
void benchmarking(int min_size, int max_size);
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
std::srand(std::time(NULL));
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << "IMPORTANT: You are currently in debug mode, debug mode has lowest optimization settings and thus yields worse benchmarking results, to switch to release mode, type 'xmake f -m debug'." << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
benchmarking(1, BENCHMARK_PIECES_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void benchmarking(int min_size, int max_size) {
|
||||||
|
using std::chrono::high_resolution_clock;
|
||||||
|
using std::chrono::duration_cast;
|
||||||
|
using std::chrono::duration;
|
||||||
|
using std::chrono::milliseconds;
|
||||||
|
|
||||||
|
std::cout << "| n | Number | Generation | File storing | File retrieving | File size |" << std::endl;
|
||||||
|
std::cout << "| -: | -: | :-: | :-: | :-: | -: |" << std::endl;
|
||||||
|
|
||||||
|
Generator gen;
|
||||||
|
PiecesFiles pf;
|
||||||
|
|
||||||
|
auto t1 = high_resolution_clock::now();
|
||||||
|
auto t2 = high_resolution_clock::now();
|
||||||
|
duration<double, std::milli> ms_double;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
for (int i = min_size; i <= max_size; i++) {
|
||||||
|
std::cout << "| " << i;
|
||||||
|
|
||||||
|
t1 = high_resolution_clock::now();
|
||||||
|
std::vector<Polyomino> polyominoes = gen.generatePolyominoes(i);
|
||||||
|
t2 = high_resolution_clock::now();
|
||||||
|
ms_double = t2 - t1;
|
||||||
|
std::cout << " | " << polyominoes.size();
|
||||||
|
std::flush(std::cout);
|
||||||
|
std::cout << " | " << (int) ms_double.count() / 1000 << "s " << std::fmod(ms_double.count(), 1000) << "ms";
|
||||||
|
std::flush(std::cout);
|
||||||
|
|
||||||
|
t1 = high_resolution_clock::now();
|
||||||
|
ok = pf.savePieces(i, polyominoes);
|
||||||
|
t2 = high_resolution_clock::now();
|
||||||
|
ms_double = t2 - t1;
|
||||||
|
std::cout << " | " << (int) ms_double.count() / 1000 << "s " << std::fmod(ms_double.count(), 1000) << "ms";
|
||||||
|
std::flush(std::cout);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
std::cerr << "\nERROR: Could not save pieces to file." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
polyominoes.clear();
|
||||||
|
polyominoes.shrink_to_fit();
|
||||||
|
|
||||||
|
std::vector<Piece> pieces;
|
||||||
|
std::vector<int> convexPieces;
|
||||||
|
std::vector<int> holelessPieces;
|
||||||
|
std::vector<int> otherPieces;
|
||||||
|
|
||||||
|
t1 = high_resolution_clock::now();
|
||||||
|
ok = pf.loadPieces(i, pieces, convexPieces, holelessPieces, otherPieces);
|
||||||
|
t2 = high_resolution_clock::now();
|
||||||
|
ms_double = t2 - t1;
|
||||||
|
std::cout << " | " << (int) ms_double.count() / 1000 << "s " << std::fmod(ms_double.count(), 1000) << "ms";
|
||||||
|
std::flush(std::cout);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
std::cerr << "\nERROR: Could not load pieces from file." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pieces.clear();
|
||||||
|
pieces.shrink_to_fit();
|
||||||
|
convexPieces.clear();
|
||||||
|
convexPieces.shrink_to_fit();
|
||||||
|
holelessPieces.clear();
|
||||||
|
holelessPieces.shrink_to_fit();
|
||||||
|
otherPieces.clear();
|
||||||
|
otherPieces.shrink_to_fit();
|
||||||
|
|
||||||
|
std::string filePath;
|
||||||
|
pf.getFilePath(i, filePath);
|
||||||
|
int fileSize = std::filesystem::file_size(filePath);
|
||||||
|
std::cout << " | " << fileSize << " bytes |" << std::endl;
|
||||||
|
std::flush(std::cout);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,7 @@ Bag::Bag(const std::shared_ptr<PiecesList>& piecesList) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& piece : this->selectedPieces) {
|
for (const auto& piece : this->selectedPieces) {
|
||||||
int pieceSize = this->piecesList->lookAtPiece(piece).getPositions().size();
|
int pieceSize = this->piecesList->lookAtPiece(piece).getPositions().getSize();
|
||||||
this->currentBags.at(pieceSize).push_back(piece);
|
this->currentBags.at(pieceSize).push_back(piece);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ Board::Board(int width, int height) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Board::changeBlock(const Position& position, Block block) {
|
void Board::changeBlock(const Position& position, Block block) {
|
||||||
if (position.x < 0 || position.x >= this->width || position.y < 0) return;
|
if (position.x < 0 || static_cast<unsigned>(position.x) >= this->width || position.y < 0) return;
|
||||||
|
|
||||||
// resize the grid if needed
|
// resize the grid if needed
|
||||||
if (position.y >= this->grid.size()) {
|
if (static_cast<unsigned>(position.y) >= this->grid.size()) {
|
||||||
for (int j = this->grid.size(); j <= position.y; j++) {
|
for (int j = this->grid.size(); j <= position.y; j++) {
|
||||||
this->grid.push_back(this->emptyRow);
|
this->grid.push_back(this->emptyRow);
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ void Board::changeBlock(const Position& position, Block block) {
|
|||||||
|
|
||||||
void Board::insertRow(int height, int holePosition, Block blockType) {
|
void Board::insertRow(int height, int holePosition, Block blockType) {
|
||||||
std::vector<Block> insertedRow;
|
std::vector<Block> insertedRow;
|
||||||
for (int i = 0; i < this->width; i++) {
|
for (unsigned i = 0; i < this->width; i++) {
|
||||||
if (i == holePosition) {
|
if (i == holePosition) {
|
||||||
insertedRow.push_back(NOTHING);
|
insertedRow.push_back(NOTHING);
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ int Board::clearRows() {
|
|||||||
int clearedLines = 0;
|
int clearedLines = 0;
|
||||||
for (int j = this->grid.size() - 1; j >= 0; j--) {
|
for (int j = this->grid.size() - 1; j >= 0; j--) {
|
||||||
bool lineIsFull = true;
|
bool lineIsFull = true;
|
||||||
int i = 0;
|
unsigned i = 0;
|
||||||
while (lineIsFull && (i < width)) {
|
while (lineIsFull && (i < width)) {
|
||||||
if (this->grid.at(j).at(i) == NOTHING) {
|
if (this->grid.at(j).at(i) == NOTHING) {
|
||||||
lineIsFull = false;
|
lineIsFull = false;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ class Board {
|
|||||||
private:
|
private:
|
||||||
std::vector<std::vector<Block>> grid; // the grid, (0,0) is downleft
|
std::vector<std::vector<Block>> grid; // the grid, (0,0) is downleft
|
||||||
std::vector<Block> emptyRow; // an empty row of blocks
|
std::vector<Block> emptyRow; // an empty row of blocks
|
||||||
int width; // the width of the grid
|
unsigned width; // the width of the grid
|
||||||
int height; // the base height of the grid, which can extend indefinitely
|
unsigned height; // the base height of the grid, which can extend indefinitely
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -297,8 +297,8 @@ void Game::lockPiece() {
|
|||||||
|
|
||||||
/* clearing one more line is worth 2x more
|
/* clearing one more line is worth 2x more
|
||||||
clearing with a spin is worth as much as clearing 2x more lines */
|
clearing with a spin is worth as much as clearing 2x more lines */
|
||||||
long int clearScore = LINE_CLEAR_BASE_SCORE;
|
long int clearScore = LINE_CLEAR_BASE_SCORE / 2;
|
||||||
clearScore = clearScore << (clear.lines << (clear.isSpin));
|
clearScore = clearScore << (clear.lines << clear.isSpin);
|
||||||
|
|
||||||
if (this->B2BChain && B2BConditionsAreMet) {
|
if (this->B2BChain && B2BConditionsAreMet) {
|
||||||
clearScore *= B2B_SCORE_MULTIPLIER;
|
clearScore *= B2B_SCORE_MULTIPLIER;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ void GameBoard::initialize() {
|
|||||||
bool GameBoard::moveLeft() {
|
bool GameBoard::moveLeft() {
|
||||||
this->movedLeftLast = true;
|
this->movedLeftLast = true;
|
||||||
|
|
||||||
if (this->activePieceInWall(Position{-1, 0})) {
|
if (this->activePieceInWall(Position(-1, 0))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -57,7 +57,7 @@ bool GameBoard::moveLeft() {
|
|||||||
bool GameBoard::moveRight() {
|
bool GameBoard::moveRight() {
|
||||||
this->movedLeftLast = false;
|
this->movedLeftLast = false;
|
||||||
|
|
||||||
if (this->activePieceInWall(Position{1, 0})) {
|
if (this->activePieceInWall(Position(1, 0))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -68,7 +68,7 @@ bool GameBoard::moveRight() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GameBoard::moveDown() {
|
bool GameBoard::moveDown() {
|
||||||
if (this->activePieceInWall(Position{0, -1})) {
|
if (this->activePieceInWall(Position(0, -1))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -100,10 +100,10 @@ bool GameBoard::rotate(Rotation rotation) {
|
|||||||
for (Position position : stored.getPositions()) {
|
for (Position position : stored.getPositions()) {
|
||||||
Position positionInGrid(position + this->activePiecePosition);
|
Position positionInGrid(position + this->activePiecePosition);
|
||||||
safePositions.insert(positionInGrid);
|
safePositions.insert(positionInGrid);
|
||||||
safePositions.insert(positionInGrid + Position{0, 1});
|
safePositions.insert(positionInGrid + Position(0, 1));
|
||||||
safePositions.insert(positionInGrid + Position{1, 0});
|
safePositions.insert(positionInGrid + Position(1, 0));
|
||||||
safePositions.insert(positionInGrid + Position{0, -1});
|
safePositions.insert(positionInGrid + Position(0, -1));
|
||||||
safePositions.insert(positionInGrid + Position{-1, 0});
|
safePositions.insert(positionInGrid + Position(-1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// first try kicking the piece down
|
// first try kicking the piece down
|
||||||
@@ -147,18 +147,18 @@ bool GameBoard::tryKicking(bool testingBottom, const std::set<Position>& safePos
|
|||||||
// we first check the side to which the player moved last
|
// we first check the side to which the player moved last
|
||||||
if (movedLeftLast) {
|
if (movedLeftLast) {
|
||||||
if (overlapsLeft) {
|
if (overlapsLeft) {
|
||||||
if (this->tryFittingKickedPiece(safePositions, Position({-i, j}), overlapsLeft)) return true;
|
if (this->tryFittingKickedPiece(safePositions, Position(-i, j), overlapsLeft)) return true;
|
||||||
}
|
}
|
||||||
if (overlapsRight) {
|
if (overlapsRight) {
|
||||||
if (this->tryFittingKickedPiece(safePositions, Position({+i, j}), overlapsRight)) return true;
|
if (this->tryFittingKickedPiece(safePositions, Position(+i, j), overlapsRight)) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (overlapsRight) {
|
if (overlapsRight) {
|
||||||
if (this->tryFittingKickedPiece(safePositions, Position({+i, j}), overlapsRight)) return true;
|
if (this->tryFittingKickedPiece(safePositions, Position(+i, j), overlapsRight)) return true;
|
||||||
}
|
}
|
||||||
if (overlapsLeft) {
|
if (overlapsLeft) {
|
||||||
if (this->tryFittingKickedPiece(safePositions, Position({-i, j}), overlapsLeft)) return true;
|
if (this->tryFittingKickedPiece(safePositions, Position(-i, j), overlapsLeft)) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,11 +265,11 @@ bool GameBoard::activePieceInWall(const Position& shift) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GameBoard::touchesGround() const {
|
bool GameBoard::touchesGround() const {
|
||||||
return this->activePieceInWall(Position{0, -1});
|
return this->activePieceInWall(Position(0, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Position GameBoard::lowestPosition() const {
|
Position GameBoard::lowestPosition() const {
|
||||||
Position shift = Position{0, -1};
|
Position shift = Position(0, -1);
|
||||||
while (!activePieceInWall(shift)) {
|
while (!activePieceInWall(shift)) {
|
||||||
shift.y -= 1;
|
shift.y -= 1;
|
||||||
}
|
}
|
||||||
@@ -278,8 +278,8 @@ Position GameBoard::lowestPosition() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LineClear GameBoard::lockPiece() {
|
LineClear GameBoard::lockPiece() {
|
||||||
bool isLockedInPlace = (this->activePieceInWall(Position{0, 1}) && this->activePieceInWall(Position{1, 0})
|
bool isLockedInPlace = (this->activePieceInWall(Position(0, 1)) && this->activePieceInWall(Position(1, 0))
|
||||||
&& this->activePieceInWall(Position{-1, 0}) && this->activePieceInWall(Position{0, -1}));
|
&& this->activePieceInWall(Position(-1, 0)) && this->activePieceInWall(Position(0, -1)));
|
||||||
|
|
||||||
for (Position position : this->activePiece->getPositions()) {
|
for (Position position : this->activePiece->getPositions()) {
|
||||||
this->board.changeBlock(position + this->activePiecePosition, this->activePiece->getBlockType());
|
this->board.changeBlock(position + this->activePiecePosition, this->activePiece->getBlockType());
|
||||||
@@ -345,7 +345,7 @@ std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
|
|||||||
// print only the position were the active piece is
|
// print only the position were the active piece is
|
||||||
for (int y = gameboard.activePiecePosition.y + gameboard.activePiece->getLength() - 1; y >= gameboard.board.getBaseHeight(); y--) {
|
for (int y = gameboard.activePiecePosition.y + gameboard.activePiece->getLength() - 1; y >= gameboard.board.getBaseHeight(); y--) {
|
||||||
for (int x = 0; x < gameboard.board.getWidth(); x++) {
|
for (int x = 0; x < gameboard.board.getWidth(); x++) {
|
||||||
bool hasActivePiece = gameboard.activePiece->getPositions().contains(Position{x, y} - gameboard.activePiecePosition);
|
bool hasActivePiece = gameboard.activePiece->containsSquare(Position(x, y) - gameboard.activePiecePosition);
|
||||||
if (hasActivePiece) {
|
if (hasActivePiece) {
|
||||||
os << "*";
|
os << "*";
|
||||||
}
|
}
|
||||||
@@ -361,7 +361,7 @@ std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
|
|||||||
Block pieceBlockType = (gameboard.activePiece == nullptr) ? NOTHING : gameboard.activePiece->getBlockType();
|
Block pieceBlockType = (gameboard.activePiece == nullptr) ? NOTHING : gameboard.activePiece->getBlockType();
|
||||||
for (int y = gameboard.board.getBaseHeight() - 1; y >= 0; y--) {
|
for (int y = gameboard.board.getBaseHeight() - 1; y >= 0; y--) {
|
||||||
for (int x = 0; x < gameboard.board.getWidth(); x++) {
|
for (int x = 0; x < gameboard.board.getWidth(); x++) {
|
||||||
bool hasActivePiece = (gameboard.activePiece == nullptr) ? false : gameboard.activePiece->getPositions().contains(Position{x, y} - gameboard.activePiecePosition);
|
bool hasActivePiece = (gameboard.activePiece == nullptr) ? false : gameboard.activePiece->containsSquare(Position(x, y) - gameboard.activePiecePosition);
|
||||||
|
|
||||||
// the active piece takes visual priority over the board
|
// the active piece takes visual priority over the board
|
||||||
if (hasActivePiece) {
|
if (hasActivePiece) {
|
||||||
@@ -369,7 +369,7 @@ std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
|
|||||||
os << "*";
|
os << "*";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Block block = gameboard.board.getBlock(Position{x, y});
|
Block block = gameboard.board.getBlock(Position(x, y));
|
||||||
os << getConsoleColorCode(block);
|
os << getConsoleColorCode(block);
|
||||||
if (block != NOTHING) {
|
if (block != NOTHING) {
|
||||||
os << "*";
|
os << "*";
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class GameBoard {
|
|||||||
* Check if one of the active piece's positions shifted by a specified position would overlap with a set of positions
|
* 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
|
* @return If the shifted active piece overlaps with one of the position
|
||||||
*/
|
*/
|
||||||
bool activePieceOverlaps(const std::set<Position>& safePositions, const Position& shift = Position{0, 0}) const;
|
bool activePieceOverlaps(const std::set<Position>& safePositions, const Position& shift = Position(0, 0)) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -103,7 +103,7 @@ class GameBoard {
|
|||||||
* Checks if one of the active piece's positions touches a wall in the board
|
* Checks if one of the active piece's positions touches a wall in the board
|
||||||
* @return If the active piece is in a wall
|
* @return If the active piece is in a wall
|
||||||
*/
|
*/
|
||||||
bool activePieceInWall(const Position& shift = Position{0, 0}) const;
|
bool activePieceInWall(const Position& shift = Position(0, 0)) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks is the active piece as a wall directly below one of its position
|
* Checks is the active piece as a wall directly below one of its position
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
|
|
||||||
static const int FRAMES_PER_SECOND = 60; // the number of frames per second, all the values in the app were choosen with this number in mind
|
static const int FRAMES_PER_SECOND = 60; // the number of frames per second, all the values in the app were choosen with this number in mind
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,13 +27,12 @@ PiecesList::PiecesList() {
|
|||||||
this->pushBackEmptyVectors();
|
this->pushBackEmptyVectors();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PiecesList::loadPieces(int size) {
|
bool PiecesList::loadPieces(unsigned max_size) {
|
||||||
if (size < 1) return false;
|
if (max_size < 1) return false;
|
||||||
if (size <= this->highestLoadedSize) return true;
|
if (max_size <= this->highestLoadedSize) return true;
|
||||||
|
|
||||||
PiecesFiles piecesFiles;
|
PiecesFiles piecesFiles;
|
||||||
for (int i = this->highestLoadedSize + 1; i <= size; i++) {
|
for (unsigned i = this->highestLoadedSize + 1; i <= max_size; i++) {
|
||||||
|
|
||||||
if (!piecesFiles.loadPieces(i, this->loadedPieces.at(i), this->convexPieces.at(i), this->holelessPieces.at(i), this->otherPieces.at(i))) {
|
if (!piecesFiles.loadPieces(i, this->loadedPieces.at(i), this->convexPieces.at(i), this->holelessPieces.at(i), this->otherPieces.at(i))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -46,14 +45,14 @@ bool PiecesList::loadPieces(int size) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PiecesList::selectPiece(int size, int number) {
|
bool PiecesList::selectPiece(unsigned size, unsigned number) {
|
||||||
if (size < 1 || size > this->highestLoadedSize || number >= this->loadedPieces.at(size).size()) return false;
|
if (size < 1 || size > this->highestLoadedSize || number >= this->loadedPieces.at(size).size()) return false;
|
||||||
|
|
||||||
this->selectedPieces.push_back(std::pair<int, int>(size, number));
|
this->selectedPieces.push_back(std::pair<int, int>(size, number));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PiecesList::selectAllPieces(int size) {
|
bool PiecesList::selectAllPieces(unsigned size) {
|
||||||
if (size < 1 || size > this->highestLoadedSize) return false;
|
if (size < 1 || size > this->highestLoadedSize) return false;
|
||||||
|
|
||||||
for (int i = 0; i < this->loadedPieces.at(size).size(); i++) {
|
for (int i = 0; i < this->loadedPieces.at(size).size(); i++) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
class PiecesList {
|
class PiecesList {
|
||||||
private:
|
private:
|
||||||
int highestLoadedSize; // the highest size of pieces currently loaded
|
unsigned highestLoadedSize; // the highest size of pieces currently loaded
|
||||||
std::vector<std::vector<Piece>> loadedPieces; // every loaded pieces by size
|
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>> 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>> holelessPieces; // the list of holeless loaded pieces by size
|
||||||
@@ -30,22 +30,22 @@ class PiecesList {
|
|||||||
PiecesList();
|
PiecesList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the list load all pieces of the specified size
|
* Makes the list load all pieces up to the specified size
|
||||||
* @return If it sucessfully loaded the pieces
|
* @return If all pieces up to the specified size are correctly loaded
|
||||||
*/
|
*/
|
||||||
bool loadPieces(int size);
|
[[nodiscard]] bool loadPieces(unsigned max_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the specified piece
|
* Selects the specified piece
|
||||||
* @return If the piece could be selected
|
* @return If the piece could be selected
|
||||||
*/
|
*/
|
||||||
bool selectPiece(int size, int number);
|
bool selectPiece(unsigned size, unsigned number);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects all pieces of the specified size
|
* Selects all pieces of the specified size
|
||||||
* @return If the pieces could be selected
|
* @return If the pieces could be selected
|
||||||
*/
|
*/
|
||||||
bool selectAllPieces(int size);
|
bool selectAllPieces(unsigned size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects all convex pieces of the specified size
|
* Selects all convex pieces of the specified size
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ GameDistributionAppMenu::GameDistributionAppMenu(std::shared_ptr<MenuStack> menu
|
|||||||
AppMenu(menuStack, settings, renderWindow),
|
AppMenu(menuStack, settings, renderWindow),
|
||||||
playerCursor({1}) {
|
playerCursor({1}) {
|
||||||
|
|
||||||
for (int i = 1; i <= this->settings->getMaximumPiecesSize(); i++) {
|
for (int i = 1; i <= this->settings->getLoadablePiecesSize(); i++) {
|
||||||
this->playerCursor.addRow(i, 1);
|
this->playerCursor.addRow(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ void GameDistributionAppMenu::drawFrame() const {
|
|||||||
const DistributionMode distributionMode = this->settings->getMenu().readPiecesList().getDistributionMode();
|
const DistributionMode distributionMode = this->settings->getMenu().readPiecesList().getDistributionMode();
|
||||||
const std::vector<int>& distributions = this->settings->getDistributions();
|
const std::vector<int>& distributions = this->settings->getDistributions();
|
||||||
|
|
||||||
int firstElem = std::clamp(((int) this->playerCursor.getPosition().y) - 1, 0, this->settings->getMaximumPiecesSize() - 3);
|
int firstElem = std::clamp(((int) this->playerCursor.getPosition().y) - 1, 0, this->settings->getLoadablePiecesSize() - 3);
|
||||||
if (firstElem == 0) {
|
if (firstElem == 0) {
|
||||||
this->placeText(text, this->playerCursor, "< DISTRIBUTION MODE: " + getPiecesDistributionName(distributionMode) + " >", 5.f, 15.f, sf::Vector2u{0, 0});
|
this->placeText(text, this->playerCursor, "< DISTRIBUTION MODE: " + getPiecesDistributionName(distributionMode) + " >", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ GamePiecesAppMenu::GamePiecesAppMenu(std::shared_ptr<MenuStack> menuStack, std::
|
|||||||
AppMenu(menuStack, settings, renderWindow),
|
AppMenu(menuStack, settings, renderWindow),
|
||||||
playerCursor({1, (unsigned int) this->settings->getSelectedPieces().size() + 1u}) {
|
playerCursor({1, (unsigned int) this->settings->getSelectedPieces().size() + 1u}) {
|
||||||
|
|
||||||
for (int i = 1; i <= this->settings->getMaximumPiecesSize(); i++) {
|
for (int i = 1; i <= this->settings->getLoadablePiecesSize(); i++) {
|
||||||
this->playerCursor.addRow(i + 1, this->settings->getMenu().readPiecesList().getNumberOfPieces(i) + 4);
|
this->playerCursor.addRow(i + 1, this->settings->getMenu().readPiecesList().getNumberOfPieces(i) + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->settings->getMaximumPiecesSize() < MAXIMUM_PIECES_SIZE) {
|
if (this->settings->getLoadablePiecesSize() < MAXIMUM_PIECES_SIZE) {
|
||||||
this->playerCursor.addRow(this->settings->getMaximumPiecesSize() + 2, 1);
|
this->playerCursor.addRow(this->settings->getLoadablePiecesSize() + 2, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,8 +35,8 @@ void GamePiecesAppMenu::computeFrame() {
|
|||||||
this->menuStack->push(std::make_shared<GameDistributionAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
this->menuStack->push(std::make_shared<GameDistributionAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->playerCursor.getPosition().y == (this->settings->getMaximumPiecesSize() + 2)) {
|
if (this->playerCursor.getPosition().y == (this->settings->getLoadablePiecesSize() + 2)) {
|
||||||
int newMaxSize = this->settings->getMaximumPiecesSize() + 1;
|
int newMaxSize = this->settings->getLoadablePiecesSize() + 1;
|
||||||
this->settings->loadPieces(newMaxSize);
|
this->settings->loadPieces(newMaxSize);
|
||||||
|
|
||||||
this->playerCursor.removeRow(newMaxSize + 1);
|
this->playerCursor.removeRow(newMaxSize + 1);
|
||||||
@@ -95,8 +95,8 @@ void GamePiecesAppMenu::drawFrame() const {
|
|||||||
this->drawSelectedPiecesRow(15.f);
|
this->drawSelectedPiecesRow(15.f);
|
||||||
|
|
||||||
bool drawFromFirstElem = (this->playerCursor.getPosition().y == 1);
|
bool drawFromFirstElem = (this->playerCursor.getPosition().y == 1);
|
||||||
bool addExtraLine = (this->settings->getMaximumPiecesSize() < MAXIMUM_PIECES_SIZE);
|
bool addExtraLine = (this->settings->getLoadablePiecesSize() < MAXIMUM_PIECES_SIZE);
|
||||||
int firstElem = std::clamp(((int) this->playerCursor.getPosition().y) - 2, 1, this->settings->getMaximumPiecesSize() - 2 + (addExtraLine ? 1 : 0));
|
int firstElem = std::clamp(((int) this->playerCursor.getPosition().y) - 2, 1, this->settings->getLoadablePiecesSize() - 2 + (addExtraLine ? 1 : 0));
|
||||||
this->drawRow(firstElem, 25.f, drawFromFirstElem);
|
this->drawRow(firstElem, 25.f, drawFromFirstElem);
|
||||||
this->drawRow(firstElem + 1, 35.f, drawFromFirstElem);
|
this->drawRow(firstElem + 1, 35.f, drawFromFirstElem);
|
||||||
this->drawRow(firstElem + 2, 45.f, drawFromFirstElem);
|
this->drawRow(firstElem + 2, 45.f, drawFromFirstElem);
|
||||||
@@ -130,7 +130,7 @@ void GamePiecesAppMenu::drawSelectedPiecesRow(float yPos) const {
|
|||||||
|
|
||||||
int pieceSize = getSizeOfPieces(pieceType);
|
int pieceSize = getSizeOfPieces(pieceType);
|
||||||
if (pieceSize > 0) {
|
if (pieceSize > 0) {
|
||||||
if (!(pieceSize > this->settings->getMaximumPiecesSize())) {
|
if (!(pieceSize > this->settings->getLoadablePiecesSize())) {
|
||||||
const Piece& piece = this->settings->getMenu().readPiecesList().lookAtPiece({pieceSize, value});
|
const Piece& piece = this->settings->getMenu().readPiecesList().lookAtPiece({pieceSize, value});
|
||||||
int cellSize = (8 * this->settings->getWindowSizeMultiplier()) / (piece.getLength());
|
int cellSize = (8 * this->settings->getWindowSizeMultiplier()) / (piece.getLength());
|
||||||
sf::FloatRect piecePosition(sf::Vector2f(xProgress, yPos - 4.f) * (float) this->settings->getWindowSizeMultiplier(), sf::Vector2f(8 , 8) * (float) this->settings->getWindowSizeMultiplier());
|
sf::FloatRect piecePosition(sf::Vector2f(xProgress, yPos - 4.f) * (float) this->settings->getWindowSizeMultiplier(), sf::Vector2f(8 , 8) * (float) this->settings->getWindowSizeMultiplier());
|
||||||
@@ -143,7 +143,7 @@ void GamePiecesAppMenu::drawSelectedPiecesRow(float yPos) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!(value > this->settings->getMaximumPiecesSize())) {
|
if (!(value > this->settings->getLoadablePiecesSize())) {
|
||||||
this->placeText(text, {}, ((first) ? "" : " ") + getPiecesTypeName(pieceType) + "_" + std::to_string(value), xProgress, yPos, {});
|
this->placeText(text, {}, ((first) ? "" : " ") + getPiecesTypeName(pieceType) + "_" + std::to_string(value), xProgress, yPos, {});
|
||||||
xProgress += (1.f + (text.getGlobalBounds().size.x / this->settings->getWindowSizeMultiplier()));
|
xProgress += (1.f + (text.getGlobalBounds().size.x / this->settings->getWindowSizeMultiplier()));
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@ void GamePiecesAppMenu::drawSelectedPiecesRow(float yPos) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GamePiecesAppMenu::drawRow(int piecesSize, float yPos, bool drawFromFirstElem) const {
|
void GamePiecesAppMenu::drawRow(int piecesSize, float yPos, bool drawFromFirstElem) const {
|
||||||
if (piecesSize > this->settings->getMaximumPiecesSize()) {
|
if (piecesSize > this->settings->getLoadablePiecesSize()) {
|
||||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier() * 2);
|
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier() * 2);
|
||||||
text.setOutlineThickness(this->settings->getWindowSizeMultiplier() / 2);
|
text.setOutlineThickness(this->settings->getWindowSizeMultiplier() / 2);
|
||||||
if (this->playerCursor.getPosition().y == (piecesSize + 1)) {
|
if (this->playerCursor.getPosition().y == (piecesSize + 1)) {
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ void GamePlayingAppMenu::drawFrame() const {
|
|||||||
// board
|
// board
|
||||||
for (int y = this->game.getBoard().getBaseHeight() + 9; y >= 0; y--) {
|
for (int y = this->game.getBoard().getBaseHeight() + 9; y >= 0; y--) {
|
||||||
for (int x = 0; x < this->game.getBoard().getWidth(); x++) {
|
for (int x = 0; x < this->game.getBoard().getWidth(); x++) {
|
||||||
Block block = this->game.getBoard().getBlock(Position{x, y});
|
Block block = this->game.getBoard().getBlock(Position(x, y));
|
||||||
if (isBoardInvisible) block = NOTHING;
|
if (isBoardInvisible) block = NOTHING;
|
||||||
|
|
||||||
sf::RectangleShape cell(cellSize);
|
sf::RectangleShape cell(cellSize);
|
||||||
@@ -196,7 +196,7 @@ void GamePlayingAppMenu::drawFrame() const {
|
|||||||
for (int y = 0; y < this->game.getNextPieces().at(i).getLength(); y++) {
|
for (int y = 0; y < this->game.getNextPieces().at(i).getLength(); y++) {
|
||||||
for (int x = 0; x < this->game.getNextPieces().at(i).getLength(); x++) {
|
for (int x = 0; x < this->game.getNextPieces().at(i).getLength(); x++) {
|
||||||
sf::RectangleShape cell(nextCellSize);
|
sf::RectangleShape cell(nextCellSize);
|
||||||
if (this->game.getNextPieces().at(i).getPositions().contains(Position{x, y})) {
|
if (this->game.getNextPieces().at(i).containsSquare(Position(x, y))) {
|
||||||
cell.setFillColor(pieceColor);
|
cell.setFillColor(pieceColor);
|
||||||
lowestRank = y;
|
lowestRank = y;
|
||||||
}
|
}
|
||||||
@@ -223,7 +223,7 @@ void GamePlayingAppMenu::drawFrame() const {
|
|||||||
for (int y = 0; y < this->game.getHeldPiece()->getLength(); y++) {
|
for (int y = 0; y < this->game.getHeldPiece()->getLength(); y++) {
|
||||||
for (int x = 0; x < this->game.getHeldPiece()->getLength(); x++) {
|
for (int x = 0; x < this->game.getHeldPiece()->getLength(); x++) {
|
||||||
sf::RectangleShape cell(holdCellSize);
|
sf::RectangleShape cell(holdCellSize);
|
||||||
if (this->game.getHeldPiece()->getPositions().contains(Position{x, y})) {
|
if (this->game.getHeldPiece()->containsSquare(Position(x, y))) {
|
||||||
cell.setFillColor(color);
|
cell.setFillColor(color);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ StartUpAppMenu::StartUpAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared
|
|||||||
AppMenu(menuStack, settings, renderWindow),
|
AppMenu(menuStack, settings, renderWindow),
|
||||||
playerCursor({MAXIMUM_PIECES_SIZE + 1}) {
|
playerCursor({MAXIMUM_PIECES_SIZE + 1}) {
|
||||||
|
|
||||||
this->playerCursor.goToPosition({(unsigned int) std::clamp(this->settings->getMaximumPiecesSize(), MINIMUM_PIECES_SIZE, MAXIMUM_PIECES_SIZE), 0u});
|
this->playerCursor.goToPosition({(unsigned int) std::clamp(this->settings->getLoadablePiecesSize(), MINIMUM_PIECES_SIZE, MAXIMUM_PIECES_SIZE), 0u});
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartUpAppMenu::computeFrame() {
|
void StartUpAppMenu::computeFrame() {
|
||||||
|
|||||||
@@ -27,41 +27,41 @@ Settings::Settings(bool loadPieces) {
|
|||||||
this->loadSettingsFromFile(loadPieces, {});
|
this->loadSettingsFromFile(loadPieces, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::loadPieces(int maximumPiecesSizeRequest) {
|
void Settings::loadPieces(int loadablePiecesSizeRequest) {
|
||||||
if (maximumPiecesSizeRequest < MINIMUM_PIECES_SIZE) {
|
if (loadablePiecesSizeRequest < MINIMUM_PIECES_SIZE) {
|
||||||
maximumPiecesSizeRequest = MINIMUM_PIECES_SIZE;
|
loadablePiecesSizeRequest = MINIMUM_PIECES_SIZE;
|
||||||
}
|
}
|
||||||
else if (maximumPiecesSizeRequest > MAXIMUM_PIECES_SIZE) {
|
else if (loadablePiecesSizeRequest > MAXIMUM_PIECES_SIZE) {
|
||||||
maximumPiecesSizeRequest = MAXIMUM_PIECES_SIZE;
|
loadablePiecesSizeRequest = MAXIMUM_PIECES_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool succeeded = true;
|
bool succeeded = true;
|
||||||
int i = 1;
|
int i = 1;
|
||||||
while (succeeded && (i <= maximumPiecesSizeRequest)) {
|
while (succeeded && (i <= loadablePiecesSizeRequest)) {
|
||||||
succeeded = this->menu.getPiecesList().loadPieces(i);
|
succeeded = this->menu.getPiecesList().loadPieces(i);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (succeeded) {
|
if (succeeded) {
|
||||||
this->maximumPiecesSize = maximumPiecesSizeRequest;
|
this->loadablePiecesSize = loadablePiecesSizeRequest;
|
||||||
}
|
}
|
||||||
this->loadedPieces = succeeded;
|
this->loadedPieces = succeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::loadSettingsFromFile(bool loadPieces, std::optional<int> maximumPiecesSizeRequest) {
|
void Settings::loadSettingsFromFile(bool loadPieces, std::optional<int> loadablePiecesSizeRequest) {
|
||||||
std::ifstream settingsFile("data/config/settings.bin", std::ios::binary);
|
std::ifstream settingsFile("data/config/settings.bin", std::ios::binary);
|
||||||
char byte;
|
char byte;
|
||||||
|
|
||||||
// file format version
|
// file format version
|
||||||
settingsFile.get(byte);
|
settingsFile.get(byte);
|
||||||
|
|
||||||
// maximum pieces size
|
// loadable pieces size
|
||||||
settingsFile.get(byte);
|
settingsFile.get(byte);
|
||||||
this->maximumPiecesSize = byte;
|
this->loadablePiecesSize = byte;
|
||||||
|
|
||||||
if (loadPieces) {
|
if (loadPieces) {
|
||||||
if (maximumPiecesSizeRequest.has_value()) {
|
if (loadablePiecesSizeRequest.has_value()) {
|
||||||
this->loadPieces(maximumPiecesSizeRequest.value());
|
this->loadPieces(loadablePiecesSizeRequest.value());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this->loadPieces(byte);
|
this->loadPieces(byte);
|
||||||
@@ -165,8 +165,8 @@ void Settings::saveSettingsToFile() const {
|
|||||||
byte = CURRENT_FILE_FORMAT_VERSION;
|
byte = CURRENT_FILE_FORMAT_VERSION;
|
||||||
settingsFile.write(&byte, 1);
|
settingsFile.write(&byte, 1);
|
||||||
|
|
||||||
// maximum pieces size
|
// loadable pieces size
|
||||||
byte = this->maximumPiecesSize;
|
byte = this->loadablePiecesSize;
|
||||||
settingsFile.write(&byte, 1);
|
settingsFile.write(&byte, 1);
|
||||||
|
|
||||||
// keybind layout
|
// keybind layout
|
||||||
@@ -321,7 +321,7 @@ void Settings::confirmSelectedPieces() {
|
|||||||
int size = getSizeOfPieces(type);
|
int size = getSizeOfPieces(type);
|
||||||
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
if (!(value > this->maximumPiecesSize)) {
|
if (!(value > this->loadablePiecesSize)) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CONVEX_PIECES : {this->menu.getPiecesList().selectConvexPieces(value); break;}
|
case CONVEX_PIECES : {this->menu.getPiecesList().selectConvexPieces(value); break;}
|
||||||
case HOLELESS_PIECES : {this->menu.getPiecesList().selectHolelessPieces(value); break;}
|
case HOLELESS_PIECES : {this->menu.getPiecesList().selectHolelessPieces(value); break;}
|
||||||
@@ -332,7 +332,7 @@ void Settings::confirmSelectedPieces() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!(getSizeOfPieces(type) > this->maximumPiecesSize)) {
|
if (!(getSizeOfPieces(type) > this->loadablePiecesSize)) {
|
||||||
this->menu.getPiecesList().selectPiece(size, value);
|
this->menu.getPiecesList().selectPiece(size, value);
|
||||||
selectedNone = false;
|
selectedNone = false;
|
||||||
}
|
}
|
||||||
@@ -347,7 +347,7 @@ void Settings::confirmSelectedPieces() {
|
|||||||
|
|
||||||
bool Settings::increaseDistribution(int size) {
|
bool Settings::increaseDistribution(int size) {
|
||||||
if (!this->loadedPieces) return false;
|
if (!this->loadedPieces) return false;
|
||||||
if (size < 1 || size > this->maximumPiecesSize) return false;
|
if (size < 1 || size > this->loadablePiecesSize) return false;
|
||||||
|
|
||||||
if (this->distributions.at(size) < DISTRIBUTION_MAX) {
|
if (this->distributions.at(size) < DISTRIBUTION_MAX) {
|
||||||
this->distributions.at(size)++;
|
this->distributions.at(size)++;
|
||||||
@@ -358,7 +358,7 @@ bool Settings::increaseDistribution(int size) {
|
|||||||
|
|
||||||
bool Settings::decreaseDistribution(int size) {
|
bool Settings::decreaseDistribution(int size) {
|
||||||
if (!this->loadedPieces) return false;
|
if (!this->loadedPieces) return false;
|
||||||
if (size < 1 || size > this->maximumPiecesSize) return false;
|
if (size < 1 || size > this->loadablePiecesSize) return false;
|
||||||
|
|
||||||
if (this->distributions.at(size) > 0) {
|
if (this->distributions.at(size) > 0) {
|
||||||
this->distributions.at(size)--;
|
this->distributions.at(size)--;
|
||||||
@@ -383,8 +383,8 @@ Keybinds& Settings::getKeybinds() {
|
|||||||
return this->keybinds.at(this->chosenKeybinds);
|
return this->keybinds.at(this->chosenKeybinds);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Settings::getMaximumPiecesSize() const {
|
int Settings::getLoadablePiecesSize() const {
|
||||||
return this->maximumPiecesSize;
|
return this->loadablePiecesSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::hasLoadedPieces() const {
|
bool Settings::hasLoadedPieces() const {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ static const std::pair<PiecesType, int> DEFAULT_SELECTION = {ALL_PIECES, MINIMUM
|
|||||||
class Settings {
|
class Settings {
|
||||||
private:
|
private:
|
||||||
Menu menu;
|
Menu menu;
|
||||||
int maximumPiecesSize;
|
int loadablePiecesSize;
|
||||||
bool loadedPieces;
|
bool loadedPieces;
|
||||||
std::vector<Keybinds> keybinds;
|
std::vector<Keybinds> keybinds;
|
||||||
int chosenKeybinds;
|
int chosenKeybinds;
|
||||||
@@ -42,9 +42,9 @@ class Settings {
|
|||||||
public:
|
public:
|
||||||
Settings(bool loadPieces);
|
Settings(bool loadPieces);
|
||||||
|
|
||||||
void loadPieces(int maximumPiecesSizeRequest);
|
void loadPieces(int loadablePiecesSizeRequest);
|
||||||
|
|
||||||
void loadSettingsFromFile(bool loadPieces, std::optional<int> maximumPiecesSizeRequest);
|
void loadSettingsFromFile(bool loadPieces, std::optional<int> loadablePiecesSizeRequest);
|
||||||
|
|
||||||
void saveSettingsToFile() const;
|
void saveSettingsToFile() const;
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ class Settings {
|
|||||||
|
|
||||||
Keybinds& getKeybinds();
|
Keybinds& getKeybinds();
|
||||||
|
|
||||||
int getMaximumPiecesSize() const;
|
int getLoadablePiecesSize() const;
|
||||||
|
|
||||||
bool hasLoadedPieces() const;
|
bool hasLoadedPieces() const;
|
||||||
|
|
||||||
|
|||||||
@@ -4,42 +4,69 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
[[nodiscard]] bool resetSettingsFile();
|
||||||
void resetSettingsFile();
|
[[nodiscard]] bool resetKeybindFile(int layout);
|
||||||
void resetKeybindFile(int layout);
|
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::srand(std::time(NULL));
|
std::srand(std::time(NULL));
|
||||||
|
|
||||||
|
bool everythingIsOK = true;
|
||||||
|
|
||||||
|
// CHECK PIECES FILES
|
||||||
|
|
||||||
PiecesFiles pf;
|
PiecesFiles pf;
|
||||||
|
bool warned = false;
|
||||||
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
|
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
|
||||||
if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) {
|
if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) {
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
std::cout << "IMPORTANT: You are currently in release mode, if you do not wish to generate big pieces (can take several minutes), type 'xmake f -m debug'." << std::endl;
|
if (!warned && i > DEBUG_PIECES_SIZE) {
|
||||||
|
std::cout << "IMPORTANT: You are currently in release mode, if you do not wish to generate big pieces (can take several minutes), type 'xmake f -m debug'." << std::endl;
|
||||||
|
warned = true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::cout << "INFO: Pieces files for size " << i << " not found, generating..." << std::endl;
|
std::cout << "INFO: Pieces files for size " << i << " not found, generating..." << std::endl;
|
||||||
pf.savePieces(i);
|
everythingIsOK &= pf.savePieces(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
std::cout << "IMPORTANT: You are currently in debug mode, if you wish to use bigger pieces, type 'xmake f -m release'." << std::endl;
|
std::cout << "IMPORTANT: You are currently in debug mode, if you wish to use bigger pieces, type 'xmake f -m release'." << std::endl;
|
||||||
|
|
||||||
bool everythingGenerated = true;
|
bool releasePiecesGenerated = true;
|
||||||
for (int i = DEBUG_PIECES_SIZE; i <= RELEASE_PIECES_SIZE; i++) {
|
for (int i = DEBUG_PIECES_SIZE + 1; i <= RELEASE_PIECES_SIZE; i++) {
|
||||||
if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) {
|
if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) {
|
||||||
everythingGenerated = false;
|
releasePiecesGenerated = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!everythingGenerated) {
|
if (!releasePiecesGenerated) {
|
||||||
std::cout << "NOTE: You do not have all pieces generated, generating can take several minutes." << std::endl;
|
std::cout << "NOTE: You do not have all pieces generated, generating can take several minutes." << std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool everythingGenerated = true;
|
||||||
|
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
|
||||||
|
std::string filePath = "data/pieces/" + std::to_string(i) + "minos.bin";
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(filePath)) {
|
||||||
|
std::cout << "ERROR: Could not open file " + filePath << std::endl;
|
||||||
|
everythingIsOK &= false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK CONFIG FILES
|
||||||
|
|
||||||
if (!std::filesystem::exists("data/config/settings.bin")) {
|
if (!std::filesystem::exists("data/config/settings.bin")) {
|
||||||
std::cout << "INFO: Settings file not found, generating..." << std::endl;
|
std::cout << "INFO: Settings file not found, generating..." << std::endl;
|
||||||
resetSettingsFile();
|
everythingIsOK &= resetSettingsFile();
|
||||||
|
|
||||||
|
for (int i = 0; i < NUMBER_OF_KEYBINDS; i++) {
|
||||||
|
if (!std::filesystem::exists("data/config/keybinds/layout" + std::to_string(i) + ".bin")) {
|
||||||
|
std::cout << "INFO: Keybind file number " << (i + 1) << "/" << NUMBER_OF_KEYBINDS << " not found, generating..." << std::endl;
|
||||||
|
everythingIsOK &= resetKeybindFile(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::ifstream settingsFile("data/config/settings.bin", std::ios::binary);
|
std::ifstream settingsFile("data/config/settings.bin", std::ios::binary);
|
||||||
@@ -48,42 +75,49 @@ int main() {
|
|||||||
settingsFile.get(byte);
|
settingsFile.get(byte);
|
||||||
if ((unsigned char) byte < CURRENT_FILE_FORMAT_VERSION) {
|
if ((unsigned char) byte < CURRENT_FILE_FORMAT_VERSION) {
|
||||||
std::cout << "INFO: Files format changed, regenerating..." << std::endl;
|
std::cout << "INFO: Files format changed, regenerating..." << std::endl;
|
||||||
resetSettingsFile();
|
everythingIsOK &= resetSettingsFile();
|
||||||
for (int i = 0; i < NUMBER_OF_KEYBINDS; i++) {
|
for (int i = 0; i < NUMBER_OF_KEYBINDS; i++) {
|
||||||
resetKeybindFile(i);
|
everythingIsOK &= resetKeybindFile(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < NUMBER_OF_KEYBINDS; i++) {
|
// LAUNCH APP
|
||||||
if (!std::filesystem::exists("data/config/keybinds/layout" + std::to_string(i) + ".bin")) {
|
|
||||||
std::cout << "INFO: Keybind file n°" << (i + 1) << "/" << NUMBER_OF_KEYBINDS << " not found, generating..." << std::endl;
|
|
||||||
resetKeybindFile(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GraphApp UI;
|
if (everythingIsOK) {
|
||||||
UI.run();
|
GraphApp UI;
|
||||||
|
UI.run();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << "ERROR: The game could not launch properly." << std::endl;
|
||||||
|
std::cout << "Press enter to quit. ";
|
||||||
|
std::cin.get();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void resetSettingsFile() {
|
bool resetSettingsFile() {
|
||||||
if (!std::filesystem::exists("data/config")) {
|
if (!std::filesystem::exists("data/config")) {
|
||||||
std::filesystem::create_directories("data/config");
|
std::filesystem::create_directories("data/config");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ofstream settingsFile("data/config/settings.bin", std::ios::trunc | std::ios::binary);
|
std::string filePath ="data/config/settings.bin";
|
||||||
char byte;
|
std::ofstream settingsFile(filePath, std::ios::trunc | std::ios::binary);
|
||||||
|
if (!settingsFile.good()) {
|
||||||
|
std::cerr << "ERROR: Could not open file " + filePath << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char byte;
|
||||||
Menu menu;
|
Menu menu;
|
||||||
|
|
||||||
// file format version
|
// file format version
|
||||||
byte = CURRENT_FILE_FORMAT_VERSION;
|
byte = CURRENT_FILE_FORMAT_VERSION;
|
||||||
settingsFile.write(&byte, 1);
|
settingsFile.write(&byte, 1);
|
||||||
|
|
||||||
// maximum pieces size
|
// loadable pieces size
|
||||||
byte = MINIMUM_PIECES_SIZE;
|
byte = MINIMUM_PIECES_SIZE;
|
||||||
settingsFile.write(&byte, 1);
|
settingsFile.write(&byte, 1);
|
||||||
|
|
||||||
@@ -132,16 +166,35 @@ void resetSettingsFile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// selected pieces
|
// selected pieces
|
||||||
byte = ALL_PIECES;
|
byte = DEFAULT_SELECTION.first;
|
||||||
settingsFile.write(&byte, 1);
|
settingsFile.write(&byte, 1);
|
||||||
byte = 4;
|
byte = DEFAULT_SELECTION.second;
|
||||||
settingsFile.write(&byte, 1);
|
settingsFile.write(&byte, 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetKeybindFile(int layout) {
|
bool resetKeybindFile(int layout) {
|
||||||
if (layout < 0 || layout > 4) return;
|
if (layout < 0 || layout > NUMBER_OF_KEYBINDS) {
|
||||||
|
std::cerr << "ERROR: Trying to create keybind layout number " << layout << " which is outside of range (" << NUMBER_OF_KEYBINDS << ")." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::filesystem::exists("data/config/keybinds")) {
|
||||||
|
std::filesystem::create_directories("data/config/keybinds");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filePath = "data/config/keybinds/layout" + std::to_string(layout) + ".bin";
|
||||||
|
std::ofstream layoutFile(filePath, std::ios::trunc | std::ios::binary);
|
||||||
|
if (!layoutFile.good()) {
|
||||||
|
std::cerr << "ERROR: Could not open file " + filePath << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layout == NUMBER_OF_KEYBINDS) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::ofstream layoutFile("data/config/keybinds/layout" + std::to_string(layout) + ".bin", std::ios::trunc | std::ios::binary);
|
|
||||||
std::map<Action, sfKey> keybinds;
|
std::map<Action, sfKey> keybinds;
|
||||||
|
|
||||||
if (layout != 4) {
|
if (layout != 4) {
|
||||||
@@ -207,4 +260,6 @@ void resetKeybindFile(int layout) {
|
|||||||
byte = 0xFF;
|
byte = 0xFF;
|
||||||
layoutFile.write(&byte, 1);
|
layoutFile.write(&byte, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,25 +11,25 @@
|
|||||||
Generator::Generator() {
|
Generator::Generator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Polyomino> Generator::generatePolyominoes(int polyominoSize) {
|
std::vector<Polyomino>&& Generator::generatePolyominoes(int polyominoSize) {
|
||||||
this->validPolyominoes.clear();
|
this->validPolyominoes.clear();
|
||||||
this->currentTestedShape.clear();
|
this->currentTestedShape.clear();
|
||||||
|
|
||||||
// a polyomino has at least 1 square
|
// a polyomino has at least 1 square
|
||||||
if (polyominoSize < 1) return this->validPolyominoes;
|
if (polyominoSize < 1) return std::move(this->validPolyominoes);
|
||||||
|
|
||||||
// always place the first cell at (0, 0)
|
// always place the first cell at (0, 0)
|
||||||
this->currentTestedShape.insert(Position{0, 0});
|
this->currentTestedShape.insert(Position(0, 0));
|
||||||
|
|
||||||
std::map<Position, int> candidatePositions;
|
std::map<Position, int> candidatePositions;
|
||||||
this->generate(polyominoSize, 0, 1, candidatePositions);
|
this->generate(polyominoSize, 0, 1, candidatePositions);
|
||||||
return this->validPolyominoes;
|
return std::move(this->validPolyominoes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Generator::generate(int polyominoSize, int lastAddedPositionNumber, int nextAvaibleNumber, std::map<Position, int> candidatePositions) {
|
void Generator::generate(unsigned polyominoSize, int lastAddedPositionNumber, int nextAvaibleNumber, std::map<Position, int> candidatePositions) {
|
||||||
// recursion stop
|
// recursion stop
|
||||||
if (polyominoSize == this->currentTestedShape.size()) {
|
if (polyominoSize == this->currentTestedShape.size()) {
|
||||||
Polyomino candidate(this->currentTestedShape);
|
Polyomino candidate(std::move(this->currentTestedShape));
|
||||||
|
|
||||||
// we sort the rotations of the polyominoes
|
// we sort the rotations of the polyominoes
|
||||||
std::vector<Polyomino> candidateRotations;
|
std::vector<Polyomino> candidateRotations;
|
||||||
@@ -51,14 +51,14 @@ void Generator::generate(int polyominoSize, int lastAddedPositionNumber, int nex
|
|||||||
|
|
||||||
// generate the list of candidate positions
|
// generate the list of candidate positions
|
||||||
for (const Position position : this->currentTestedShape) {
|
for (const Position position : this->currentTestedShape) {
|
||||||
this->tryToAddCandidatePosition(Position{position.x, position.y + 1}, nextAvaibleNumber, candidatePositions);
|
this->tryToAddCandidatePosition(Position(position.x, position.y + 1), nextAvaibleNumber, candidatePositions);
|
||||||
this->tryToAddCandidatePosition(Position{position.x + 1, position.y}, nextAvaibleNumber, candidatePositions);
|
this->tryToAddCandidatePosition(Position(position.x + 1, position.y), nextAvaibleNumber, candidatePositions);
|
||||||
this->tryToAddCandidatePosition(Position{position.x, position.y - 1}, nextAvaibleNumber, candidatePositions);
|
this->tryToAddCandidatePosition(Position(position.x, position.y - 1), nextAvaibleNumber, candidatePositions);
|
||||||
this->tryToAddCandidatePosition(Position{position.x - 1, position.y}, nextAvaibleNumber, candidatePositions);
|
this->tryToAddCandidatePosition(Position(position.x - 1, position.y), nextAvaibleNumber, candidatePositions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// try adding a square only to positions with a higher number than the last one
|
// try adding a square only to positions with a higher number than the last one
|
||||||
for (const auto [key, val] : candidatePositions) {
|
for (const auto& [key, val] : candidatePositions) {
|
||||||
if (val > lastAddedPositionNumber) {
|
if (val > lastAddedPositionNumber) {
|
||||||
this->currentTestedShape.insert(key);
|
this->currentTestedShape.insert(key);
|
||||||
this->generate(polyominoSize, val, nextAvaibleNumber, (polyominoSize == this->currentTestedShape.size()) ? std::map<Position, int>() : candidatePositions);
|
this->generate(polyominoSize, val, nextAvaibleNumber, (polyominoSize == this->currentTestedShape.size()) ? std::map<Position, int>() : candidatePositions);
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ class Generator {
|
|||||||
* Generates the list of all one-sided polyominoes of the specified size
|
* Generates the list of all one-sided polyominoes of the specified size
|
||||||
* @return The list of polyominoes
|
* @return The list of polyominoes
|
||||||
*/
|
*/
|
||||||
std::vector<Polyomino> generatePolyominoes(int polyominoSize);
|
std::vector<Polyomino>&& generatePolyominoes(int polyominoSize);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Generates all one-sided polyominoes of the specified size using the current tested shape
|
* Generates all one-sided polyominoes of the specified size using the current tested shape
|
||||||
*/
|
*/
|
||||||
void generate(int polyominoSize, int lastAddedPositionNumber, int nextAvaibleNumber, std::map<Position, int> candidatePositions);
|
void generate(unsigned polyominoSize, int lastAddedPositionNumber, int nextAvaibleNumber, std::map<Position, int> candidatePositions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks wheter a candidate position can be added to the current tested shape
|
* Checks wheter a candidate position can be added to the current tested shape
|
||||||
|
|||||||
@@ -9,11 +9,10 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
Piece::Piece(const Polyomino& polyomino, Block blockType) :
|
Piece::Piece(Polyomino&& polyomino, Block blockType) :
|
||||||
polyomino(polyomino),
|
polyomino(polyomino),
|
||||||
blockType(blockType) {
|
blockType(blockType),
|
||||||
|
rotationState(NONE) {
|
||||||
this->rotationState = NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Piece::rotate(Rotation rotation) {
|
void Piece::rotate(Rotation rotation) {
|
||||||
@@ -38,8 +37,8 @@ void Piece::defaultRotation() {
|
|||||||
this->rotationState = NONE;
|
this->rotationState = NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::set<Position>& Piece::getPositions() const {
|
const Polyomino& Piece::getPositions() const {
|
||||||
return this->polyomino.getPositions();
|
return this->polyomino;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Piece::getLength() const {
|
int Piece::getLength() const {
|
||||||
@@ -54,3 +53,7 @@ std::ostream& operator<<(std::ostream& os, const Piece& piece) {
|
|||||||
os << getConsoleColorCode(piece.blockType) << piece.polyomino << getResetConsoleColorCode();
|
os << getConsoleColorCode(piece.blockType) << piece.polyomino << getResetConsoleColorCode();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Piece::containsSquare(const Position& position) const {
|
||||||
|
return polyomino.contains(position);
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ class Piece {
|
|||||||
/**
|
/**
|
||||||
* Creates a piece with a specified shape and block type
|
* Creates a piece with a specified shape and block type
|
||||||
*/
|
*/
|
||||||
Piece(const Polyomino& piece, Block blockType);
|
Piece(Polyomino&& piece, Block blockType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotates the piece in the specified direction
|
* Rotates the piece in the specified direction
|
||||||
@@ -36,7 +36,13 @@ class Piece {
|
|||||||
/**
|
/**
|
||||||
* @return The list of positions of the piece
|
* @return The list of positions of the piece
|
||||||
*/
|
*/
|
||||||
const std::set<Position>& getPositions() const;
|
const Polyomino& getPositions() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param the position of the square
|
||||||
|
* @return false if there is a hole
|
||||||
|
*/
|
||||||
|
bool containsSquare(const Position& position) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The length of the piece
|
* @return The length of the piece
|
||||||
|
|||||||
@@ -50,11 +50,18 @@ bool PiecesFiles::savePieces(int polyominoSize, std::vector<Polyomino>& polyomin
|
|||||||
std::uint8_t infoByte = (isConvex << 7) + (hasHole << 6) + polyomino.getLength();
|
std::uint8_t infoByte = (isConvex << 7) + (hasHole << 6) + polyomino.getLength();
|
||||||
buffer << infoByte;
|
buffer << infoByte;
|
||||||
|
|
||||||
|
const int bitsNeeded = polyomino.getLength() * polyomino.getLength();
|
||||||
|
const int bytesNeeded = bitsNeeded / 8 + 1;
|
||||||
|
|
||||||
|
static const Polyomino::PolyominoData byteMask = 0xFF;
|
||||||
|
const Polyomino::PolyominoData& polyominoData = polyomino.getPositionsData();
|
||||||
|
|
||||||
// write the positions of the piece
|
// write the positions of the piece
|
||||||
std::uint8_t positionByte;
|
for (int i = 0; i < bytesNeeded; i++) {
|
||||||
for (const Position position : polyomino.getPositions()) {
|
Polyomino::PolyominoData pData = polyominoData >> (i * 8);
|
||||||
positionByte = (position.x << 4) + position.y;
|
unsigned long data =
|
||||||
buffer << positionByte;
|
(pData & byteMask).to_ulong();
|
||||||
|
buffer << static_cast<std::uint8_t>(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,13 +98,12 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
|
|||||||
nextPieceBlockType(pieceBlock);
|
nextPieceBlockType(pieceBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
char convexMask = 0b1000'0000;
|
constexpr char convexMask = 0b1000'0000;
|
||||||
char holeMask = 0b0100'0000;
|
constexpr char holeMask = 0b0100'0000;
|
||||||
char lengthMask = 0b0011'1111;
|
constexpr char lengthMask = 0b0011'1111;
|
||||||
char xMask = 0b1111'0000;
|
|
||||||
char yMask = 0b0000'1111;
|
|
||||||
|
|
||||||
std::uint8_t infoByte;
|
std::uint8_t infoByte;
|
||||||
|
std::uint8_t positionByte;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (!buffer.IsFinished()) {
|
while (!buffer.IsFinished()) {
|
||||||
// if (piecesFile.eof()) break;
|
// if (piecesFile.eof()) break;
|
||||||
@@ -108,21 +114,22 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
|
|||||||
bool hasHole = (infoByte & holeMask) >> 6;
|
bool hasHole = (infoByte & holeMask) >> 6;
|
||||||
int length = (infoByte & lengthMask);
|
int length = (infoByte & lengthMask);
|
||||||
|
|
||||||
|
const int bitsNeeded = length * length;
|
||||||
|
const int bytesNeeded = bitsNeeded / 8 + 1;
|
||||||
|
|
||||||
// read positions
|
// read positions
|
||||||
std::set<Position> piecePositions;
|
Polyomino::PolyominoData polyominoData{};
|
||||||
std::uint8_t positionByte;
|
|
||||||
for (int i = 0; i < polyominoSize; i++) {
|
for (int j = 0; j < bytesNeeded; j++) {
|
||||||
buffer >> positionByte;
|
buffer >> positionByte;
|
||||||
int x = ((unsigned char) positionByte & xMask) >> 4;
|
Polyomino::PolyominoData tempByte(positionByte);
|
||||||
int y = positionByte & yMask;
|
polyominoData |= (tempByte << (j * 8));
|
||||||
piecePositions.insert(Position{x, y});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create piece
|
pieces.emplace_back(Polyomino(std::move(polyominoData), length), pieceBlock);
|
||||||
Piece readPiece(Polyomino(piecePositions, length), pieceBlock);
|
|
||||||
nextPieceBlockType(pieceBlock);
|
nextPieceBlockType(pieceBlock);
|
||||||
|
|
||||||
pieces.push_back(readPiece);
|
|
||||||
if (isConvex) {
|
if (isConvex) {
|
||||||
convexPieces.push_back(i);
|
convexPieces.push_back(i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,21 +18,21 @@ class PiecesFiles {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a file containing all the pieces of the specified size
|
* Generate a file containing all the pieces of the specified size
|
||||||
* @return If the file could be created
|
* @return If the pieces are saved correctly
|
||||||
*/
|
*/
|
||||||
bool savePieces(int polyominoSize) const;
|
[[nodiscard]] bool savePieces(int polyominoSize) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a file containing all the pieces of the specified size, assuming they have been correctly generated
|
* Generate a file containing all the pieces of the specified size, assuming they have been correctly generated
|
||||||
* @return If the file could be created
|
* @return If the piece are saved correctly
|
||||||
*/
|
*/
|
||||||
bool savePieces(int polyominoSize, std::vector<Polyomino>& polyominoes) const;
|
[[nodiscard]] bool savePieces(int polyominoSize, std::vector<Polyomino>& polyominoes) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace the content of the vectors by the pieces of the specified size, if the file wasn't found the vectors stays untouched
|
* Replace the content of the vectors by the pieces of the specified size, if the pieces can't be loaded correctly the vectors stays untouched
|
||||||
* @return If the file was found
|
* @return If the pieces could be loaded correctly
|
||||||
*/
|
*/
|
||||||
bool loadPieces(int polyominoSize, std::vector<Piece>& pieces, std::vector<int>& convexPieces, std::vector<int>& holelessPieces, std::vector<int>& otherPieces) const;
|
[[nodiscard]] bool loadPieces(int polyominoSize, std::vector<Piece>& pieces, std::vector<int>& convexPieces, std::vector<int>& holelessPieces, std::vector<int>& otherPieces) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the path to the piece file of the specified size in order, if the data folder wasn't found the string stays untouched
|
* Puts the path to the piece file of the specified size in order, if the data folder wasn't found the string stays untouched
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
#include <climits>
|
#include <climits>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
Polyomino::Polyomino(std::set<Position>&& positions) : positions(0) {
|
||||||
Polyomino::Polyomino(const std::set<Position>& positions) {
|
|
||||||
int minX = INT_MAX;
|
int minX = INT_MAX;
|
||||||
int maxX = INT_MIN;
|
int maxX = INT_MIN;
|
||||||
int minY = INT_MAX;
|
int minY = INT_MAX;
|
||||||
@@ -25,71 +25,64 @@ Polyomino::Polyomino(const std::set<Position>& positions) {
|
|||||||
this->length = std::max(maxX - minX + 1, maxY - minY + 1);
|
this->length = std::max(maxX - minX + 1, maxY - minY + 1);
|
||||||
|
|
||||||
// we normalize here instead of calling this->normalize() to reduce the number of calculations for the generation algorithm
|
// we normalize here instead of calling this->normalize() to reduce the number of calculations for the generation algorithm
|
||||||
std::set<Position> newPositions;
|
Polyomino newPolyomino({}, this->length);
|
||||||
for (Position position : positions) {
|
for (Position position : positions) {
|
||||||
newPositions.insert(Position{position.x - minX, position.y - minY});
|
newPolyomino.insert(Position(position.x - minX, position.y - minY));
|
||||||
}
|
}
|
||||||
this->positions = std::move(newPositions);
|
this->positions = std::move(newPolyomino.positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
Polyomino::Polyomino(const std::set<Position>& positions, int length) :
|
Polyomino::Polyomino(PolyominoData&& positions, std::int8_t length) :
|
||||||
positions(positions),
|
positions(std::move(positions)),
|
||||||
length(length) {
|
length(length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Polyomino::normalize() {
|
void Polyomino::normalize() {
|
||||||
int minX = INT_MAX;
|
int minX = INT_MAX;
|
||||||
int minY = INT_MAX;
|
int minY = INT_MAX;
|
||||||
for (const Position position : this->positions) {
|
for (const Position position : *this) {
|
||||||
if (position.x < minX) minX = position.x;
|
if (position.x < minX) minX = position.x;
|
||||||
if (position.y < minY) minY = position.y;
|
if (position.y < minY) minY = position.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<Position> newPositions;
|
Polyomino newPolyomino({}, this->length);
|
||||||
for (const Position position : this->positions) {
|
for (const Position position : *this) {
|
||||||
newPositions.insert(Position{position.x - minX, position.y - minY});
|
newPolyomino.insert(Position(position.x - minX, position.y - minY));
|
||||||
}
|
}
|
||||||
this->positions = std::move(newPositions);
|
this->positions = std::move(newPolyomino.positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Polyomino::rotateCW() {
|
void Polyomino::rotateCW() {
|
||||||
std::set<Position> newPositions;
|
Polyomino temp({}, this->length);
|
||||||
for (const Position position : this->positions) {
|
for (const Position position : *this) {
|
||||||
newPositions.insert(Position{position.y, (length - 1) - (position.x)});
|
temp.insert(Position(position.y, (length - 1) - (position.x)));
|
||||||
}
|
}
|
||||||
this->positions = std::move(newPositions);
|
this->positions = std::move(temp.positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Polyomino::rotate180() {
|
void Polyomino::rotate180() {
|
||||||
std::set<Position> newPositions;
|
Polyomino temp({}, this->length);
|
||||||
for (const Position position : this->positions) {
|
for (const Position position : *this) {
|
||||||
newPositions.insert(Position{(length - 1) - (position.x), (length - 1) - (position.y)});
|
temp.insert(Position((length - 1) - (position.x), (length - 1) - (position.y)));
|
||||||
}
|
}
|
||||||
this->positions = std::move(newPositions);
|
this->positions = std::move(temp.positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Polyomino::rotateCCW() {
|
void Polyomino::rotateCCW() {
|
||||||
std::set<Position> newPositions;
|
Polyomino temp({}, this->length);
|
||||||
for (const Position position : this->positions) {
|
for (const Position position : *this) {
|
||||||
newPositions.insert(Position{(length - 1) - (position.y), position.x});
|
temp.insert(Position((length - 1) - (position.y), position.x));
|
||||||
}
|
}
|
||||||
this->positions = std::move(newPositions);
|
this->positions = std::move(temp.positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Polyomino::goToSpawnPosition() {
|
void Polyomino::goToSpawnPosition() {
|
||||||
// initialize array
|
// initialize array
|
||||||
std::vector<std::vector<int>> linesCompleteness;
|
std::vector<int> empty(this->length, 0);
|
||||||
linesCompleteness.reserve(4);
|
std::vector<std::vector<int>> linesCompleteness(4, empty);
|
||||||
std::vector<int> empty;
|
|
||||||
for (int j = 0; j < this->length; j++) {
|
|
||||||
empty.push_back(0);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
linesCompleteness.push_back(empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculates amount of squares per rows and columns
|
// calculates amount of squares per rows and columns
|
||||||
for (const Position position : this->positions) {
|
for (const Position position : *this) {
|
||||||
linesCompleteness.at(0).at(position.y) += 1; // 0 = bottom to top = no rotation
|
linesCompleteness.at(0).at(position.y) += 1; // 0 = bottom to top = no rotation
|
||||||
linesCompleteness.at(1).at((length - 1) - position.x) += 1; // 1 = right to left = CW
|
linesCompleteness.at(1).at((length - 1) - position.x) += 1; // 1 = right to left = CW
|
||||||
linesCompleteness.at(2).at((length - 1) - position.y) += 1; // 2 = top to bottom = 180
|
linesCompleteness.at(2).at((length - 1) - position.y) += 1; // 2 = top to bottom = 180
|
||||||
@@ -156,19 +149,20 @@ void Polyomino::goToSpawnPosition() {
|
|||||||
std::swap(verticalEmptyLines, horizontalEmptyLines);
|
std::swap(verticalEmptyLines, horizontalEmptyLines);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int minX = INT_MAX;
|
int minX = INT_MAX;
|
||||||
int minY = INT_MAX;
|
int minY = INT_MAX;
|
||||||
for (const Position position : this->positions) {
|
for (const Position position : *this) {
|
||||||
if (position.x < minX) minX = position.x;
|
if (position.x < minX) minX = position.x;
|
||||||
if (position.y < minY) minY = position.y;
|
if (position.y < minY) minY = position.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// center the piece with an up bias
|
// center the piece with an up bias
|
||||||
std::set<Position> newPositions;
|
Polyomino temp({}, this->length);
|
||||||
for (const Position position : positions) {
|
for (const Position position : *this) {
|
||||||
newPositions.insert(Position{(position.x - minX) + (verticalEmptyLines / 2), (position.y - minY) + ((horizontalEmptyLines + 1) / 2)});
|
temp.insert(Position((position.x - minX) + (verticalEmptyLines / 2), (position.y - minY) + ((horizontalEmptyLines + 1) / 2)));
|
||||||
}
|
}
|
||||||
this->positions = std::move(newPositions);
|
this->positions = std::move(temp.positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Polyomino::checkForFlattestSide(const std::vector<std::vector<int>>& linesCompleteness, bool currentFlattestSides[4], int& sideToBeOn, bool checkLeftSide) const {
|
void Polyomino::checkForFlattestSide(const std::vector<std::vector<int>>& linesCompleteness, bool currentFlattestSides[4], int& sideToBeOn, bool checkLeftSide) const {
|
||||||
@@ -216,7 +210,7 @@ bool Polyomino::isConvex() const {
|
|||||||
bool startedColumn = false;
|
bool startedColumn = false;
|
||||||
bool completedColumn = false;
|
bool completedColumn = false;
|
||||||
for (int i = 0; i < this->length; i++) {
|
for (int i = 0; i < this->length; i++) {
|
||||||
if (this->positions.contains(Position{i, j})) {
|
if (this->contains(Position(i, j))) {
|
||||||
if (completedLine) return false;
|
if (completedLine) return false;
|
||||||
else startedLine = true;
|
else startedLine = true;
|
||||||
}
|
}
|
||||||
@@ -224,7 +218,7 @@ bool Polyomino::isConvex() const {
|
|||||||
if (startedLine) completedLine = true;
|
if (startedLine) completedLine = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->positions.contains(Position{j, i})) {
|
if (this->contains(Position(j, i))) {
|
||||||
if (completedColumn) return false;
|
if (completedColumn) return false;
|
||||||
else startedColumn = true;
|
else startedColumn = true;
|
||||||
}
|
}
|
||||||
@@ -238,31 +232,31 @@ bool Polyomino::isConvex() const {
|
|||||||
|
|
||||||
bool Polyomino::hasHole() const {
|
bool Polyomino::hasHole() const {
|
||||||
// add every empty square on the outer of the box containing the polyomino
|
// add every empty square on the outer of the box containing the polyomino
|
||||||
std::set<Position> emptyPositions;
|
Polyomino temp({}, this->length);
|
||||||
for (int i = 0; i < this->length - 1; i++) {
|
for (int i = 0; i < this->length - 1; i++) {
|
||||||
this->tryToInsertPosition(emptyPositions, Position{i, 0}); // up row
|
this->tryToInsertPosition(temp, Position(i, 0)); // up row
|
||||||
this->tryToInsertPosition(emptyPositions, Position{this->length - 1, i}); // rigth column
|
this->tryToInsertPosition(temp, Position(this->length - 1, i)); // rigth column
|
||||||
this->tryToInsertPosition(emptyPositions, Position{this->length - 1 - i, this->length - 1}); // bottom row
|
this->tryToInsertPosition(temp, Position(this->length - 1 - i, this->length - 1)); // bottom row
|
||||||
this->tryToInsertPosition(emptyPositions, Position{0, this->length - 1 - i}); // left column
|
this->tryToInsertPosition(temp, Position(0, this->length - 1 - i)); // left column
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we didn't reached all empty squares in the box then there was some contained within the polyomino, i.e. there was a hole
|
// if we didn't reached all empty squares in the box then there was some contained within the polyomino, i.e. there was a hole
|
||||||
return (emptyPositions.size() < (this->length * this->length) - this->positions.size());
|
return (temp.getSize() < (this->length * this->length) - this->positions.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Polyomino::tryToInsertPosition(std::set<Position>& emptyPositions, const Position& candidate) const {
|
void Polyomino::tryToInsertPosition(Polyomino& emptyPositions, const Position& candidate) const {
|
||||||
if (candidate.x >= this->length || candidate.x < 0 || candidate.y >= this->length || candidate.y < 0) return;
|
if (candidate.x >= this->length || candidate.x < 0 || candidate.y >= this->length || candidate.y < 0) return;
|
||||||
if (this->positions.contains(candidate) || emptyPositions.contains(candidate)) return;
|
if (this->contains(candidate) || emptyPositions.contains(candidate)) return;
|
||||||
|
|
||||||
// if it's a new empty square, try its neighbors
|
// if it's a new empty square, try its neighbors
|
||||||
emptyPositions.insert(candidate);
|
emptyPositions.insert(candidate);
|
||||||
tryToInsertPosition(emptyPositions, Position{candidate.x, candidate.y + 1});
|
tryToInsertPosition(emptyPositions, Position(candidate.x, candidate.y + 1));
|
||||||
tryToInsertPosition(emptyPositions, Position{candidate.x + 1, candidate.y});
|
tryToInsertPosition(emptyPositions, Position(candidate.x + 1, candidate.y));
|
||||||
tryToInsertPosition(emptyPositions, Position{candidate.x, candidate.y - 1});
|
tryToInsertPosition(emptyPositions, Position(candidate.x, candidate.y - 1));
|
||||||
tryToInsertPosition(emptyPositions, Position{candidate.x - 1, candidate.y});
|
tryToInsertPosition(emptyPositions, Position(candidate.x - 1, candidate.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::set<Position>& Polyomino::getPositions() const {
|
const Polyomino::PolyominoData& Polyomino::getPositionsData() const {
|
||||||
return this->positions;
|
return this->positions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,13 +271,19 @@ int Polyomino::getPolyominoSize() const {
|
|||||||
bool Polyomino::operator<(const Polyomino& other) const {
|
bool Polyomino::operator<(const Polyomino& other) const {
|
||||||
if (this->length != other.length) return this->length < other.length;
|
if (this->length != other.length) return this->length < other.length;
|
||||||
|
|
||||||
for (int y = this->length - 1; y >= 0; y--) {
|
assert(other.positions.any() && "The other polyomino is empty !");
|
||||||
for (int x = 0; x < this->length; x++) {
|
|
||||||
bool hasThisPosition = this->positions.contains(Position{x, y});
|
static const PolyominoData longMask = 0xFFFFFFFFFFFFFFFF;
|
||||||
bool hasOtherPosition = other.positions.contains(Position{x, y});
|
const int longsNeeded = this->length * this->length / 64 + 1;
|
||||||
if (hasThisPosition != hasOtherPosition) return hasThisPosition;
|
|
||||||
|
for (int i = 0; i < longsNeeded; i++) {
|
||||||
|
unsigned long l1 = (this->positions >> (i * sizeof(std::uint64_t)) & longMask).to_ulong();
|
||||||
|
unsigned long l2 = (other.positions >> (i * sizeof(std::uint64_t)) & longMask).to_ulong();
|
||||||
|
if (l1 != l2) {
|
||||||
|
return l1 < l2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ bool Polyomino::operator==(const Polyomino& other) const {
|
|||||||
std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino) {
|
std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino) {
|
||||||
for (int y = polyomino.length - 1; y >= 0; y--) {
|
for (int y = polyomino.length - 1; y >= 0; y--) {
|
||||||
for (int x = 0; x < polyomino.length; x++) {
|
for (int x = 0; x < polyomino.length; x++) {
|
||||||
if (polyomino.positions.contains(Position{x, y})) {
|
if (polyomino.contains(Position(x, y))) {
|
||||||
os << "*";
|
os << "*";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -305,3 +305,31 @@ std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino) {
|
|||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Polyomino::getSize() const {
|
||||||
|
return positions.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Polyomino::contains(const Position& position) const {
|
||||||
|
return this->positions[getBitIndex(position)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Polyomino::insert(const Position& position) {
|
||||||
|
this->positions.set(getBitIndex(position), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Polyomino::erase(const Position& position) {
|
||||||
|
this->positions.set(getBitIndex(position), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t Polyomino::getBitIndex(const Position& position) const {
|
||||||
|
return position.y * this->length + position.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
Polyomino::ConstIterator Polyomino::begin() const {
|
||||||
|
return ConstIterator(*this, positions._Find_first());
|
||||||
|
}
|
||||||
|
|
||||||
|
Polyomino::ConstIterator Polyomino::end() const {
|
||||||
|
return ConstIterator(*this, positions.size());
|
||||||
|
}
|
||||||
@@ -5,26 +5,68 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <array>
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mathematical object consisting of touching squares on a 2D grid
|
* A mathematical object consisting of touching squares on a 2D grid
|
||||||
*/
|
*/
|
||||||
class Polyomino {
|
class Polyomino {
|
||||||
|
public:
|
||||||
|
static const std::size_t MAX_LENGTH = 16;
|
||||||
|
using PolyominoData = std::bitset<MAX_LENGTH * MAX_LENGTH>;
|
||||||
|
|
||||||
|
class ConstIterator {
|
||||||
|
public:
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using value_type = Position;
|
||||||
|
using const_pointer = const Position*; // or also value_type*
|
||||||
|
using const_reference = const Position&; // or also value_type&
|
||||||
|
public:
|
||||||
|
ConstIterator(const Polyomino& polyomino, std::size_t index) : m_Polyomino(polyomino), m_Index(index) {
|
||||||
|
updatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_reference operator*() const { return m_Position; }
|
||||||
|
const_pointer operator->() { return &m_Position; }
|
||||||
|
|
||||||
|
// Prefix increment
|
||||||
|
ConstIterator& operator++() {
|
||||||
|
m_Index = m_Polyomino.getPositionsData()._Find_next(m_Index);
|
||||||
|
updatePosition();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
friend bool operator== (const ConstIterator& a, const ConstIterator& b) { return a.m_Index == b.m_Index; };
|
||||||
|
friend bool operator!= (const ConstIterator& a, const ConstIterator& b) { return a.m_Index != b.m_Index; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updatePosition() {
|
||||||
|
m_Position = Position(m_Index % m_Polyomino.getLength(), m_Index / m_Polyomino.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
const Polyomino& m_Polyomino;
|
||||||
|
std::size_t m_Index;
|
||||||
|
Position m_Position;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<Position> positions; // the squares composing the polyomino, (0,0) is downleft
|
PolyominoData positions; // the squares composing the polyomino, stored in binary. MSB is downleft
|
||||||
int length; // the size of the smallest square box in which the polyomino can fit on any rotation
|
std::int8_t length; // the size of the smallest square box in which the polyomino can fit on any rotation
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* Creates a polyomino with the specified positions and normalizes it, wheter it is actually a polyonimo is not checked
|
|
||||||
*/
|
|
||||||
Polyomino(const std::set<Position>& positions);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a polyomino with the specified positions and length, wheter it is actually a polyonimo of this length is not checked
|
* Creates a polyomino with the specified positions and length, wheter it is actually a polyonimo of this length is not checked
|
||||||
*/
|
*/
|
||||||
Polyomino(const std::set<Position>& positions, int length);
|
Polyomino(PolyominoData&& positions, std::int8_t length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a polyomino with the specified positions and normalizes it, wheter it is actually a polyonimo is not checked
|
||||||
|
*/
|
||||||
|
Polyomino(std::set<Position>&& positions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates the polyomino to the lowest unsigned values (lower row on y = 0, and left-most column on x = 0)
|
* Translates the polyomino to the lowest unsigned values (lower row on y = 0, and left-most column on x = 0)
|
||||||
@@ -70,23 +112,33 @@ class Polyomino {
|
|||||||
*/
|
*/
|
||||||
bool hasHole() const;
|
bool hasHole() const;
|
||||||
|
|
||||||
private :
|
private:
|
||||||
/**
|
/**
|
||||||
* Auxiliary method of hasHole()
|
* Auxiliary method of hasHole()
|
||||||
*/
|
*/
|
||||||
void tryToInsertPosition(std::set<Position>& emptypositions, const Position& candidate) const;
|
void tryToInsertPosition(Polyomino& emptypositions, const Position& candidate) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @return The positions of the polyomino
|
* @return The positions data of the polyomino
|
||||||
*/
|
*/
|
||||||
const std::set<Position>& getPositions() const;
|
const PolyominoData& getPositionsData() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The length of the polyomino
|
* @return The length of the polyomino
|
||||||
*/
|
*/
|
||||||
int getLength() const;
|
int getLength() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int getSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::size_t getBitIndex(const Position& position) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The number of squares in the polyomino
|
* @return The number of squares in the polyomino
|
||||||
*/
|
*/
|
||||||
@@ -110,4 +162,23 @@ class Polyomino {
|
|||||||
* @return A reference to the output stream
|
* @return A reference to the output stream
|
||||||
*/
|
*/
|
||||||
friend std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino);
|
friend std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if it contains the position
|
||||||
|
*/
|
||||||
|
bool contains(const Position& position) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Insert a square at the position
|
||||||
|
*/
|
||||||
|
void insert(const Position& position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a square at the position
|
||||||
|
*/
|
||||||
|
void erase(const Position& position);
|
||||||
|
|
||||||
|
ConstIterator begin() const;
|
||||||
|
|
||||||
|
ConstIterator end() const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A position on a 2D grid
|
* A position on a 2D grid
|
||||||
*/
|
*/
|
||||||
struct Position {
|
struct Position {
|
||||||
int x; // x position
|
std::int8_t x; // x position
|
||||||
int y; // y position
|
std::int8_t y; // y position
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ struct Position {
|
|||||||
* @return The sums of the coordinates of both positions
|
* @return The sums of the coordinates of both positions
|
||||||
*/
|
*/
|
||||||
inline Position operator+(const Position& left, const Position& right) {
|
inline Position operator+(const Position& left, const Position& right) {
|
||||||
return Position{left.x + right.x, left.y + right.y};
|
return Position(left.x + right.x, left.y + right.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,7 +34,7 @@ inline Position& operator+=(Position& left, const Position& right) {
|
|||||||
* @return The difference of the coordinate between the left and right position
|
* @return The difference of the coordinate between the left and right position
|
||||||
*/
|
*/
|
||||||
inline Position operator-(const Position& left, const Position& right) {
|
inline Position operator-(const Position& left, const Position& right) {
|
||||||
return Position{left.x - right.x, left.y - right.y};
|
return Position(left.x - right.x, left.y - right.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -250,9 +250,9 @@ void TextApp::printGame(const Game& game) const {
|
|||||||
for (int y = maxHeight; y >= 0; y--) {
|
for (int y = maxHeight; y >= 0; y--) {
|
||||||
for (int x = 0; x < game.getBoard().getWidth(); x++) {
|
for (int x = 0; x < game.getBoard().getWidth(); x++) {
|
||||||
/* BOARD PRINTING */
|
/* BOARD PRINTING */
|
||||||
bool isActivePieceHere = (game.getActivePiece() != nullptr) && (game.getActivePiece()->getPositions().contains(Position{x, y} - game.getActivePiecePosition()));
|
bool isActivePieceHere = (game.getActivePiece() != nullptr) && (game.getActivePiece()->getPositions().contains(Position(x, y) - game.getActivePiecePosition()));
|
||||||
bool isGhostPieceHere = (game.getActivePiece() != nullptr) && (game.getActivePiece()->getPositions().contains(Position{x, y} - game.getGhostPiecePosition()));
|
bool isGhostPieceHere = (game.getActivePiece() != nullptr) && (game.getActivePiece()->getPositions().contains(Position(x, y) - game.getGhostPiecePosition()));
|
||||||
Block block = (isActivePieceHere || isGhostPieceHere) ? game.getActivePiece()->getBlockType() : game.getBoard().getBlock(Position{x, y});
|
Block block = (isActivePieceHere || isGhostPieceHere) ? game.getActivePiece()->getBlockType() : game.getBoard().getBlock(Position(x, y));
|
||||||
|
|
||||||
if (isActivePieceHere || isGhostPieceHere) {
|
if (isActivePieceHere || isGhostPieceHere) {
|
||||||
std::cout << getConsoleColorCode(block);
|
std::cout << getConsoleColorCode(block);
|
||||||
@@ -294,7 +294,7 @@ void TextApp::printGame(const Game& game) const {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (int i = 0; i < game.getHeldPiece()->getLength(); i++) {
|
for (int i = 0; i < game.getHeldPiece()->getLength(); i++) {
|
||||||
if (game.getHeldPiece()->getPositions().contains(Position{i, printedPieceLineHeight})) {
|
if (game.getHeldPiece()->getPositions().contains(Position(i, printedPieceLineHeight))) {
|
||||||
std::cout << getConsoleColorCode(game.getHeldPiece()->getBlockType()) << "*";
|
std::cout << getConsoleColorCode(game.getHeldPiece()->getBlockType()) << "*";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -316,7 +316,7 @@ void TextApp::printGame(const Game& game) const {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (int i = 0; i < game.getNextPieces().at(nextQueuePrintedPiece).getLength(); i++) {
|
for (int i = 0; i < game.getNextPieces().at(nextQueuePrintedPiece).getLength(); i++) {
|
||||||
if (game.getNextPieces().at(nextQueuePrintedPiece).getPositions().contains(Position{i, printedPieceLineHeight})) {
|
if (game.getNextPieces().at(nextQueuePrintedPiece).getPositions().contains(Position(i, printedPieceLineHeight))) {
|
||||||
std::cout << getConsoleColorCode(game.getNextPieces().at(nextQueuePrintedPiece).getBlockType()) << "*";
|
std::cout << getConsoleColorCode(game.getNextPieces().at(nextQueuePrintedPiece).getBlockType()) << "*";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -7,38 +7,35 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
static const int MAXIMUM_PIECES_SIZE = 10;
|
static const int MAXIMUM_PIECES_SIZE = 10;
|
||||||
static const int BENCHMARK_PIECES_SIZE = 15;
|
|
||||||
|
|
||||||
|
|
||||||
void testGeneratorForAllSizes(int max_size);
|
void testGeneratorForAllSizes(int max_size);
|
||||||
void testGeneratorForOneSize(int size);
|
void testGeneratorForOneSize(int size);
|
||||||
void printPiecesByTypesForOneSize(int size);
|
void printPiecesByTypesForOneSize(int size);
|
||||||
void readStatsFromFilesForAllSizes(int max_size);
|
void readStatsFromFilesForAllSizes(int max_size);
|
||||||
|
|
||||||
void benchmarking(int min_size, int max_size);
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
std::srand(std::time(NULL));
|
std::srand(std::time(NULL));
|
||||||
|
|
||||||
#ifdef BENCHMARK
|
// CHECK PIECES FILES
|
||||||
#ifdef DEBUG
|
|
||||||
std::cout << "IMPORTANT: You are currently in debug mode, debug mode has lowest optimization settings and thus yields worse benchmarking results, to switch to release mode, type 'xmake f -m debug'." << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
benchmarking(1, BENCHMARK_PIECES_SIZE);
|
PiecesFiles pf;
|
||||||
#else
|
bool warned = false;
|
||||||
PiecesFiles pf;
|
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
|
||||||
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
|
if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) {
|
||||||
if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) {
|
if (!warned) {
|
||||||
std::cout << "INFO: Pieces files for size " << i << " not found, generating..." << std::endl;
|
std::cout << "INFO: Pieces files for size " << i << " not found, generating..." << std::endl;
|
||||||
pf.savePieces(i);
|
warned = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TextApp UI;
|
pf.savePieces(i);
|
||||||
UI.run();
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
// LAUNCH APP
|
||||||
|
|
||||||
|
TextApp UI;
|
||||||
|
UI.run();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -119,66 +116,3 @@ void readStatsFromFilesForAllSizes(int max_size) {
|
|||||||
std::cout << "Others " << i << "-minos : " << otherPieces.size() << std::endl;
|
std::cout << "Others " << i << "-minos : " << otherPieces.size() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void benchmarking(int min_size, int max_size) {
|
|
||||||
using std::chrono::high_resolution_clock;
|
|
||||||
using std::chrono::duration_cast;
|
|
||||||
using std::chrono::duration;
|
|
||||||
using std::chrono::milliseconds;
|
|
||||||
|
|
||||||
std::cout << "| n | Number | Generation | File storing | File retrieving | File size |" << std::endl;
|
|
||||||
std::cout << "| -: | -: | :-: | :-: | :-: | -: |" << std::endl;
|
|
||||||
|
|
||||||
Generator gen;
|
|
||||||
PiecesFiles pf;
|
|
||||||
|
|
||||||
for (int i = min_size; i <= max_size; i++) {
|
|
||||||
std::cout << "| " << i;
|
|
||||||
|
|
||||||
auto t1 = high_resolution_clock::now();
|
|
||||||
std::vector<Polyomino> polyominoes = gen.generatePolyominoes(i);
|
|
||||||
auto t2 = high_resolution_clock::now();
|
|
||||||
duration<double, std::milli> ms_double = t2 - t1;
|
|
||||||
std::cout << " | " << polyominoes.size();
|
|
||||||
std::flush(std::cout);
|
|
||||||
std::cout << " | " << (int) ms_double.count() / 1000 << "s " << std::fmod(ms_double.count(), 1000) << "ms ";
|
|
||||||
std::flush(std::cout);
|
|
||||||
|
|
||||||
t1 = high_resolution_clock::now();
|
|
||||||
pf.savePieces(i, polyominoes);
|
|
||||||
t2 = high_resolution_clock::now();
|
|
||||||
ms_double = t2 - t1;
|
|
||||||
std::cout << " | " << (int) ms_double.count() / 1000 << "s " << std::fmod(ms_double.count(), 1000) << "ms ";
|
|
||||||
std::flush(std::cout);
|
|
||||||
|
|
||||||
polyominoes.clear();
|
|
||||||
polyominoes.shrink_to_fit();
|
|
||||||
|
|
||||||
std::vector<Piece> pieces;
|
|
||||||
std::vector<int> convexPieces;
|
|
||||||
std::vector<int> holelessPieces;
|
|
||||||
std::vector<int> otherPieces;
|
|
||||||
|
|
||||||
t1 = high_resolution_clock::now();
|
|
||||||
pf.loadPieces(i, pieces, convexPieces, holelessPieces, otherPieces);
|
|
||||||
t2 = high_resolution_clock::now();
|
|
||||||
ms_double = t2 - t1;
|
|
||||||
std::cout << " | " << (int) ms_double.count() / 1000 << "s " << std::fmod(ms_double.count(), 1000) << "ms ";
|
|
||||||
std::flush(std::cout);
|
|
||||||
|
|
||||||
pieces.clear();
|
|
||||||
pieces.shrink_to_fit();
|
|
||||||
convexPieces.clear();
|
|
||||||
convexPieces.shrink_to_fit();
|
|
||||||
holelessPieces.clear();
|
|
||||||
holelessPieces.shrink_to_fit();
|
|
||||||
otherPieces.clear();
|
|
||||||
otherPieces.shrink_to_fit();
|
|
||||||
|
|
||||||
std::string filePath;
|
|
||||||
pf.getFilePath(i, filePath);
|
|
||||||
int fileSize = std::filesystem::file_size(filePath);
|
|
||||||
std::cout << " | " << fileSize << " bytes |" << std::endl;
|
|
||||||
std::flush(std::cout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,30 +10,6 @@ static const unsigned char data_fonts_pressstart_prstartk_ttf[] = {
|
|||||||
#include <data/fonts/pressstart/prstartk.ttf.h>
|
#include <data/fonts/pressstart/prstartk.ttf.h>
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char data_images_keybinds_Rotate180_png[] = {
|
|
||||||
#include <data/images/keybinds/Rotate180.png.h>
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned char data_images_keybinds_Rotate0_png[] = {
|
|
||||||
#include <data/images/keybinds/Rotate0.png.h>
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned char data_images_keybinds_RotateCCW_png[] = {
|
|
||||||
#include <data/images/keybinds/RotateCCW.png.h>
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned char data_images_keybinds_Retry_png[] = {
|
|
||||||
#include <data/images/keybinds/Retry.png.h>
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned char data_images_keybinds_RotateCW_png[] = {
|
|
||||||
#include <data/images/keybinds/RotateCW.png.h>
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned char data_images_keybinds_Moveright_png[] = {
|
|
||||||
#include <data/images/keybinds/Moveright.png.h>
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned char data_images_keybinds_Harddrop_png[] = {
|
static const unsigned char data_images_keybinds_Harddrop_png[] = {
|
||||||
#include <data/images/keybinds/Harddrop.png.h>
|
#include <data/images/keybinds/Harddrop.png.h>
|
||||||
};
|
};
|
||||||
@@ -42,14 +18,38 @@ static const unsigned char data_images_keybinds_Moveleft_png[] = {
|
|||||||
#include <data/images/keybinds/Moveleft.png.h>
|
#include <data/images/keybinds/Moveleft.png.h>
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char data_images_keybinds_Hold_png[] = {
|
static const unsigned char data_images_keybinds_RotateCW_png[] = {
|
||||||
#include <data/images/keybinds/Hold.png.h>
|
#include <data/images/keybinds/RotateCW.png.h>
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char data_images_keybinds_RotateCCW_png[] = {
|
||||||
|
#include <data/images/keybinds/RotateCCW.png.h>
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char data_images_keybinds_Softdrop_png[] = {
|
static const unsigned char data_images_keybinds_Softdrop_png[] = {
|
||||||
#include <data/images/keybinds/Softdrop.png.h>
|
#include <data/images/keybinds/Softdrop.png.h>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const unsigned char data_images_keybinds_Moveright_png[] = {
|
||||||
|
#include <data/images/keybinds/Moveright.png.h>
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char data_images_keybinds_Rotate180_png[] = {
|
||||||
|
#include <data/images/keybinds/Rotate180.png.h>
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char data_images_keybinds_Hold_png[] = {
|
||||||
|
#include <data/images/keybinds/Hold.png.h>
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char data_images_keybinds_Rotate0_png[] = {
|
||||||
|
#include <data/images/keybinds/Rotate0.png.h>
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char data_images_keybinds_Retry_png[] = {
|
||||||
|
#include <data/images/keybinds/Retry.png.h>
|
||||||
|
};
|
||||||
|
|
||||||
static const unsigned char data_images_keybinds_Pause_png[] = {
|
static const unsigned char data_images_keybinds_Pause_png[] = {
|
||||||
#include <data/images/keybinds/Pause.png.h>
|
#include <data/images/keybinds/Pause.png.h>
|
||||||
};
|
};
|
||||||
@@ -57,16 +57,16 @@ static const unsigned char data_images_keybinds_Pause_png[] = {
|
|||||||
static const Asset assets[] = {
|
static const Asset assets[] = {
|
||||||
{data_fonts_pressstart_prstart_ttf, sizeof(data_fonts_pressstart_prstart_ttf)},
|
{data_fonts_pressstart_prstart_ttf, sizeof(data_fonts_pressstart_prstart_ttf)},
|
||||||
{data_fonts_pressstart_prstartk_ttf, sizeof(data_fonts_pressstart_prstartk_ttf)},
|
{data_fonts_pressstart_prstartk_ttf, sizeof(data_fonts_pressstart_prstartk_ttf)},
|
||||||
{data_images_keybinds_Rotate180_png, sizeof(data_images_keybinds_Rotate180_png)},
|
|
||||||
{data_images_keybinds_Rotate0_png, sizeof(data_images_keybinds_Rotate0_png)},
|
|
||||||
{data_images_keybinds_RotateCCW_png, sizeof(data_images_keybinds_RotateCCW_png)},
|
|
||||||
{data_images_keybinds_Retry_png, sizeof(data_images_keybinds_Retry_png)},
|
|
||||||
{data_images_keybinds_RotateCW_png, sizeof(data_images_keybinds_RotateCW_png)},
|
|
||||||
{data_images_keybinds_Moveright_png, sizeof(data_images_keybinds_Moveright_png)},
|
|
||||||
{data_images_keybinds_Harddrop_png, sizeof(data_images_keybinds_Harddrop_png)},
|
{data_images_keybinds_Harddrop_png, sizeof(data_images_keybinds_Harddrop_png)},
|
||||||
{data_images_keybinds_Moveleft_png, sizeof(data_images_keybinds_Moveleft_png)},
|
{data_images_keybinds_Moveleft_png, sizeof(data_images_keybinds_Moveleft_png)},
|
||||||
{data_images_keybinds_Hold_png, sizeof(data_images_keybinds_Hold_png)},
|
{data_images_keybinds_RotateCW_png, sizeof(data_images_keybinds_RotateCW_png)},
|
||||||
|
{data_images_keybinds_RotateCCW_png, sizeof(data_images_keybinds_RotateCCW_png)},
|
||||||
{data_images_keybinds_Softdrop_png, sizeof(data_images_keybinds_Softdrop_png)},
|
{data_images_keybinds_Softdrop_png, sizeof(data_images_keybinds_Softdrop_png)},
|
||||||
|
{data_images_keybinds_Moveright_png, sizeof(data_images_keybinds_Moveright_png)},
|
||||||
|
{data_images_keybinds_Rotate180_png, sizeof(data_images_keybinds_Rotate180_png)},
|
||||||
|
{data_images_keybinds_Hold_png, sizeof(data_images_keybinds_Hold_png)},
|
||||||
|
{data_images_keybinds_Rotate0_png, sizeof(data_images_keybinds_Rotate0_png)},
|
||||||
|
{data_images_keybinds_Retry_png, sizeof(data_images_keybinds_Retry_png)},
|
||||||
{data_images_keybinds_Pause_png, sizeof(data_images_keybinds_Pause_png)},
|
{data_images_keybinds_Pause_png, sizeof(data_images_keybinds_Pause_png)},
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -74,16 +74,16 @@ static const Asset assets[] = {
|
|||||||
static const std::map<std::string, AssetName> assetMap = {
|
static const std::map<std::string, AssetName> assetMap = {
|
||||||
{"data/fonts/pressstart/prstart.ttf", AssetName::data_fonts_pressstart_prstart_ttf},
|
{"data/fonts/pressstart/prstart.ttf", AssetName::data_fonts_pressstart_prstart_ttf},
|
||||||
{"data/fonts/pressstart/prstartk.ttf", AssetName::data_fonts_pressstart_prstartk_ttf},
|
{"data/fonts/pressstart/prstartk.ttf", AssetName::data_fonts_pressstart_prstartk_ttf},
|
||||||
{"data/images/keybinds/Rotate180.png", AssetName::data_images_keybinds_Rotate180_png},
|
|
||||||
{"data/images/keybinds/Rotate0.png", AssetName::data_images_keybinds_Rotate0_png},
|
|
||||||
{"data/images/keybinds/RotateCCW.png", AssetName::data_images_keybinds_RotateCCW_png},
|
|
||||||
{"data/images/keybinds/Retry.png", AssetName::data_images_keybinds_Retry_png},
|
|
||||||
{"data/images/keybinds/RotateCW.png", AssetName::data_images_keybinds_RotateCW_png},
|
|
||||||
{"data/images/keybinds/Moveright.png", AssetName::data_images_keybinds_Moveright_png},
|
|
||||||
{"data/images/keybinds/Harddrop.png", AssetName::data_images_keybinds_Harddrop_png},
|
{"data/images/keybinds/Harddrop.png", AssetName::data_images_keybinds_Harddrop_png},
|
||||||
{"data/images/keybinds/Moveleft.png", AssetName::data_images_keybinds_Moveleft_png},
|
{"data/images/keybinds/Moveleft.png", AssetName::data_images_keybinds_Moveleft_png},
|
||||||
{"data/images/keybinds/Hold.png", AssetName::data_images_keybinds_Hold_png},
|
{"data/images/keybinds/RotateCW.png", AssetName::data_images_keybinds_RotateCW_png},
|
||||||
|
{"data/images/keybinds/RotateCCW.png", AssetName::data_images_keybinds_RotateCCW_png},
|
||||||
{"data/images/keybinds/Softdrop.png", AssetName::data_images_keybinds_Softdrop_png},
|
{"data/images/keybinds/Softdrop.png", AssetName::data_images_keybinds_Softdrop_png},
|
||||||
|
{"data/images/keybinds/Moveright.png", AssetName::data_images_keybinds_Moveright_png},
|
||||||
|
{"data/images/keybinds/Rotate180.png", AssetName::data_images_keybinds_Rotate180_png},
|
||||||
|
{"data/images/keybinds/Hold.png", AssetName::data_images_keybinds_Hold_png},
|
||||||
|
{"data/images/keybinds/Rotate0.png", AssetName::data_images_keybinds_Rotate0_png},
|
||||||
|
{"data/images/keybinds/Retry.png", AssetName::data_images_keybinds_Retry_png},
|
||||||
{"data/images/keybinds/Pause.png", AssetName::data_images_keybinds_Pause_png},
|
{"data/images/keybinds/Pause.png", AssetName::data_images_keybinds_Pause_png},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,16 +11,16 @@ struct Asset {
|
|||||||
enum class AssetName {
|
enum class AssetName {
|
||||||
data_fonts_pressstart_prstart_ttf,
|
data_fonts_pressstart_prstart_ttf,
|
||||||
data_fonts_pressstart_prstartk_ttf,
|
data_fonts_pressstart_prstartk_ttf,
|
||||||
data_images_keybinds_Rotate180_png,
|
|
||||||
data_images_keybinds_Rotate0_png,
|
|
||||||
data_images_keybinds_RotateCCW_png,
|
|
||||||
data_images_keybinds_Retry_png,
|
|
||||||
data_images_keybinds_RotateCW_png,
|
|
||||||
data_images_keybinds_Moveright_png,
|
|
||||||
data_images_keybinds_Harddrop_png,
|
data_images_keybinds_Harddrop_png,
|
||||||
data_images_keybinds_Moveleft_png,
|
data_images_keybinds_Moveleft_png,
|
||||||
data_images_keybinds_Hold_png,
|
data_images_keybinds_RotateCW_png,
|
||||||
|
data_images_keybinds_RotateCCW_png,
|
||||||
data_images_keybinds_Softdrop_png,
|
data_images_keybinds_Softdrop_png,
|
||||||
|
data_images_keybinds_Moveright_png,
|
||||||
|
data_images_keybinds_Rotate180_png,
|
||||||
|
data_images_keybinds_Hold_png,
|
||||||
|
data_images_keybinds_Rotate0_png,
|
||||||
|
data_images_keybinds_Retry_png,
|
||||||
data_images_keybinds_Pause_png,
|
data_images_keybinds_Pause_png,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,9 +22,8 @@ target("text")
|
|||||||
target("bmark")
|
target("bmark")
|
||||||
set_default(false)
|
set_default(false)
|
||||||
set_kind("binary")
|
set_kind("binary")
|
||||||
add_files("./src/TextUI/*.cpp")
|
add_files("./src/Benchmark/*.cpp")
|
||||||
add_deps("core")
|
add_deps("core")
|
||||||
add_defines("BENCHMARK")
|
|
||||||
|
|
||||||
target("graph")
|
target("graph")
|
||||||
set_default(true)
|
set_default(true)
|
||||||
|
|||||||
Reference in New Issue
Block a user