20 Commits

Author SHA1 Message Date
a836dd31e2 fix exec path
All checks were successful
Linux arm64 / Build (push) Successful in 2m13s
2025-07-29 21:36:18 +02:00
94e5450a74 fix icon path 2025-07-29 21:36:01 +02:00
7977fb976b nsis packaging
All checks were successful
Linux arm64 / Build (push) Successful in 2m16s
2025-07-29 21:13:10 +02:00
86a034a4ac update flatpak metainfo
All checks were successful
Linux arm64 / Build (push) Successful in 2m13s
2025-07-28 10:31:06 +02:00
9208a5750d zip windows packing 2025-07-28 10:29:42 +02:00
7301c40ba9 fix mingw build
All checks were successful
Linux arm64 / Build (push) Successful in 2m13s
2025-07-25 11:54:58 +02:00
792bf73e79 split xmake module in its own file
All checks were successful
Linux arm64 / Build (push) Successful in 2m15s
2025-07-25 10:50:38 +02:00
c9d5cc35ff fix config save (flatpak)
All checks were successful
Linux arm64 / Build (push) Successful in 2m12s
2025-07-25 10:22:45 +02:00
7040ce3381 add flatpak metadata
All checks were successful
Linux arm64 / Build (push) Successful in 2m30s
2025-07-24 17:45:44 +02:00
508405b00c fix desktop file
All checks were successful
Linux arm64 / Build (push) Successful in 2m17s
2025-07-24 15:12:55 +02:00
6dbcc717f7 fix normal build 2025-07-24 15:12:48 +02:00
19d953891b working flatpak
Some checks failed
Linux arm64 / Build (push) Failing after 1m47s
2025-07-24 14:54:26 +02:00
161c9425ae add table of contents to readme
All checks were successful
Linux arm64 / Build (push) Successful in 2m29s
2025-07-03 12:56:32 +02:00
561b6d76b8 add diagrams
All checks were successful
Linux arm64 / Build (push) Successful in 3m51s
2025-07-02 17:43:35 +02:00
b276213794 add diagrams 2025-07-02 17:43:28 +02:00
7b5801e630 readme completed 2025-07-02 16:40:41 +02:00
e676cd19f6 fixed line scoring
All checks were successful
Linux arm64 / Build (push) Successful in 12m32s
2025-06-21 16:53:24 +02:00
8342bf3969 petits [[nodiscard]] pour le fun
All checks were successful
Linux arm64 / Build (push) Successful in 12m30s
2025-06-19 22:31:41 +02:00
34d781fcfe better main
All checks were successful
Linux arm64 / Build (push) Successful in 12m32s
2025-06-19 19:13:43 +02:00
b17a40fda5 benchmark de simon
All checks were successful
Linux arm64 / Build (push) Successful in 3m14s
2025-06-19 15:55:15 +02:00
34 changed files with 563 additions and 341 deletions

5
.gitignore vendored
View File

@@ -17,3 +17,8 @@ doc/mockups/*
data/pieces/*.bin
data/config/*.bin
data/config/keybinds/*.bin
# flatpak files
flatpak/.flatpak-builder
flatpak/builddir
flatpak/repo

View File

@@ -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/)!
- [Download](#download)
- [How to play](#how-to-play)
- [Features](#features)
- [Manual build](#manual-build)
- [Benchmarks](#benchmarks)
- [Credits](#credits)
## Download
// TODO when the game is finished //
This game has been tested on and built for Windows 11 and WSL2 Ubuntu.
If your OS isn't compactible with either of theses two, you can try [manually building the project](#manual-build).
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.
If your OS isn't compatible, you can try [manually building the project](#manual-build).
## How to play
@@ -44,22 +50,28 @@ You will find more infos about the Rotation System, the scoring system, or the d
### Screenshots
Pentedecamino jumpscare
![](./doc/readme/big_piece.png)
![Screenshot1](./doc/readme/big_piece.png)
Pieces select screen
![](./doc/readme/pieces_selection.png)
![Screenshot2](./doc/readme/pieces_selection.png)
AutoRS demonstration
![](./doc/readme/rotations.gif)
![Video1](./doc/readme/rotations.gif)
0° spins demonstration
![](./doc/readme/rotation_0.gif)
![Video2](./doc/readme/rotation_0.gif)
## Manual build
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.
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
``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):
``xmake f --toolchain=gcc``
If you want to build for another platform (for example with mingw):
``xmake f -p mingw``
### Run the project
``xmake run``
@@ -79,13 +94,20 @@ To switch between debug and release mode:
``xmake f -m debug``
``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 run text``
The command line version is **not** updated.
### 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
@@ -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 |
| -: | -: | :-: | :-: | :-: | -: |
| 1 | 1 | 0s 0.005622ms | 0s 0.750955ms | 0s 0.014016ms | 2 bytes |
| 2 | 1 | 0s 0.005758ms | 0s 0.181323ms | 0s 0.012256ms | 3 bytes |
| 3 | 2 | 0s 0.017525ms | 0s 0.054497ms | 0s 0.006431ms | 8 bytes |
| 4 | 7 | 0s 0.050554ms | 0s 0.067617ms | 0s 0.010984ms | 35 bytes |
| 5 | 18 | 0s 0.191971ms | 0s 0.109905ms | 0s 0.021234ms | 108 bytes |
| 6 | 60 | 0s 0.651757ms | 0s 0.327465ms | 0s 0.04558ms | 420 bytes |
| 7 | 196 | 0s 3.38847ms | 0s 1.94434ms | 0s 0.258777ms | 1568 bytes |
| 8 | 704 | 0s 22.7411ms | 0s 10.0103ms | 0s 1.34813ms | 6336 bytes |
| 9 | 2500 | 0s 66.2949ms | 0s 20.6137ms | 0s 2.56374ms | 25000 bytes |
| 10 | 9189 | 0s 194.764ms | 0s 84.5884ms | 0s 9.64467ms | 101079 bytes |
| 11 | 33896 | 0s 759.182ms | 0s 378.494ms | 0s 44.1424ms | 406752 bytes |
| 12 | 126759 | 2s 709.277ms | 1s 530.34ms | 0s 155ms | 1647867 bytes |
| 13 | 476270 | 10s 668.308ms | 7s 395.512ms | 0s 765.601ms | 6667780 bytes |
| 14 | 1802312 | 45s 606.597ms | 32s 28.7977ms | 2s 919.653ms | 27034680 bytes |
| 15 | ~6M | ~5mn | ~5mn | ~10s | ~100 MB |
| 1 | 1 | 0s 0.005471ms | 0s 0.14436ms | 0s 0.022223ms | 3 bytes |
| 2 | 1 | 0s 0.006979ms | 0s 0.036624ms | 0s 0.011424ms | 4 bytes |
| 3 | 2 | 0s 0.018718ms | 0s 0.035885ms | 0s 0.013246ms | 9 bytes |
| 4 | 7 | 0s 0.060544ms | 0s 0.056277ms | 0s 0.019395ms | 36 bytes |
| 5 | 18 | 0s 0.220348ms | 0s 0.166593ms | 0s 0.036526ms | 76 bytes |
| 6 | 60 | 0s 0.773924ms | 0s 0.283423ms | 0s 0.063492ms | 186 bytes |
| 7 | 196 | 0s 3.00331ms | 0s 0.827344ms | 0s 0.163653ms | 546 bytes |
| 8 | 704 | 0s 13.142ms | 0s 3.68255ms | 0s 0.630044ms | 1898 bytes |
| 9 | 2500 | 0s 50.9272ms | 0s 16.1929ms | 0s 2.35157ms | 6889 bytes |
| 10 | 9189 | 0s 204.031ms | 0s 87.1819ms | 0s 10.5841ms | 25302 bytes |
| 11 | 33896 | 0s 832.82ms | 0s 412.466ms | 0s 57.6399ms | 93711 bytes |
| 12 | 126759 | 3s 425.907ms | 1s 982.715ms | 0s 226.816ms | 350325 bytes |
| 13 | 476270 | 14s 570.595ms | 9s 945.511ms | 0s 972.036ms | 1327156 bytes |
| 14 | 1802312 | 56s 394.426ms | 41s 675.672ms | 4s 79.0436ms | 5035148 bytes |
| 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._
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:
``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.
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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -2,11 +2,11 @@
## 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.
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.
@@ -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),
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.
If the file starts with a number lower than that, it will be regenerated upon launching the game.
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.

View File

@@ -1,7 +1,7 @@
# Game logic
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

2
flatpak/FlatpakLaunch.sh Normal file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
JMINOS_DATA="/app/share" JMINOS_CONFIG=$XDG_CONFIG_HOME /app/bin/graph

View File

@@ -0,0 +1,9 @@
[Desktop Entry]
Type=Application
Version=1.0
Name=Jminos
Exec=/usr/bin/graph
Icon=org.zulianc.jminos
Terminal=false
Categories=Game;
Comment=Amazing stacker game by the J

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>org.zulianc.jminos</id>
<launchable type="desktop-id">org.zulianc.jminos.desktop</launchable>
<name>jminos</name>
<developer_name>Zulianc</developer_name>
<summary>Amazing stacker game by the J </summary>
<!-- <metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-only</project_license> -->
<url type="homepage">https://git.ale-pri.com/TetrisNerd/jminos</url>
<description>
<p>
Modern stacker game with every polyominoes from size 1 to 15, made in C++ with SFML 3!
</p>
<p>Features</p>
<ul>
<li>Every polyominoes up to pentedecaminoes!</li>
<li>7bag with proportionnality for each polyomino size!</li>
<li>AutoRS as the Rotation System!</li>
<li>0° rotations!</li>
<li>All spin!</li>
<li>IRS, IHS, infinite hold, and other leniency mechanics!</li>
<li>Customizable board size!</li>
<li>Customizable keybinds!</li>
<li>Very bland interface!! (i'm not a designer)</li>
</ul>
<p>Available gamemodes</p>
<ul>
<li>SPRINT : clear 40 lines as fast as possible!</li>
<li>MARATHON : clear 200 lines with increasing gravity!</li>
<li>ULTRA : scores as much as possible in only 2 minutes!</li>
<li>MASTER : clear 200 lines at levels higher than maximum gravity!</li>
<li>INVISIBLE : get 1000 grade while not being able to see the board!</li>
<li>ZEN : practice indefinitely in this mode with no gravity!</li>
</ul>
</description>
<launchable type="desktop-id">
org.zulianc.jminos.desktop
</launchable>
<categories>
<category>Game</category>
</categories>
<screenshots>
<screenshot type="default">
<caption>Big piece</caption>
<image>https://git.ale-pri.com/TetrisNerd/jminos/raw/branch/main/doc/readme/big_piece.png</image>
</screenshot>
<screenshot>
<caption>Pieces selection</caption>
<image>https://git.ale-pri.com/TetrisNerd/jminos/media/branch/main/doc/readme/pieces_selection.png</image>
</screenshot>
<screenshot>
<caption>Rotations</caption>
<image>https://git.ale-pri.com/TetrisNerd/jminos/media/branch/main/doc/readme/rotations.gif</image>
</screenshot>
<screenshot>
<caption>Rotation_0</caption>
<image>https://git.ale-pri.com/TetrisNerd/jminos/media/branch/main/doc/readme/rotation_0.gif</image>
</screenshot>
</screenshots>
<releases>
<release version="1.0" date="2025-07-02">
<url>https://git.ale-pri.com/TetrisNerd/jminos/src/tag/v1.0/</url>
<description>
Inital release
</description>
</release>
</releases>
<content_rating type="oars-1.1" />
</component>

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,31 @@
app-id: org.zulianc.jminos
runtime: org.freedesktop.Platform
runtime-version: "24.08"
sdk: org.freedesktop.Sdk
command: FlatpakLaunch.sh
finish-args:
- --socket=x11
- --device=dri
modules:
- xmake.yml
- name: jminos
buildsystem: simple
build-options:
build-args:
- --share=network
build-commands:
- xmake f --policies=package.install_locally --external_build=y -m release -y
- xmake
- xmake install -o output
- install -D output/bin/* /app/bin
- cp -r output/data /app/share
- install -D flatpak/FlatpakLaunch.sh /app/bin
- install -D -t /app/share/applications flatpak/${FLATPAK_ID}.desktop
- install -Dm644 flatpak/${FLATPAK_ID}.metainfo.xml /app/share/metainfo/${FLATPAK_ID}.metainfo.xml
- install -D flatpak/${FLATPAK_ID}.png /app/share/icons/hicolor/512x512/apps/${FLATPAK_ID}.png
sources:
- type: dir
path: ..

12
flatpak/xmake.yml Normal file
View File

@@ -0,0 +1,12 @@
name: xmake
buildsystem: simple
no-autogen: true
cleanup: ['*']
build-commands:
- ./configure --prefix=/app
- make -j $(FLATPAK_BUILDER_N_JOBS)
- prefix=/app ./scripts/get.sh __local__ __install_only__
sources:
- type: git
url: https://github.com/xmake-io/xmake.git
tag: v3.0.1

102
src/Benchmark/main.cpp Normal file
View 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);
}
}

View File

@@ -297,8 +297,8 @@ void Game::lockPiece() {
/* clearing one more line is worth 2x more
clearing with a spin is worth as much as clearing 2x more lines */
long int clearScore = LINE_CLEAR_BASE_SCORE;
clearScore = clearScore << (clear.lines << (clear.isSpin));
long int clearScore = LINE_CLEAR_BASE_SCORE / 2;
clearScore = clearScore << (clear.lines << clear.isSpin);
if (this->B2BChain && B2BConditionsAreMet) {
clearScore *= B2B_SCORE_MULTIPLIER;

View File

@@ -4,7 +4,7 @@
#include "Player.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
/**

View File

@@ -27,13 +27,12 @@ PiecesList::PiecesList() {
this->pushBackEmptyVectors();
}
bool PiecesList::loadPieces(int size) {
if (size < 1) return false;
if (size <= this->highestLoadedSize) return true;
bool PiecesList::loadPieces(int max_size) {
if (max_size < 1) return false;
if (max_size <= this->highestLoadedSize) return true;
PiecesFiles piecesFiles;
for (int i = this->highestLoadedSize + 1; i <= size; i++) {
for (int 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))) {
return false;
}

View File

@@ -30,10 +30,10 @@ class PiecesList {
PiecesList();
/**
* Makes the list load all pieces of the specified size
* @return If it sucessfully loaded the pieces
* Makes the list load all pieces up to the specified size
* @return If all pieces up to the specified size are correctly loaded
*/
bool loadPieces(int size);
[[nodiscard]] bool loadPieces(int max_size);
/**
* Selects the specified piece

View File

@@ -15,9 +15,7 @@ AppMenu::AppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings>
settings(settings),
renderWindow(renderWindow) {
const Asset& file = getResource(AssetName::data_fonts_pressstart_prstartk_ttf);
this->pressStartFont = sf::Font(file.data, file.size);
this->pressStartFont = sf::Font(AssetManager::getResourcePath("data/fonts/pressstart/prstart.ttf"));
}
void AppMenu::updateMetaBinds() {

View File

@@ -12,7 +12,7 @@ GameDistributionAppMenu::GameDistributionAppMenu(std::shared_ptr<MenuStack> menu
AppMenu(menuStack, settings, renderWindow),
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);
}
}
@@ -65,7 +65,7 @@ void GameDistributionAppMenu::drawFrame() const {
const DistributionMode distributionMode = this->settings->getMenu().readPiecesList().getDistributionMode();
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) {
this->placeText(text, this->playerCursor, "< DISTRIBUTION MODE: " + getPiecesDistributionName(distributionMode) + " >", 5.f, 15.f, sf::Vector2u{0, 0});
}

View File

@@ -13,12 +13,12 @@ GamePiecesAppMenu::GamePiecesAppMenu(std::shared_ptr<MenuStack> menuStack, std::
AppMenu(menuStack, settings, renderWindow),
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);
}
if (this->settings->getMaximumPiecesSize() < MAXIMUM_PIECES_SIZE) {
this->playerCursor.addRow(this->settings->getMaximumPiecesSize() + 2, 1);
if (this->settings->getLoadablePiecesSize() < MAXIMUM_PIECES_SIZE) {
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));
}
if (this->playerCursor.getPosition().y == (this->settings->getMaximumPiecesSize() + 2)) {
int newMaxSize = this->settings->getMaximumPiecesSize() + 1;
if (this->playerCursor.getPosition().y == (this->settings->getLoadablePiecesSize() + 2)) {
int newMaxSize = this->settings->getLoadablePiecesSize() + 1;
this->settings->loadPieces(newMaxSize);
this->playerCursor.removeRow(newMaxSize + 1);
@@ -95,8 +95,8 @@ void GamePiecesAppMenu::drawFrame() const {
this->drawSelectedPiecesRow(15.f);
bool drawFromFirstElem = (this->playerCursor.getPosition().y == 1);
bool addExtraLine = (this->settings->getMaximumPiecesSize() < MAXIMUM_PIECES_SIZE);
int firstElem = std::clamp(((int) this->playerCursor.getPosition().y) - 2, 1, this->settings->getMaximumPiecesSize() - 2 + (addExtraLine ? 1 : 0));
bool addExtraLine = (this->settings->getLoadablePiecesSize() < MAXIMUM_PIECES_SIZE);
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 + 1, 35.f, drawFromFirstElem);
this->drawRow(firstElem + 2, 45.f, drawFromFirstElem);
@@ -130,7 +130,7 @@ void GamePiecesAppMenu::drawSelectedPiecesRow(float yPos) const {
int pieceSize = getSizeOfPieces(pieceType);
if (pieceSize > 0) {
if (!(pieceSize > this->settings->getMaximumPiecesSize())) {
if (!(pieceSize > this->settings->getLoadablePiecesSize())) {
const Piece& piece = this->settings->getMenu().readPiecesList().lookAtPiece({pieceSize, value});
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());
@@ -143,7 +143,7 @@ void GamePiecesAppMenu::drawSelectedPiecesRow(float yPos) const {
}
}
else {
if (!(value > this->settings->getMaximumPiecesSize())) {
if (!(value > this->settings->getLoadablePiecesSize())) {
this->placeText(text, {}, ((first) ? "" : " ") + getPiecesTypeName(pieceType) + "_" + std::to_string(value), xProgress, yPos, {});
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 {
if (piecesSize > this->settings->getMaximumPiecesSize()) {
if (piecesSize > this->settings->getLoadablePiecesSize()) {
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier() * 2);
text.setOutlineThickness(this->settings->getWindowSizeMultiplier() / 2);
if (this->playerCursor.getPosition().y == (piecesSize + 1)) {

View File

@@ -23,9 +23,7 @@ SettingsKeybindsAppMenu::SettingsKeybindsAppMenu(std::shared_ptr<MenuStack> menu
std::string textureName = ACTION_NAMES[action];
textureName = std::regex_replace(textureName, std::regex(" "), "");
const Asset& textureData = getResource("data/images/keybinds/" + textureName + ".png");
this->iconTextures[action] = sf::Texture(textureData.data, textureData.size, false, {{0, 0}, {16, 16}});
this->iconTextures[action] = sf::Texture(AssetManager::getResourcePath("data/images/keybinds/" + textureName + ".png"), false, {{0, 0}, {16, 16}});
}
}

View File

@@ -14,7 +14,7 @@ StartUpAppMenu::StartUpAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared
AppMenu(menuStack, settings, renderWindow),
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() {

View File

@@ -6,6 +6,7 @@
#include <set>
#include <fstream>
#include <SFML/Graphics.hpp>
#include "../Utils/AssetManager.h"
Keybinds::Keybinds(int layoutNumber) :
@@ -20,7 +21,7 @@ Keybinds::Keybinds(int layoutNumber) :
}
void Keybinds::loadKeybindsFromFile() {
std::ifstream layoutFile("data/config/keybinds/layout" + std::to_string(this->layoutNumber) + ".bin", std::ios::binary);
std::ifstream layoutFile(AssetManager::getConfigPath("data/config/keybinds/layout" + std::to_string(this->layoutNumber) + ".bin"), std::ios::binary);
for (Action action : ACTION_LIST_IN_ORDER) {
this->keybinds.at(action).clear();
@@ -47,7 +48,7 @@ void Keybinds::loadKeybindsFromFile() {
void Keybinds::saveKeybindsToFile() const {
if (!this->modifiable) return;
std::ofstream layoutFile("data/config/keybinds/layout" + std::to_string(this->layoutNumber) + ".bin", std::ios::trunc | std::ios::binary);
std::ofstream layoutFile(AssetManager::getConfigPath("data/config/keybinds/layout" + std::to_string(this->layoutNumber) + ".bin"), std::ios::trunc | std::ios::binary);
char byte;
for (Action action : ACTION_LIST_IN_ORDER) {

View File

@@ -3,6 +3,7 @@
#include "../Core/Menu.h"
#include "Keybinds.h"
#include "PiecesType.h"
#include "../Utils/AssetManager.h"
#include <vector>
#include <optional>
@@ -27,41 +28,41 @@ Settings::Settings(bool loadPieces) {
this->loadSettingsFromFile(loadPieces, {});
}
void Settings::loadPieces(int maximumPiecesSizeRequest) {
if (maximumPiecesSizeRequest < MINIMUM_PIECES_SIZE) {
maximumPiecesSizeRequest = MINIMUM_PIECES_SIZE;
void Settings::loadPieces(int loadablePiecesSizeRequest) {
if (loadablePiecesSizeRequest < MINIMUM_PIECES_SIZE) {
loadablePiecesSizeRequest = MINIMUM_PIECES_SIZE;
}
else if (maximumPiecesSizeRequest > MAXIMUM_PIECES_SIZE) {
maximumPiecesSizeRequest = MAXIMUM_PIECES_SIZE;
else if (loadablePiecesSizeRequest > MAXIMUM_PIECES_SIZE) {
loadablePiecesSizeRequest = MAXIMUM_PIECES_SIZE;
}
bool succeeded = true;
int i = 1;
while (succeeded && (i <= maximumPiecesSizeRequest)) {
while (succeeded && (i <= loadablePiecesSizeRequest)) {
succeeded = this->menu.getPiecesList().loadPieces(i);
i++;
}
if (succeeded) {
this->maximumPiecesSize = maximumPiecesSizeRequest;
this->loadablePiecesSize = loadablePiecesSizeRequest;
}
this->loadedPieces = succeeded;
}
void Settings::loadSettingsFromFile(bool loadPieces, std::optional<int> maximumPiecesSizeRequest) {
std::ifstream settingsFile("data/config/settings.bin", std::ios::binary);
void Settings::loadSettingsFromFile(bool loadPieces, std::optional<int> loadablePiecesSizeRequest) {
std::ifstream settingsFile(AssetManager::getConfigPath("data/config/settings.bin"), std::ios::binary);
char byte;
// file format version
settingsFile.get(byte);
// maximum pieces size
// loadable pieces size
settingsFile.get(byte);
this->maximumPiecesSize = byte;
this->loadablePiecesSize = byte;
if (loadPieces) {
if (maximumPiecesSizeRequest.has_value()) {
this->loadPieces(maximumPiecesSizeRequest.value());
if (loadablePiecesSizeRequest.has_value()) {
this->loadPieces(loadablePiecesSizeRequest.value());
}
else {
this->loadPieces(byte);
@@ -158,15 +159,15 @@ void Settings::saveSettingsToFile() const {
this->keybinds.at(CUSTOMIZABLE_KEYBINDS).saveKeybindsToFile();
std::ofstream settingsFile("data/config/settings.bin", std::ios::trunc | std::ios::binary);
std::ofstream settingsFile(AssetManager::getConfigPath("data/config/settings.bin"), std::ios::trunc | std::ios::binary);
char byte;
// file format version
byte = CURRENT_FILE_FORMAT_VERSION;
settingsFile.write(&byte, 1);
// maximum pieces size
byte = this->maximumPiecesSize;
// loadable pieces size
byte = this->loadablePiecesSize;
settingsFile.write(&byte, 1);
// keybind layout
@@ -321,7 +322,7 @@ void Settings::confirmSelectedPieces() {
int size = getSizeOfPieces(type);
if (size == 0) {
if (!(value > this->maximumPiecesSize)) {
if (!(value > this->loadablePiecesSize)) {
switch (type) {
case CONVEX_PIECES : {this->menu.getPiecesList().selectConvexPieces(value); break;}
case HOLELESS_PIECES : {this->menu.getPiecesList().selectHolelessPieces(value); break;}
@@ -332,7 +333,7 @@ void Settings::confirmSelectedPieces() {
}
}
else {
if (!(getSizeOfPieces(type) > this->maximumPiecesSize)) {
if (!(getSizeOfPieces(type) > this->loadablePiecesSize)) {
this->menu.getPiecesList().selectPiece(size, value);
selectedNone = false;
}
@@ -347,7 +348,7 @@ void Settings::confirmSelectedPieces() {
bool Settings::increaseDistribution(int size) {
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) {
this->distributions.at(size)++;
@@ -358,7 +359,7 @@ bool Settings::increaseDistribution(int size) {
bool Settings::decreaseDistribution(int size) {
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) {
this->distributions.at(size)--;
@@ -383,8 +384,8 @@ Keybinds& Settings::getKeybinds() {
return this->keybinds.at(this->chosenKeybinds);
}
int Settings::getMaximumPiecesSize() const {
return this->maximumPiecesSize;
int Settings::getLoadablePiecesSize() const {
return this->loadablePiecesSize;
}
bool Settings::hasLoadedPieces() const {

View File

@@ -29,7 +29,7 @@ static const std::pair<PiecesType, int> DEFAULT_SELECTION = {ALL_PIECES, MINIMUM
class Settings {
private:
Menu menu;
int maximumPiecesSize;
int loadablePiecesSize;
bool loadedPieces;
std::vector<Keybinds> keybinds;
int chosenKeybinds;
@@ -42,9 +42,9 @@ class Settings {
public:
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;
@@ -82,7 +82,7 @@ class Settings {
Keybinds& getKeybinds();
int getMaximumPiecesSize() const;
int getLoadablePiecesSize() const;
bool hasLoadedPieces() const;

View File

@@ -4,86 +4,122 @@
#include <filesystem>
#include <fstream>
#include "../Utils/AssetManager.h"
void resetSettingsFile();
void resetKeybindFile(int layout);
[[nodiscard]] bool resetSettingsFile();
[[nodiscard]] bool resetKeybindFile(int layout);
int main() {
int main(int arc, char** args) {
std::srand(std::time(NULL));
bool everythingIsOK = true;
// CHECK PIECES FILES
PiecesFiles pf;
bool warned = false;
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(AssetManager::getResourcePath("data/pieces/" + std::to_string(i) + "minos.bin"))) {
#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
std::cout << "INFO: Pieces files for size " << i << " not found, generating..." << std::endl;
pf.savePieces(i);
everythingIsOK &= pf.savePieces(i);
}
}
#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;
bool everythingGenerated = true;
for (int i = DEBUG_PIECES_SIZE; i <= RELEASE_PIECES_SIZE; i++) {
if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) {
everythingGenerated = false;
bool releasePiecesGenerated = true;
for (int i = DEBUG_PIECES_SIZE + 1; i <= RELEASE_PIECES_SIZE; i++) {
if (!std::filesystem::exists(AssetManager::getResourcePath("data/pieces/" + std::to_string(i) + "minos.bin"))) {
releasePiecesGenerated = false;
}
}
if (!everythingGenerated) {
if (!releasePiecesGenerated) {
std::cout << "NOTE: You do not have all pieces generated, generating can take several minutes." << std::endl;
}
#endif
if (!std::filesystem::exists("data/config/settings.bin")) {
bool everythingGenerated = true;
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
auto filePath = AssetManager::getResourcePath("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(AssetManager::getConfigPath("data/config/settings.bin"))) {
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(AssetManager::getConfigPath("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 {
std::ifstream settingsFile("data/config/settings.bin", std::ios::binary);
std::ifstream settingsFile(AssetManager::getConfigPath("data/config/settings.bin"), std::ios::binary);
char byte;
settingsFile.get(byte);
if ((unsigned char) byte < CURRENT_FILE_FORMAT_VERSION) {
std::cout << "INFO: Files format changed, regenerating..." << std::endl;
resetSettingsFile();
everythingIsOK &= resetSettingsFile();
for (int i = 0; i < NUMBER_OF_KEYBINDS; i++) {
resetKeybindFile(i);
everythingIsOK &= resetKeybindFile(i);
}
}
}
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 n°" << (i + 1) << "/" << NUMBER_OF_KEYBINDS << " not found, generating..." << std::endl;
resetKeybindFile(i);
}
}
// LAUNCH APP
GraphApp UI;
UI.run();
if (everythingIsOK) {
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;
}
void resetSettingsFile() {
if (!std::filesystem::exists("data/config")) {
std::filesystem::create_directories("data/config");
bool resetSettingsFile() {
if (!std::filesystem::exists(AssetManager::getConfigPath("data/config"))) {
std::filesystem::create_directories(AssetManager::getConfigPath("data/config"));
}
std::ofstream settingsFile("data/config/settings.bin", std::ios::trunc | std::ios::binary);
char byte;
auto filePath = AssetManager::getConfigPath("data/config/settings.bin");
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;
// file format version
byte = CURRENT_FILE_FORMAT_VERSION;
settingsFile.write(&byte, 1);
// maximum pieces size
// loadable pieces size
byte = MINIMUM_PIECES_SIZE;
settingsFile.write(&byte, 1);
@@ -132,16 +168,35 @@ void resetSettingsFile() {
}
// selected pieces
byte = ALL_PIECES;
byte = DEFAULT_SELECTION.first;
settingsFile.write(&byte, 1);
byte = 4;
byte = DEFAULT_SELECTION.second;
settingsFile.write(&byte, 1);
return true;
}
void resetKeybindFile(int layout) {
if (layout < 0 || layout > 4) return;
bool resetKeybindFile(int layout) {
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(AssetManager::getConfigPath("data/config/keybinds"))) {
std::filesystem::create_directories(AssetManager::getConfigPath("data/config/keybinds"));
}
auto filePath = AssetManager::getConfigPath("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;
if (layout != 4) {
@@ -207,4 +262,6 @@ void resetKeybindFile(int layout) {
byte = 0xFF;
layoutFile.write(&byte, 1);
}
return true;
}

View File

@@ -11,6 +11,7 @@
#include <algorithm>
#include "../Common/Compression.h"
#include "../Utils/AssetManager.h"
PiecesFiles::PiecesFiles() {
@@ -140,7 +141,7 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
}
bool PiecesFiles::getFilePath(int polyominoSize, std::string& filePath) const {
std::string dataFolderPath = "data/pieces/";
auto dataFolderPath = AssetManager::getResourcePath("data/pieces");
if (!std::filesystem::exists(dataFolderPath)) {
std::filesystem::create_directories(dataFolderPath);
@@ -150,6 +151,6 @@ bool PiecesFiles::getFilePath(int polyominoSize, std::string& filePath) const {
return false;
}
filePath = dataFolderPath + std::to_string(polyominoSize) + "minos.bin";
filePath = (dataFolderPath / (std::to_string(polyominoSize) + "minos.bin")).string();
return true;
}

View File

@@ -18,21 +18,21 @@ class PiecesFiles {
/**
* 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
* @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
* @return If the file was found
* 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 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

View File

@@ -1,44 +1,42 @@
#include "../Pieces/Generator.h"
#include "../Pieces/PiecesFiles.h"
#include "TextApp.h"
#include "../Utils/AssetManager.h"
#include <chrono>
#include <filesystem>
#include <cmath>
static const int MAXIMUM_PIECES_SIZE = 10;
static const int BENCHMARK_PIECES_SIZE = 15;
void testGeneratorForAllSizes(int max_size);
void testGeneratorForOneSize(int size);
void printPiecesByTypesForOneSize(int size);
void readStatsFromFilesForAllSizes(int max_size);
void benchmarking(int min_size, int max_size);
int main(int argc, char** argv) {
std::srand(std::time(NULL));
#ifdef BENCHMARK
#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
// CHECK PIECES FILES
benchmarking(1, BENCHMARK_PIECES_SIZE);
#else
PiecesFiles pf;
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) {
PiecesFiles pf;
bool warned = false;
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
if (!std::filesystem::exists(AssetManager::getResourcePath("data/pieces/" + std::to_string(i) + "minos.bin"))) {
if (!warned) {
std::cout << "INFO: Pieces files for size " << i << " not found, generating..." << std::endl;
pf.savePieces(i);
warned = true;
}
}
TextApp UI;
UI.run();
#endif
pf.savePieces(i);
}
}
// LAUNCH APP
TextApp UI;
UI.run();
return 0;
}
@@ -119,66 +117,3 @@ void readStatsFromFilesForAllSizes(int max_size) {
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);
}
}

View File

@@ -1,97 +1,42 @@
#include "./AssetManager.h"
#include "AssetManager.h"
#include <map>
#ifdef _WIN32
#include <windows.h> //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h> //readlink
#endif
static const unsigned char data_fonts_pressstart_prstart_ttf[] = {
#include <data/fonts/pressstart/prstart.ttf.h>
};
namespace fs = std::filesystem;
static const unsigned char data_fonts_pressstart_prstartk_ttf[] = {
#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[] = {
#include <data/images/keybinds/Harddrop.png.h>
};
static const unsigned char data_images_keybinds_Moveleft_png[] = {
#include <data/images/keybinds/Moveleft.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_Softdrop_png[] = {
#include <data/images/keybinds/Softdrop.png.h>
};
static const unsigned char data_images_keybinds_Pause_png[] = {
#include <data/images/keybinds/Pause.png.h>
};
static const Asset assets[] = {
{data_fonts_pressstart_prstart_ttf, sizeof(data_fonts_pressstart_prstart_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_Moveleft_png, sizeof(data_images_keybinds_Moveleft_png)},
{data_images_keybinds_Hold_png, sizeof(data_images_keybinds_Hold_png)},
{data_images_keybinds_Softdrop_png, sizeof(data_images_keybinds_Softdrop_png)},
{data_images_keybinds_Pause_png, sizeof(data_images_keybinds_Pause_png)},
};
static const std::map<std::string, AssetName> assetMap = {
{"data/fonts/pressstart/prstart.ttf", AssetName::data_fonts_pressstart_prstart_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/Moveleft.png", AssetName::data_images_keybinds_Moveleft_png},
{"data/images/keybinds/Hold.png", AssetName::data_images_keybinds_Hold_png},
{"data/images/keybinds/Softdrop.png", AssetName::data_images_keybinds_Softdrop_png},
{"data/images/keybinds/Pause.png", AssetName::data_images_keybinds_Pause_png},
};
const Asset& getResource(AssetName fileName) {
return assets[static_cast<std::size_t>(fileName)];
static fs::path getExeDirectory(){
#ifdef _WIN32
wchar_t path[MAX_PATH] = { 0 };
GetModuleFileNameW(NULL, path, MAX_PATH);
return path;
#else
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return std::string(result, (count > 0) ? count : 0);
#endif
}
const Asset& getResource(const std::string& fileName) {
return getResource(assetMap.at(fileName));
static fs::path getEnv(const std::string& var) {
char* env = std::getenv(var.c_str());
return env ? env :
#ifdef JMINOS_IGNORE_WORKDIR
getExeDirectory().parent_path().parent_path();
#else
"";
#endif
}
fs::path AssetManager::getResourcePath(const std::string& resource) {
return fs::path{getEnv("JMINOS_DATA")} / resource;
}
fs::path AssetManager::getConfigPath(const std::string& resource) {
return fs::path{getEnv("JMINOS_CONFIG")} / resource;
}

View File

@@ -2,29 +2,17 @@
#include <cstdint>
#include <string>
#include <filesystem>
struct Asset {
const unsigned char* data;
std::size_t size;
class AssetManager {
public:
/**
* @brief Used to load things (might be read-only)
*/
static std::filesystem::path getResourcePath(const std::string& resource);
/**
* @brief Used to save things
*/
static std::filesystem::path getConfigPath(const std::string& resource);
};
enum class AssetName {
data_fonts_pressstart_prstart_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_Moveleft_png,
data_images_keybinds_Hold_png,
data_images_keybinds_Softdrop_png,
data_images_keybinds_Pause_png,
};
const Asset& getResource(AssetName fileName);
const Asset& getResource(const std::string& fileName);

View File

@@ -1,8 +1,20 @@
add_rules("mode.debug", "mode.release")
includes("xmake/bin2c.lua")
set_version("1.0.0")
set_project("org.zulianc.jminos")
add_requires("sfml 3.0.0", "zlib")
includes("@builtin/xpack")
option("external_build")
set_default(false)
option_end()
if has_config("external_build") then
add_requires("sfml 3.0.0", "zlib", {system = false})
add_defines("JMINOS_IGNORE_WORKDIR")
else
add_requires("sfml 3.0.0", "zlib")
end
set_languages("c++20")
@@ -10,7 +22,7 @@ set_rundir(".")
target("core")
set_kind("$(kind)")
add_files("src/Pieces/*.cpp", "src/Core/*.cpp", "src/Common/*.cpp")
add_files("src/Pieces/*.cpp", "src/Core/*.cpp", "src/Common/*.cpp", "src/Utils/*.cpp")
add_packages("zlib")
target("text")
@@ -22,22 +34,16 @@ target("text")
target("bmark")
set_default(false)
set_kind("binary")
add_files("./src/TextUI/*.cpp")
add_files("./src/Benchmark/*.cpp")
add_deps("core")
add_defines("BENCHMARK")
target("graph")
set_default(true)
add_rules("bin2c", {
extensions = {".png", ".ttf"},
outputSource = {"src/Utils/AssetManager.cpp"},
outputHeader = {"src/Utils/AssetManager.h"}
})
set_kind("binary")
add_files("./src/GraphicalUI/**.cpp")
add_files("data/fonts/**.ttf", "data/images/**.png")
add_deps("core")
add_packages("sfml")
add_installfiles("(data/**)")
if is_mode("debug") then
add_defines("DEBUG")
@@ -47,6 +53,7 @@ if is_plat("mingw") then
add_ldflags("-static-libstdc++", "-static")
end
includes("xmake/xpack.lua")
--
-- If you want to known more usage about xmake, please see https://xmake.io

36
xmake/xpack.lua Normal file
View File

@@ -0,0 +1,36 @@
if is_os("linux") then
xpack("jminos")
set_formats("flatpak")
set_extension("flatpak")
set_title("jminos")
set_author("zulianc")
set_description("A test installer.")
set_homepage("https://git.ale-pri.com/TetrisNerd/jminos")
set_company("org.zulianc")
on_package(function (package)
os.cd("flatpak")
os.exec("flatpak install org.flatpak.Builder --user -y")
os.exec("flatpak run org.flatpak.Builder --force-clean --user --install-deps-from=flathub --repo=repo --install builddir org.zulianc.jminos.yml")
os.exec("flatpak build-bundle repo jminos.flatpak org.zulianc.jminos --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo")
os.mv("jminos.flatpak", package:outputdir())
end)
on_load(function (package)
package:set("basename", package:name() .. "-v" .. package:version() .. "-" .. package:arch())
end)
else
xpack("jminos")
set_formats("zip", "nsis")
add_targets("graph")
add_installfiles("(data/**.png)")
set_iconfile("../flatpak/org.zulianc.jminos.ico")
on_load(function (package)
package:set("basename", package:name() .. "-v" .. package:version() .. "-" .. package:arch())
end)
after_installcmd(function (package, batchcmds)
batchcmds:rm(package:installdir("**/.gitkeep"))
end)
end