9 Commits

Author SHA1 Message Date
17459c4026 use VarInt
All checks were successful
Linux arm64 / Build (push) Successful in 12m53s
2025-06-12 21:38:47 +02:00
3e40ff7252 add compression
All checks were successful
Linux arm64 / Build (push) Successful in 1m58s
2025-06-12 21:28:46 +02:00
dd8314f76c ff windaube veut toujours pas
All checks were successful
Linux arm64 / Build (push) Successful in 2m45s
2025-06-12 17:35:39 +02:00
d7f52239f0 and again
All checks were successful
Linux arm64 / Build (push) Successful in 1m57s
2025-06-03 12:03:59 +02:00
72f4ea75ff fix again 2025-06-03 12:03:47 +02:00
b1b7277666 fix array initialization
Some checks failed
Linux arm64 / Build (push) Failing after 1m53s
2025-06-03 11:55:12 +02:00
fd6bdc2b09 Merge branch 'assets'
All checks were successful
Linux arm64 / Build (push) Successful in 2m0s
2025-05-28 19:24:49 +02:00
69b91d6497 simon PR review 2025-05-28 19:24:36 +02:00
6ed85869ae added bones block to master mode and added invisible mode
All checks were successful
Linux arm64 / Build (push) Successful in 1m55s
2025-05-27 18:52:07 +02:00
26 changed files with 867 additions and 189 deletions

View File

@@ -24,11 +24,12 @@ You will find more infos about the Rotation System, the scoring system, or the d
- Every polyominoes up to pentedecaminoes! - Every polyominoes up to pentedecaminoes!
- 7bag with proportionnality for each polyomino size! - 7bag with proportionnality for each polyomino size!
- AutoRS as the Rotation System!
- 0° rotations!
- All spin!
- IRS, IHS, infinite hold, and other leniency mechanics!
- Customizable board size! - Customizable board size!
- Customizable keybinds! - Customizable keybinds!
- 0° rotations!
- AutoRS as the Rotation System!
- IRS, IHS, infinite hold, and other leniency mechanics!
- Very bland interface!! (i'm not a designer) - Very bland interface!! (i'm not a designer)
### Available gamemodes ### Available gamemodes
@@ -37,6 +38,7 @@ You will find more infos about the Rotation System, the scoring system, or the d
- MARATHON : clear 200 lines with increasing gravity! - MARATHON : clear 200 lines with increasing gravity!
- ULTRA : scores as much as possible in only 2 minutes! - ULTRA : scores as much as possible in only 2 minutes!
- MASTER : clear 200 lines at levels higher than maximum gravity! - MASTER : clear 200 lines at levels higher than maximum gravity!
- INVISIBLE : get 1000 grade while not being able to see the board!
- ZEN : practice indefinitely in this mode with no gravity! - ZEN : practice indefinitely in this mode with no gravity!
### Screenshots ### Screenshots
@@ -90,7 +92,7 @@ If for some reasons you wanna run the command line version (not updated):
### One-sided n-polyominoes ### One-sided n-polyominoes
| 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.005622ms | 0s 0.750955ms | 0s 0.014016ms | 2 bytes |
| 2 | 1 | 0s 0.005758ms | 0s 0.181323ms | 0s 0.012256ms | 3 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 | | 3 | 2 | 0s 0.017525ms | 0s 0.054497ms | 0s 0.006431ms | 8 bytes |
@@ -107,12 +109,13 @@ If for some reasons you wanna run the command line version (not updated):
| 14 | 1802312 | 45s 606.597ms | 32s 28.7977ms | 2s 919.653ms | 27034680 bytes | | 14 | 1802312 | 45s 606.597ms | 32s 28.7977ms | 2s 919.653ms | 27034680 bytes |
| 15 | ~6M | ~5mn | ~5mn | ~10s | ~100 MB | | 15 | ~6M | ~5mn | ~5mn | ~10s | ~100 MB |
_File storing includes normalizing 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/)! If you want to know more details about the generation and storage of polyominoes, [check the documentation](/doc/)!
Run it yourself by typing: Run it yourself by typing:
``xmake build benchmark`` ``xmake f -m release``
``xmake run benchmark`` ``xmake build bmark``
``xmake run bmark``
## Credits ## Credits

View File

@@ -0,0 +1,68 @@
#include "Compression.h"
#include "VarInt.h"
#include <cassert>
#include <zlib.h>
#define COMPRESSION_THRESHOLD 64
static DataBuffer Inflate(const std::uint8_t* source, std::size_t size, std::size_t uncompressedSize) {
DataBuffer result;
result.Resize(uncompressedSize);
uncompress(reinterpret_cast<Bytef*>(result.data()), reinterpret_cast<uLongf*>(&uncompressedSize),
reinterpret_cast<const Bytef*>(source), static_cast<uLong>(size));
assert(result.GetSize() == uncompressedSize);
return result;
}
static DataBuffer Deflate(const std::uint8_t* source, std::size_t size) {
DataBuffer result;
uLongf compressedSize = size;
result.Resize(size); // Resize for the compressed data to fit into
compress(
reinterpret_cast<Bytef*>(result.data()), &compressedSize, reinterpret_cast<const Bytef*>(source), static_cast<uLong>(size));
result.Resize(compressedSize); // Resize to cut useless data
return result;
}
DataBuffer Compress(const DataBuffer& buffer) {
DataBuffer packet;
if (buffer.GetSize() < COMPRESSION_THRESHOLD) {
// Don't compress since it's a small packet
VarInt compressedDataLength = 0;
packet << compressedDataLength;
packet << buffer;
return packet;
}
DataBuffer compressedData = Deflate(buffer.data(), buffer.GetSize());
VarInt uncompressedDataLength = buffer.GetSize();
packet << uncompressedDataLength;
packet.WriteSome(compressedData.data(), compressedData.GetSize());
return packet;
}
DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength) {
VarInt uncompressedLength;
buffer >> uncompressedLength;
std::uint64_t compressedLength = packetLength - uncompressedLength.GetSerializedLength();
if (uncompressedLength.GetValue() == 0) {
// Data already uncompressed. Nothing to do
DataBuffer ret;
buffer.ReadSome(ret, compressedLength);
return ret;
}
assert(buffer.GetReadOffset() + compressedLength <= buffer.GetSize());
return Inflate(buffer.data() + buffer.GetReadOffset(), compressedLength, uncompressedLength.GetValue());
}

23
src/Common/Compression.h Normal file
View File

@@ -0,0 +1,23 @@
#pragma once
/**
* \file Compression.h
* \brief File containing compress utilities
*/
#include "DataBuffer.h"
/**
* \brief Compress some data
* \param buffer the data to compress
* \return the compressed data
*/
DataBuffer Compress(const DataBuffer& buffer);
/**
* \brief Uncompress some data
* \param buffer the data to uncompress
* \param packetLength lenght of data
* \return the uncompressed data
*/
DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength);

98
src/Common/DataBuffer.cpp Normal file
View File

@@ -0,0 +1,98 @@
#include "DataBuffer.h"
#include <fstream>
#include <iomanip>
#include <sstream>
#include <iostream>
DataBuffer::DataBuffer(std::size_t initalCapacity) : m_ReadOffset(0) {
m_Buffer.reserve(initalCapacity);
}
DataBuffer::DataBuffer() : m_ReadOffset(0) {}
DataBuffer::DataBuffer(const DataBuffer& other) : m_Buffer(other.m_Buffer), m_ReadOffset(other.m_ReadOffset) {}
DataBuffer::DataBuffer(DataBuffer&& other) : m_Buffer(std::move(other.m_Buffer)), m_ReadOffset(std::move(other.m_ReadOffset)) {}
DataBuffer::DataBuffer(const std::string& str) : m_Buffer(str.begin(), str.end()), m_ReadOffset(0) {}
DataBuffer::DataBuffer(const DataBuffer& other, Data::difference_type offset) : m_ReadOffset(0) {
m_Buffer.reserve(other.GetSize() - static_cast<std::size_t>(offset));
std::copy(other.m_Buffer.begin() + offset, other.m_Buffer.end(), std::back_inserter(m_Buffer));
}
DataBuffer& DataBuffer::operator=(const DataBuffer& other) {
m_Buffer = other.m_Buffer;
m_ReadOffset = other.m_ReadOffset;
return *this;
}
DataBuffer& DataBuffer::operator=(DataBuffer&& other) {
m_Buffer = std::move(other.m_Buffer);
m_ReadOffset = std::move(other.m_ReadOffset);
return *this;
}
void DataBuffer::SetReadOffset(std::size_t pos) {
assert(pos <= GetSize());
m_ReadOffset = pos;
}
std::size_t DataBuffer::GetSize() const {
return m_Buffer.size();
}
std::size_t DataBuffer::GetRemaining() const {
return m_Buffer.size() - m_ReadOffset;
}
DataBuffer::iterator DataBuffer::begin() {
return m_Buffer.begin();
}
DataBuffer::iterator DataBuffer::end() {
return m_Buffer.end();
}
DataBuffer::const_iterator DataBuffer::begin() const {
return m_Buffer.begin();
}
DataBuffer::const_iterator DataBuffer::end() const {
return m_Buffer.end();
}
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer) {
for (unsigned char u : buffer)
os << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(u) << " ";
os << std::dec;
return os;
}
bool DataBuffer::ReadFile(const std::string& fileName) {
try {
std::ifstream file(fileName, std::istream::binary);
std::ostringstream ss;
ss << file.rdbuf();
const std::string& s = ss.str();
m_Buffer = DataBuffer::Data(s.begin(), s.end());
m_ReadOffset = 0;
} catch (std::exception& e) {
std::cerr << "Failed to read file : " << e.what() << std::endl;
return false;
}
return m_Buffer.size() > 0;
}
bool DataBuffer::WriteFile(const std::string& fileName) const {
try {
std::ofstream file(fileName, std::ostream::binary);
file.write(reinterpret_cast<const char*>(m_Buffer.data()), static_cast<std::streamsize>(m_Buffer.size()));
file.flush();
} catch (std::exception& e) {
std::cerr << "Failed to write file : " << e.what() << std::endl;
return false;
}
return true;
}

284
src/Common/DataBuffer.h Normal file
View File

@@ -0,0 +1,284 @@
#pragma once
/**
* \file DataBuffer.h
* \brief File containing the blitz::DataBuffer class
*/
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
/**
* \class DataBuffer
* \brief Class used to manipulate memory
*/
class DataBuffer {
private:
typedef std::vector<std::uint8_t> Data;
Data m_Buffer;
std::size_t m_ReadOffset;
public:
typedef Data::iterator iterator;
typedef Data::const_iterator const_iterator;
typedef Data::reference reference;
typedef Data::const_reference const_reference;
typedef Data::difference_type difference_type;
DataBuffer();
DataBuffer(std::size_t initalCapacity);
DataBuffer(const DataBuffer& other);
DataBuffer(const DataBuffer& other, difference_type offset);
DataBuffer(DataBuffer&& other);
DataBuffer(const std::string& str);
DataBuffer& operator=(const DataBuffer& other);
DataBuffer& operator=(DataBuffer&& other);
/**
* \brief Append data to the buffer
*/
template <typename T>
void Append(const T& data) {
std::size_t size = sizeof(data);
std::size_t end_pos = m_Buffer.size();
m_Buffer.resize(m_Buffer.size() + size);
std::memcpy(&m_Buffer[end_pos], &data, size);
}
/**
* \brief Append data to the buffer
*/
template <typename T>
DataBuffer& operator<<(const T& data) {
Append(data);
return *this;
}
/**
* \brief Append a string to the buffer
* \warning Don't use it for binary data !
* \param str The string to append
*/
DataBuffer& operator<<(const std::string& str) {
std::size_t strlen = str.length() + 1; // including null character
Resize(GetSize() + strlen);
std::memcpy(m_Buffer.data() + GetSize() - strlen, str.data(), strlen);
return *this;
}
/**
* \brief Append data to the buffer from another const buffer
* \param data The buffer to append
*/
DataBuffer& operator<<(const DataBuffer& data) {
m_Buffer.insert(m_Buffer.end(), data.begin(), data.end());
return *this;
}
/**
* \brief Read some data from the buffer and assign to desired variable
*/
template <typename T>
DataBuffer& operator>>(T& data) {
assert(m_ReadOffset + sizeof(T) <= GetSize());
data = *(reinterpret_cast<T*>(&m_Buffer[m_ReadOffset]));
m_ReadOffset += sizeof(T);
return *this;
}
/**
* \brief Read some data from the buffer and assign to the new buffer
* \param data The buffer to assign
*/
DataBuffer& operator>>(DataBuffer& data) {
data.Resize(GetSize() - m_ReadOffset);
std::copy(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), m_Buffer.end(), data.begin());
m_ReadOffset = m_Buffer.size();
return *this;
}
/**
* \brief Read a string from the buffer
* \param str The string to assign in the new buffer
* \warning Don't use it for binary data !
*/
DataBuffer& operator>>(std::string& str) {
std::size_t stringSize =
strlen(reinterpret_cast<const char*>(m_Buffer.data()) + m_ReadOffset) + 1; // including null character
str.resize(stringSize);
std::copy(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset),
m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset + stringSize), str.begin());
m_ReadOffset += stringSize;
return *this;
}
/**
* \brief Write some data to the buffer
* \param buffer The buffer to write
* \param amount The amount of data to write
*/
void WriteSome(const char* buffer, std::size_t amount) {
std::size_t end_pos = m_Buffer.size();
m_Buffer.resize(m_Buffer.size() + amount);
std::memcpy(m_Buffer.data() + end_pos, buffer, amount);
}
/**
* \brief Write some data to the buffer
* \param buffer The buffer to write
* \param amount The amount of data to write
*/
void WriteSome(const std::uint8_t* buffer, std::size_t amount) {
std::size_t end_pos = m_Buffer.size();
m_Buffer.resize(m_Buffer.size() + amount);
std::memcpy(m_Buffer.data() + end_pos, buffer, amount);
}
/**
* \brief Read some data from the buffer
* \param buffer The buffer to Read
* \param amount The amount of data from the buffer
*/
void ReadSome(char* buffer, std::size_t amount) {
assert(m_ReadOffset + amount <= GetSize());
std::copy_n(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), amount, buffer);
m_ReadOffset += amount;
}
/**
* \brief Read some data from the buffer
* \param buffer The buffer to Read
* \param amount The amount of data from the buffer
*/
void ReadSome(std::uint8_t* buffer, std::size_t amount) {
assert(m_ReadOffset + amount <= GetSize());
std::copy_n(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), amount, buffer);
m_ReadOffset += amount;
}
/**
* \brief Read some data from the buffer
* \param buffer The buffer to Read
* \param amount The amount of data from the buffer
*/
void ReadSome(DataBuffer& buffer, std::size_t amount) {
assert(m_ReadOffset + amount <= GetSize());
buffer.Resize(amount);
std::copy_n(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), amount, buffer.begin());
m_ReadOffset += amount;
}
/**
* \brief Resize the buffer
* \param size The new size of the buffer
*/
void Resize(std::size_t size) {
m_Buffer.resize(size);
}
/**
* \brief Reserve some space in the buffer
* \param amount The amount of space to reserve
*/
void Reserve(std::size_t amount) {
m_Buffer.reserve(amount);
}
/**
* \brief Clear the buffer
*/
void Clear() {
m_Buffer.clear();
m_ReadOffset = 0;
}
/**
* \brief When the buffer has been read entirely
*/
bool IsFinished() const {
return m_ReadOffset >= m_Buffer.size();
}
/**
* \brief Get the buffer data
*/
std::uint8_t* data() {
return m_Buffer.data();
}
/**
* \brief Get the buffer data
*/
const std::uint8_t* data() const {
return m_Buffer.data();
}
/**
* \brief Get the read offset
*/
std::size_t GetReadOffset() const {
return m_ReadOffset;
}
/**
* \brief Set the read offset
* \param pos The new read offset
*/
void SetReadOffset(std::size_t pos);
/**
* \brief Get the size of the buffer
*/
std::size_t GetSize() const;
/**
* \brief Get the remaining size of the buffer
*/
std::size_t GetRemaining() const;
/**
* \brief Read a file into the buffer
* \param fileName The name of the file to read
*/
bool ReadFile(const std::string& fileName);
/**
* \brief Write a file into the buffer
* \param fileName The name of the file to write to
*/
bool WriteFile(const std::string& fileName) const;
/**
* \brief Allocate the buffer on the heap
* \warning Don't forget to free the data !
*/
std::uint8_t* HeapAllocatedData() const {
std::uint8_t* newBuffer = new std::uint8_t[GetSize()];
std::memcpy(newBuffer, data(), GetSize());
return newBuffer;
}
/**
* \brief Operator == to compare two DataBuffer
*/
bool operator==(const DataBuffer& other) const {
return m_Buffer == other.m_Buffer;
}
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
};
/**
* \brief Operator << to write a DataBuffer to an ostream
*/
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer);

48
src/Common/VarInt.cpp Normal file
View File

@@ -0,0 +1,48 @@
#include "VarInt.h"
#include "DataBuffer.h"
#include <stdexcept>
static constexpr int SEGMENT_BITS = 0x7F;
static constexpr int CONTINUE_BIT = 0x80;
std::size_t VarInt::GetSerializedLength() const {
DataBuffer buffer;
buffer << *this;
return buffer.GetSize();
}
DataBuffer& operator<<(DataBuffer& out, const VarInt& var) {
std::uint64_t value = var.m_Value;
while (true) {
if ((value & ~static_cast<std::uint64_t>(SEGMENT_BITS)) == 0) {
out << static_cast<std::uint8_t>(value);
return out;
}
out << static_cast<std::uint8_t>((value & SEGMENT_BITS) | CONTINUE_BIT);
value >>= 7;
}
}
DataBuffer& operator>>(DataBuffer& in, VarInt& var) {
var.m_Value = 0;
unsigned int position = 0;
std::uint8_t currentByte;
while (true) {
in.ReadSome(&currentByte, 1);
var.m_Value |= static_cast<std::uint64_t>(currentByte & SEGMENT_BITS) << position;
if ((currentByte & CONTINUE_BIT) == 0)
break;
position += 7;
if (position >= 8 * sizeof(var.m_Value))
throw std::runtime_error("VarInt is too big");
}
return in;
}

54
src/Common/VarInt.h Normal file
View File

@@ -0,0 +1,54 @@
#pragma once
/**
* \file VarInt.h
* \brief File containing the blitz::VarInt class
*/
#include <cstddef>
#include <cstdint>
class DataBuffer;
/**
* \class VarInt
* \brief Variable-length format such that smaller numbers use fewer bytes.
*/
class VarInt {
private:
std::uint64_t m_Value;
public:
VarInt() : m_Value(0) {}
/**
* \brief Construct a variable integer from a value
* \param value The value of the variable integer
*/
VarInt(std::uint64_t value) : m_Value(value) {}
/**
* \brief Get the value of the variable integer
*/
std::uint64_t GetValue() const {
return m_Value;
}
/**
* \brief Get the length of the serialized variable integer
*/
std::size_t GetSerializedLength() const;
/**
* \brief Serialize the variable integer
* \param out The buffer to write the serialized variable integer to
* \param var The variable integer to serialize
*/
friend DataBuffer& operator<<(DataBuffer& out, const VarInt& var);
/**
* \brief Deserialize the variable integer
* \param in The buffer to read the serialized variable integer from
* \param var The variable integer to deserialize
*/
friend DataBuffer& operator>>(DataBuffer& in, VarInt& var);
};

View File

@@ -366,6 +366,10 @@ bool Game::areBlocksBones() const {
return this->parameters.getBoneBlocks(); return this->parameters.getBoneBlocks();
} }
bool Game::isBoardInvisible() const {
return this->parameters.getInvisibleBoard();
}
const Board& Game::getBoard() const { const Board& Game::getBoard() const {
return this->board.getBoard(); return this->board.getBoard();
} }

View File

@@ -136,6 +136,11 @@ class Game {
*/ */
bool areBlocksBones() const; bool areBlocksBones() const;
/**
* @return If the board is currently invisible
*/
bool isBoardInvisible() const;
/** /**
* @return The board * @return The board
*/ */

View File

@@ -24,6 +24,8 @@ void GameParameters::reset() {
case MARATHON : {this->level = 1; break;} case MARATHON : {this->level = 1; break;}
// goes from level 20 to 39 // goes from level 20 to 39
case MASTER : {this->level = 20; break;} case MASTER : {this->level = 20; break;}
// goes from level 1 to 19
case INVISIBLE : {this->level = 1; break;}
// no gravity // no gravity
case ZEN : {this->level = 0; break;} case ZEN : {this->level = 0; break;}
default : this->level = 1; default : this->level = 1;
@@ -34,7 +36,7 @@ void GameParameters::reset() {
void GameParameters::lockedPiece(const LineClear& lineClear) { void GameParameters::lockedPiece(const LineClear& lineClear) {
switch (this->gamemode) { switch (this->gamemode) {
// modes where level increases // modes where level increases with lines
case MARATHON : case MARATHON :
case MASTER : { case MASTER : {
int previousLines = this->clearedLines; int previousLines = this->clearedLines;
@@ -51,9 +53,23 @@ void GameParameters::lockedPiece(const LineClear& lineClear) {
default : this->clearedLines += lineClear.lines; default : this->clearedLines += lineClear.lines;
} }
int previousGrade = this->grade;
if (!((lineClear.lines == 0) && ((this->grade % 100) == 99))) { if (!((lineClear.lines == 0) && ((this->grade % 100) == 99))) {
this->grade += (1 + lineClear.lines); this->grade += (1 + lineClear.lines);
} }
switch (this->gamemode) {
// modes where level increases with grade
case INVISIBLE : {
if (previousGrade / 100 < this->grade / 100) {
this->level += 2;
this->updateStats();
}
break;
}
// other modes
default : break;
}
} }
bool GameParameters::hasWon(int framesPassed) const { bool GameParameters::hasWon(int framesPassed) const {
@@ -66,6 +82,8 @@ bool GameParameters::hasWon(int framesPassed) const {
case MARATHON : return this->clearedLines >= 200; case MARATHON : return this->clearedLines >= 200;
// win once 200 lines have been cleared // win once 200 lines have been cleared
case MASTER : return this->clearedLines >= 200; case MASTER : return this->clearedLines >= 200;
// win once 1000 grade has been passed
case INVISIBLE : return this->grade >= 1000;
// infinite mode // infinite mode
case ZEN : case ZEN :
default : return false; default : return false;
@@ -84,7 +102,8 @@ void GameParameters::updateStats() {
} }
// 3 for slow-controls gamemodes // 3 for slow-controls gamemodes
case MARATHON : case MARATHON :
case MASTER : { case MASTER :
case INVISIBLE : {
this->nextQueueLength = 3; this->nextQueueLength = 3;
break; break;
} }
@@ -94,10 +113,13 @@ void GameParameters::updateStats() {
/* BONE BLOCKS */ /* BONE BLOCKS */
switch (this->gamemode) { switch (this->gamemode) {
// blocks turns into bone blocks at level 30 // blocks turns into bone blocks at level 30
case MASTER : this->boneBlocks = (this->level >= 30); case MASTER : {this->boneBlocks = (this->level >= 30); break;}
default : this->boneBlocks = false; default : this->boneBlocks = false;
} }
/* INVISIBLE */
this->invisibleBoard = (this->gamemode == INVISIBLE);
/* GRAVITY */ /* GRAVITY */
// get gravity for an assumed 20-rows board // get gravity for an assumed 20-rows board
static const int gravityPerLevel[] = { static const int gravityPerLevel[] = {
@@ -152,6 +174,8 @@ void GameParameters::updateStats() {
case MARATHON : {this->ARE = 24 - (this->level - 1); break;} case MARATHON : {this->ARE = 24 - (this->level - 1); break;}
// starts at 400ms (24f) at lvl 20 and ends at 083ms (5f) at lvl 39 // starts at 400ms (24f) at lvl 20 and ends at 083ms (5f) at lvl 39
case MASTER : {this->ARE = 24 - (this->level - 20); break;} case MASTER : {this->ARE = 24 - (this->level - 20); break;}
// fixed at 250ms (15f)
case INVISIBLE : {this->ARE = 15; break;}
// no ARE by default // no ARE by default
default : this->ARE = 0; default : this->ARE = 0;
} }
@@ -228,6 +252,10 @@ bool GameParameters::getBoneBlocks() const {
return this->boneBlocks; return this->boneBlocks;
} }
bool GameParameters::getInvisibleBoard() const {
return this->invisibleBoard;
}
int GameParameters::getGravity() const { int GameParameters::getGravity() const {
return this->gravity; return this->gravity;
} }

View File

@@ -18,6 +18,7 @@ class GameParameters {
int grade; // the current amount of points int grade; // the current amount of points
int nextQueueLength; // the number of pieces visibles in the next queue int nextQueueLength; // the number of pieces visibles in the next queue
bool boneBlocks; // wheter all blocks are bone blocks bool boneBlocks; // wheter all blocks are bone blocks
bool invisibleBoard; // wheter the board is invisible
int gravity; // the gravity at which pieces drop int gravity; // the gravity at which pieces drop
int lockDelay; // the time before the piece lock in place int lockDelay; // the time before the piece lock in place
int forcedLockDelay; // the forced time before the piece lock in place int forcedLockDelay; // the forced time before the piece lock in place
@@ -77,9 +78,14 @@ class GameParameters {
int getNextQueueLength() const; int getNextQueueLength() const;
/** /**
* Returns wheter the blocks are currently bone blocks * @return Wheter the blocks are currently bone blocks
*/ */
bool getBoneBlocks() const; bool getBoneBlocks() const;
/**
* @return Wheter the board is currently invisible
*/
bool getInvisibleBoard() const;
/** /**
* @return The current gravity for a 20-line high board * @return The current gravity for a 20-line high board

View File

@@ -11,6 +11,7 @@ enum Gamemode {
MARATHON, MARATHON,
ULTRA, ULTRA,
MASTER, MASTER,
INVISIBLE,
ZEN ZEN
}; };
@@ -24,6 +25,7 @@ inline std::string getGamemodeName(Gamemode gamemode) {
"MARATHON", "MARATHON",
"ULTRA", "ULTRA",
"MASTER", "MASTER",
"INVISIBLE",
"ZEN" "ZEN"
}; };
@@ -39,6 +41,7 @@ inline std::string getGamemodeGoal(Gamemode gamemode) {
"200 lines", "200 lines",
"2 minutes", "2 minutes",
"200 lines", "200 lines",
"1000 grade",
"Infinite" "Infinite"
}; };

View File

@@ -1,12 +1,72 @@
#include "AppMenu.h" #include "AppMenu.h"
#include "../Settings.h"
#include "../PlayerCursor.h"
#include "../../Utils/AssetManager.h" #include "../../Utils/AssetManager.h"
AppMenu::AppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) : menuStack(menuStack), #include <stack>
settings(settings), #include <memory>
renderWindow(renderWindow) #include <optional>
{ #include <SFML/Graphics.hpp>
AppMenu::AppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
menuStack(menuStack),
settings(settings),
renderWindow(renderWindow) {
const Asset& file = getResource(AssetName::data_fonts_pressstart_prstartk_ttf); const Asset& file = getResource(AssetName::data_fonts_pressstart_prstartk_ttf);
this->pressStartFont = sf::Font(file.data, file.size); this->pressStartFont = sf::Font(file.data, file.size);
} }
void AppMenu::updateMetaBinds() {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Enter)) {
this->enterPressed = true;
this->enterReleased = false;
}
else {
this->enterReleased = this->enterPressed;
this->enterPressed = false;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Escape)) {
this->escPressed = true;
this->escReleased = false;
}
else {
this->escReleased = this->escPressed;
this->escPressed = false;
}
}
void AppMenu::placeText(sf::Text& text, const std::optional<PlayerCursor>& playerCursor, const sf::String& string, float xPos, float yPos, const std::optional<sf::Vector2u>& cursorPos) const {
float sizeMultiplier = this->settings->getWindowSizeMultiplier();
text.setString(string);
if (playerCursor.has_value() && cursorPos.has_value()) {
text.setOutlineThickness((playerCursor.value().getPosition() == cursorPos.value()) ? (sizeMultiplier / 2) : 0);
}
text.setOrigin(sf::Vector2f({0, text.getLocalBounds().size.y / 2}));
text.setPosition(sf::Vector2f({sizeMultiplier * xPos, sizeMultiplier * yPos}));
this->renderWindow->draw(text);
}
void AppMenu::placeTitle(sf::Text& text, const std::optional<PlayerCursor>& playerCursor, const sf::String& string, float yPos, const std::optional<sf::Vector2u>& cursorPos) const {
float sizeMultiplier = this->settings->getWindowSizeMultiplier();
text.setString(string);
if (playerCursor.has_value() && cursorPos.has_value()) {
text.setOutlineThickness((playerCursor.value().getPosition() == cursorPos.value()) ? (sizeMultiplier / 2) : 0);
}
text.setOrigin({text.getLocalBounds().getCenter().x, text.getLocalBounds().size.y / 2});
text.setPosition(sf::Vector2f({sizeMultiplier * 40.f, sizeMultiplier * yPos}));
this->renderWindow->draw(text);
}
sf::Color AppMenu::getColorOfBlock(Block block, int luminosityShift) const {
Color rgbColor = BLOCKS_COLOR[block];
return sf::Color(std::clamp(rgbColor.red + luminosityShift, 0, 255),
std::clamp(rgbColor.green + luminosityShift, 0, 255),
std::clamp(rgbColor.blue + luminosityShift, 0, 255));
}

View File

@@ -31,54 +31,11 @@ class AppMenu {
virtual void drawFrame() const = 0; virtual void drawFrame() const = 0;
protected: protected:
void updateMetaBinds() { void updateMetaBinds();
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Enter)) {
enterPressed = true;
enterReleased = false;
}
else {
enterReleased = enterPressed;
enterPressed = false;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Escape)) { void placeText(sf::Text& text, const std::optional<PlayerCursor>& playerCursor, const sf::String& string, float xPos, float yPos, const std::optional<sf::Vector2u>& cursorPos) const;
escPressed = true;
escReleased = false;
}
else {
escReleased = escPressed;
escPressed = false;
}
}
void placeText(sf::Text& text, const std::optional<PlayerCursor>& playerCursor, const sf::String& string, float xPos, float yPos, const std::optional<sf::Vector2u>& cursorPos) const { void placeTitle(sf::Text& text, const std::optional<PlayerCursor>& playerCursor, const sf::String& string, float yPos, const std::optional<sf::Vector2u>& cursorPos) const;
float sizeMultiplier = this->settings->getWindowSizeMultiplier();
text.setString(string); sf::Color getColorOfBlock(Block block, int luminosityShift) const;
if (playerCursor.has_value() && cursorPos.has_value()) {
text.setOutlineThickness((playerCursor.value().getPosition() == cursorPos.value()) ? (sizeMultiplier / 2) : 0);
}
text.setOrigin(sf::Vector2f({0, text.getLocalBounds().size.y / 2}));
text.setPosition(sf::Vector2f({sizeMultiplier * xPos, sizeMultiplier * yPos}));
this->renderWindow->draw(text);
}
void placeTitle(sf::Text& text, const std::optional<PlayerCursor>& playerCursor, const sf::String& string, float yPos, const std::optional<sf::Vector2u>& cursorPos) const {
float sizeMultiplier = this->settings->getWindowSizeMultiplier();
text.setString(string);
if (playerCursor.has_value() && cursorPos.has_value()) {
text.setOutlineThickness((playerCursor.value().getPosition() == cursorPos.value()) ? (sizeMultiplier / 2) : 0);
}
text.setOrigin({text.getLocalBounds().getCenter().x, text.getLocalBounds().size.y / 2});
text.setPosition(sf::Vector2f({sizeMultiplier * 40.f, sizeMultiplier * yPos}));
this->renderWindow->draw(text);
}
sf::Color getColorOfBlock(Block block, int luminosityShift) const {
Color rgbColor = BLOCKS_COLOR[block];
return sf::Color(std::clamp(rgbColor.red + luminosityShift, 0, 255),
std::clamp(rgbColor.green + luminosityShift, 0, 255),
std::clamp(rgbColor.blue + luminosityShift, 0, 255));
}
}; };

View File

@@ -104,17 +104,26 @@ void GamePlayingAppMenu::computeFrame() {
void GamePlayingAppMenu::drawFrame() const { void GamePlayingAppMenu::drawFrame() const {
this->renderWindow->clear(sf::Color(200, 200, 200)); this->renderWindow->clear(sf::Color(200, 200, 200));
sf::Color bonesBlockColor(0, 0, 0);
sf::Color bonesBlockGhostColor(100, 100, 100);
bool areBlockBones = this->game.areBlocksBones();
bool isBoardInvisible = this->game.isBoardInvisible() && !(this->game.hasWon() || this->game.hasLost());
sf::Vector2f cellSize(this->cellSizeZoom, this->cellSizeZoom); sf::Vector2f cellSize(this->cellSizeZoom, this->cellSizeZoom);
float cellOutlineThickness = this->cellSizeZoom / 4;
bool drawActivePiece = (this->game.getActivePiece() != nullptr) && (!this->game.hasLost()); bool drawActivePiece = (this->game.getActivePiece() != nullptr) && (!this->game.hasLost());
// 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;
sf::RectangleShape cell(cellSize); sf::RectangleShape cell(cellSize);
cell.setFillColor(this->getColorOfBlock(block, (block == NOTHING) ? 0 : -30)); cell.setFillColor((areBlockBones && block != NOTHING)
? bonesBlockColor
: this->getColorOfBlock(block, (block == NOTHING) ? 0 : -30));
cell.setPosition(this->getBoardBlockPosition(x, y)); cell.setPosition(this->getBoardBlockPosition(x, y));
this->renderWindow->draw(cell); this->renderWindow->draw(cell);
} }
@@ -122,7 +131,10 @@ void GamePlayingAppMenu::drawFrame() const {
if (drawActivePiece) { if (drawActivePiece) {
// ghost piece // ghost piece
sf::Color ghostColor = this->getColorOfBlock(this->game.getActivePiece()->getBlockType(), 100); sf::Color ghostColor = areBlockBones
? bonesBlockGhostColor
: this->getColorOfBlock(this->game.getActivePiece()->getBlockType(), 100);
for (const Position& position : this->game.getActivePiece()->getPositions()) { for (const Position& position : this->game.getActivePiece()->getPositions()) {
Position cellPosition = (this->game.getGhostPiecePosition() + position); Position cellPosition = (this->game.getGhostPiecePosition() + position);
@@ -133,13 +145,13 @@ void GamePlayingAppMenu::drawFrame() const {
} }
// active piece outline // active piece outline
float pieceOutlineSize = std::roundf(this->cellSizeZoom / 4);
sf::Color pieceOultlineColor = sf::Color(255, 255 - (255 * this->game.getForcedLockDelayProgression()), 255 - (255 * this->game.getForcedLockDelayProgression())); sf::Color pieceOultlineColor = sf::Color(255, 255 - (255 * this->game.getForcedLockDelayProgression()), 255 - (255 * this->game.getForcedLockDelayProgression()));
for (const Position& position : this->game.getActivePiece()->getPositions()) { for (const Position& position : this->game.getActivePiece()->getPositions()) {
Position cellPosition = (this->game.getActivePiecePosition() + position); Position cellPosition = (this->game.getActivePiecePosition() + position);
sf::RectangleShape cell(cellSize); sf::RectangleShape cell(cellSize);
cell.setOutlineThickness(pieceOutlineSize); cell.setOutlineThickness(cellOutlineThickness);
cell.setOutlineColor(pieceOultlineColor); cell.setOutlineColor(pieceOultlineColor);
cell.setPosition(this->getBoardBlockPosition(cellPosition.x, cellPosition.y)); cell.setPosition(this->getBoardBlockPosition(cellPosition.x, cellPosition.y));
this->renderWindow->draw(cell); this->renderWindow->draw(cell);
@@ -154,7 +166,9 @@ void GamePlayingAppMenu::drawFrame() const {
if (drawActivePiece) { if (drawActivePiece) {
// active piece // active piece
sf::Color pieceColor = this->getColorOfBlock(this->game.getActivePiece()->getBlockType(), -200 * (this->game.getLockDelayProgression())); sf::Color pieceColor = areBlockBones
? bonesBlockColor
: this->getColorOfBlock(this->game.getActivePiece()->getBlockType(), -200 * (this->game.getLockDelayProgression()));
for (const Position& position : this->game.getActivePiece()->getPositions()) { for (const Position& position : this->game.getActivePiece()->getPositions()) {
Position cellPosition = (this->game.getActivePiecePosition() + position); Position cellPosition = (this->game.getActivePiecePosition() + position);
@@ -173,7 +187,9 @@ void GamePlayingAppMenu::drawFrame() const {
nextBox.position.y -= upShift; nextBox.position.y -= upShift;
sf::Vector2f nextCellSize(this->nextCellSizeZoom, this->nextCellSizeZoom); sf::Vector2f nextCellSize(this->nextCellSizeZoom, this->nextCellSizeZoom);
sf::Color color = this->getColorOfBlock(this->game.getNextPieces().at(i).getBlockType(), 0); sf::Color pieceColor = areBlockBones
? bonesBlockColor
: this->getColorOfBlock(this->game.getNextPieces().at(i).getBlockType(), 0);
sf::Color boxColor = sf::Color(180, 180, 180); sf::Color boxColor = sf::Color(180, 180, 180);
int lowestRank = 0; int lowestRank = 0;
@@ -181,7 +197,7 @@ void GamePlayingAppMenu::drawFrame() const {
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).getPositions().contains(Position{x, y})) {
cell.setFillColor(color); cell.setFillColor(pieceColor);
lowestRank = y; lowestRank = y;
} }
else { else {
@@ -199,9 +215,11 @@ void GamePlayingAppMenu::drawFrame() const {
// hold box // hold box
if (this->game.getHeldPiece() != nullptr) { if (this->game.getHeldPiece() != nullptr) {
sf::Vector2f holdCellSize(this->holdCellSizeZoom, this->holdCellSizeZoom); sf::Vector2f holdCellSize(this->holdCellSizeZoom, this->holdCellSizeZoom);
sf::Color color = this->getColorOfBlock(this->game.getHeldPiece()->getBlockType(), 0); sf::Color color = areBlockBones
? bonesBlockColor
: this->getColorOfBlock(this->game.getHeldPiece()->getBlockType(), 0);
sf::Color boxColor = sf::Color(180, 180, 180); sf::Color boxColor = sf::Color(180, 180, 180);
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);
@@ -212,7 +230,7 @@ void GamePlayingAppMenu::drawFrame() const {
cell.setFillColor(boxColor); cell.setFillColor(boxColor);
} }
cell.setPosition(sf::Vector2f(this->holdBoxPosition.position.x + (x * this->nextCellSizeZoom), cell.setPosition(sf::Vector2f(this->holdBoxPosition.position.x + (x * this->nextCellSizeZoom),
this->holdBoxPosition.position.y + ((this->game.getHeldPiece()->getLength() - y - 1) * this->holdCellSizeZoom))); this->holdBoxPosition.position.y + ((this->game.getHeldPiece()->getLength() - y - 1) * this->holdCellSizeZoom)));
this->renderWindow->draw(cell); this->renderWindow->draw(cell);
} }
} }

View File

@@ -13,7 +13,7 @@
GameSettingsAppMenu::GameSettingsAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) : GameSettingsAppMenu::GameSettingsAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
AppMenu(menuStack, settings, renderWindow), AppMenu(menuStack, settings, renderWindow),
playerCursor({2, 3, 2}) { playerCursor({2, 3, 3}) {
} }
@@ -33,7 +33,8 @@ void GameSettingsAppMenu::computeFrame() {
case 2 : { case 2 : {
switch (this->playerCursor.getPosition().x) { switch (this->playerCursor.getPosition().x) {
case 0 : {this->settings->setGamemode(MASTER); break;} case 0 : {this->settings->setGamemode(MASTER); break;}
case 1 : {this->settings->setGamemode(ZEN); break;} case 1 : {this->settings->setGamemode(INVISIBLE); break;}
case 2 : {this->settings->setGamemode(ZEN); break;}
} }
break; break;
} }
@@ -76,7 +77,8 @@ void GameSettingsAppMenu::drawFrame() const {
this->placeText(text, this->playerCursor, "MARATHON", 25.f, 35.f, sf::Vector2u{1, 1}); this->placeText(text, this->playerCursor, "MARATHON", 25.f, 35.f, sf::Vector2u{1, 1});
this->placeText(text, this->playerCursor, "ULTRA", 50.f, 35.f, sf::Vector2u{2, 1}); this->placeText(text, this->playerCursor, "ULTRA", 50.f, 35.f, sf::Vector2u{2, 1});
this->placeText(text, this->playerCursor, "MASTER", 5.f, 45.f, sf::Vector2u{0, 2}); this->placeText(text, this->playerCursor, "MASTER", 5.f, 45.f, sf::Vector2u{0, 2});
this->placeText(text, this->playerCursor, "ZEN", 25.f, 45.f, sf::Vector2u{1, 2}); this->placeText(text, this->playerCursor, "INVISIBLE", 25.f, 45.f, sf::Vector2u{1, 2});
this->placeText(text, this->playerCursor, "ZEN", 50.f, 45.f, sf::Vector2u{2, 2});
this->renderWindow->display(); this->renderWindow->display();
} }

View File

@@ -11,14 +11,14 @@
InfoAppMenu::InfoAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) : InfoAppMenu::InfoAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
AppMenu(menuStack, settings, renderWindow), AppMenu(menuStack, settings, renderWindow),
playerCursor({INFO_SECTIONS_COUNT}), playerCursor({INFO_SECTIONS_COUNT}),
sectionsName( sectionsName({
"< ABOUT >", "< ABOUT >",
"< PIECES TYPES >", "< PIECES TYPES >",
"< 0 DEGREES ROTATIONS >", "< 0 DEGREES ROTATIONS >",
"< ROTATION SYSTEM >", "< ROTATION SYSTEM >",
"< SCORING >" "< SCORING >"
), }),
sectionsContent( sectionsContent({
"This game is written in C++,\n" "This game is written in C++,\n"
"using SFML 3 for the GUI.\n" "using SFML 3 for the GUI.\n"
"It has been inspired by other\n" "It has been inspired by other\n"
@@ -67,7 +67,7 @@ InfoAppMenu::InfoAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<S
"A spin is detected when the piece is\n" "A spin is detected when the piece is\n"
"locked in place, a mini-spin simply\n" "locked in place, a mini-spin simply\n"
"when the last move was a kick." "when the last move was a kick."
) { }) {
} }

View File

@@ -9,12 +9,11 @@
static const int INFO_SECTIONS_COUNT = 5; static const int INFO_SECTIONS_COUNT = 5;
class InfoAppMenu : public AppMenu { class InfoAppMenu : public AppMenu {
private: private:
PlayerCursor playerCursor; PlayerCursor playerCursor;
sf::String sectionsName[INFO_SECTIONS_COUNT]; std::array<std::string, INFO_SECTIONS_COUNT> sectionsName;
sf::String sectionsContent[INFO_SECTIONS_COUNT]; std::array<std::string, INFO_SECTIONS_COUNT> sectionsContent;
public: public:
InfoAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow); InfoAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow);

View File

@@ -15,7 +15,7 @@ int main() {
PiecesFiles pf; 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")) {
#ifdef NDEBUG #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; 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;
#endif #endif
@@ -23,8 +23,8 @@ int main() {
pf.savePieces(i); pf.savePieces(i);
} }
} }
#ifndef NDEBUG #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 everythingGenerated = true;
for (int i = DEBUG_PIECES_SIZE; i <= RELEASE_PIECES_SIZE; i++) { for (int i = DEBUG_PIECES_SIZE; i <= RELEASE_PIECES_SIZE; i++) {
@@ -33,7 +33,7 @@ int main() {
} }
} }
if (!everythingGenerated) { if (!everythingGenerated) {
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
@@ -70,7 +70,10 @@ int main() {
void resetSettingsFile() { void resetSettingsFile() {
std::filesystem::create_directories("data/config"); if (!std::filesystem::exists("data/config")) {
std::filesystem::create_directories("data/config");
}
std::ofstream settingsFile("data/config/settings.bin", std::ios::trunc | std::ios::binary); std::ofstream settingsFile("data/config/settings.bin", std::ios::trunc | std::ios::binary);
char byte; char byte;
@@ -138,7 +141,6 @@ void resetSettingsFile() {
void resetKeybindFile(int layout) { void resetKeybindFile(int layout) {
if (layout < 0 || layout > 4) return; if (layout < 0 || layout > 4) return;
std::filesystem::create_directories("data/config/keybinds/layout");
std::ofstream layoutFile("data/config/keybinds/layout" + std::to_string(layout) + ".bin", std::ios::trunc | std::ios::binary); 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;

View File

@@ -50,7 +50,7 @@ void Generator::generate(int polyominoSize, int lastAddedPositionNumber, int nex
} }
// generate the list of candidate positions // generate the list of candidate positions
for (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);
@@ -58,7 +58,7 @@ void Generator::generate(int polyominoSize, int lastAddedPositionNumber, int nex
} }
// 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 (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);

View File

@@ -10,7 +10,7 @@
#include <filesystem> #include <filesystem>
#include <algorithm> #include <algorithm>
namespace fs = std::filesystem; #include "../Common/Compression.h"
PiecesFiles::PiecesFiles() { PiecesFiles::PiecesFiles() {
@@ -21,10 +21,6 @@ bool PiecesFiles::savePieces(int polyominoSize) const {
if (!this->getFilePath(polyominoSize, filePath)) { if (!this->getFilePath(polyominoSize, filePath)) {
return false; return false;
} }
std::ofstream piecesFile(filePath, std::ios::trunc | std::ios::binary);
if (!piecesFile.good()) {
return false;
}
Generator generator; Generator generator;
std::vector<Polyomino> polyominoes = generator.generatePolyominoes(polyominoSize); std::vector<Polyomino> polyominoes = generator.generatePolyominoes(polyominoSize);
@@ -37,10 +33,9 @@ bool PiecesFiles::savePieces(int polyominoSize, std::vector<Polyomino>& polyomin
if (!this->getFilePath(polyominoSize, filePath)) { if (!this->getFilePath(polyominoSize, filePath)) {
return false; return false;
} }
std::ofstream piecesFile(filePath, std::ios::trunc | std::ios::binary);
if (!piecesFile.good()) { constexpr std::size_t INITIAL_CAPACITY = 2048;
return false; DataBuffer buffer(INITIAL_CAPACITY);
}
// sorting the polyominoes is done after setting spawn position to ensure the order is always the same // sorting the polyominoes is done after setting spawn position to ensure the order is always the same
for (Polyomino& nMino : polyominoes) { for (Polyomino& nMino : polyominoes) {
@@ -50,18 +45,22 @@ bool PiecesFiles::savePieces(int polyominoSize, std::vector<Polyomino>& polyomin
for (const Polyomino& polyomino : polyominoes) { for (const Polyomino& polyomino : polyominoes) {
// write the characteristics of the piece // write the characteristics of the piece
char infoByte = (polyomino.isConvex() << 7) + (polyomino.hasHole() << 6) + polyomino.getLength(); bool isConvex = polyomino.isConvex();
piecesFile.write(&infoByte, 1); bool hasHole = (isConvex) ? false : polyomino.hasHole();
std::uint8_t infoByte = (isConvex << 7) + (hasHole << 6) + polyomino.getLength();
buffer << infoByte;
// write the positions of the piece // write the positions of the piece
char positionByte; std::uint8_t positionByte;
for (const Position position : polyomino.getPositions()) { for (const Position position : polyomino.getPositions()) {
positionByte = (position.x << 4) + position.y; positionByte = (position.x << 4) + position.y;
piecesFile.write(&positionByte, 1); buffer << positionByte;
} }
} }
return true; DataBuffer compressed = Compress(buffer);
return compressed.WriteFile(filePath);
} }
bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std::vector<int>& convexPieces, std::vector<int>& holelessPieces, std::vector<int>& otherPieces) const { bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std::vector<int>& convexPieces, std::vector<int>& holelessPieces, std::vector<int>& otherPieces) const {
@@ -69,6 +68,13 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
if (!this->getFilePath(polyominoSize, filePath)) { if (!this->getFilePath(polyominoSize, filePath)) {
return false; return false;
} }
DataBuffer compressed;
if(!compressed.ReadFile(filePath))
return false;
DataBuffer buffer = Decompress(compressed, compressed.GetSize());
std::ifstream piecesFile(filePath, std::ios::binary); std::ifstream piecesFile(filePath, std::ios::binary);
if (!piecesFile.good()) { if (!piecesFile.good()) {
return false; return false;
@@ -91,10 +97,11 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
char xMask = 0b1111'0000; char xMask = 0b1111'0000;
char yMask = 0b0000'1111; char yMask = 0b0000'1111;
char infoByte; std::uint8_t infoByte;
int i = 0; int i = 0;
while (piecesFile.get(infoByte)) { while (!buffer.IsFinished()) {
if (piecesFile.eof()) break; // if (piecesFile.eof()) break;
buffer >> infoByte;
// read piece infos // read piece infos
bool isConvex = (infoByte & convexMask) >> 7; bool isConvex = (infoByte & convexMask) >> 7;
@@ -103,9 +110,9 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
// read positions // read positions
std::set<Position> piecePositions; std::set<Position> piecePositions;
char positionByte; std::uint8_t positionByte;
for (int i = 0; i < polyominoSize; i++) { for (int i = 0; i < polyominoSize; i++) {
piecesFile.get(positionByte); buffer >> positionByte;
int x = ((unsigned char) positionByte & xMask) >> 4; int x = ((unsigned char) positionByte & xMask) >> 4;
int y = positionByte & yMask; int y = positionByte & yMask;
piecePositions.insert(Position{x, y}); piecePositions.insert(Position{x, y});
@@ -135,11 +142,11 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
bool PiecesFiles::getFilePath(int polyominoSize, std::string& filePath) const { bool PiecesFiles::getFilePath(int polyominoSize, std::string& filePath) const {
std::string dataFolderPath = "data/pieces/"; std::string dataFolderPath = "data/pieces/";
if (!fs::exists(dataFolderPath)) { if (!std::filesystem::exists(dataFolderPath)) {
fs::create_directories(dataFolderPath); std::filesystem::create_directories(dataFolderPath);
} }
if (!fs::is_directory(dataFolderPath)) { if (!std::filesystem::is_directory(dataFolderPath)) {
return false; return false;
} }

View File

@@ -15,7 +15,7 @@ Polyomino::Polyomino(const std::set<Position>& positions) {
int maxX = INT_MIN; int maxX = INT_MIN;
int minY = INT_MAX; int minY = INT_MAX;
int maxY = INT_MIN; int maxY = INT_MIN;
for (Position position : positions) { for (const Position position : positions) {
if (position.x < minX) minX = position.x; if (position.x < minX) minX = position.x;
if (position.x > maxX) maxX = position.x; if (position.x > maxX) maxX = position.x;
if (position.y < minY) minY = position.y; if (position.y < minY) minY = position.y;
@@ -40,13 +40,13 @@ Polyomino::Polyomino(const std::set<Position>& positions, int length) :
void Polyomino::normalize() { void Polyomino::normalize() {
int minX = INT_MAX; int minX = INT_MAX;
int minY = INT_MAX; int minY = INT_MAX;
for (Position position : this->positions) { for (const Position position : this->positions) {
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; std::set<Position> newPositions;
for (Position position : this->positions) { for (const Position position : this->positions) {
newPositions.insert(Position{position.x - minX, position.y - minY}); newPositions.insert(Position{position.x - minX, position.y - minY});
} }
this->positions = std::move(newPositions); this->positions = std::move(newPositions);
@@ -54,7 +54,7 @@ void Polyomino::normalize() {
void Polyomino::rotateCW() { void Polyomino::rotateCW() {
std::set<Position> newPositions; std::set<Position> newPositions;
for (Position position : this->positions) { for (const Position position : this->positions) {
newPositions.insert(Position{position.y, (length - 1) - (position.x)}); newPositions.insert(Position{position.y, (length - 1) - (position.x)});
} }
this->positions = std::move(newPositions); this->positions = std::move(newPositions);
@@ -62,7 +62,7 @@ void Polyomino::rotateCW() {
void Polyomino::rotate180() { void Polyomino::rotate180() {
std::set<Position> newPositions; std::set<Position> newPositions;
for (Position position : this->positions) { for (const Position position : this->positions) {
newPositions.insert(Position{(length - 1) - (position.x), (length - 1) - (position.y)}); newPositions.insert(Position{(length - 1) - (position.x), (length - 1) - (position.y)});
} }
this->positions = std::move(newPositions); this->positions = std::move(newPositions);
@@ -70,7 +70,7 @@ void Polyomino::rotate180() {
void Polyomino::rotateCCW() { void Polyomino::rotateCCW() {
std::set<Position> newPositions; std::set<Position> newPositions;
for (Position position : this->positions) { for (const Position position : this->positions) {
newPositions.insert(Position{(length - 1) - (position.y), position.x}); newPositions.insert(Position{(length - 1) - (position.y), position.x});
} }
this->positions = std::move(newPositions); this->positions = std::move(newPositions);
@@ -89,7 +89,7 @@ void Polyomino::goToSpawnPosition() {
} }
// calculates amount of squares per rows and columns // calculates amount of squares per rows and columns
for (Position position : this->positions) { for (const Position position : this->positions) {
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
@@ -158,14 +158,14 @@ void Polyomino::goToSpawnPosition() {
int minX = INT_MAX; int minX = INT_MAX;
int minY = INT_MAX; int minY = INT_MAX;
for (Position position : this->positions) { for (const Position position : this->positions) {
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; std::set<Position> newPositions;
for (Position position : positions) { for (const Position position : positions) {
newPositions.insert(Position{(position.x - minX) + (verticalEmptyLines / 2), (position.y - minY) + ((horizontalEmptyLines + 1) / 2)}); newPositions.insert(Position{(position.x - minX) + (verticalEmptyLines / 2), (position.y - minY) + ((horizontalEmptyLines + 1) / 2)});
} }
this->positions = std::move(newPositions); this->positions = std::move(newPositions);

View File

@@ -22,11 +22,12 @@ int main(int argc, char** argv) {
std::srand(std::time(NULL)); std::srand(std::time(NULL));
#ifdef BENCHMARK #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
benchmarking(1, BENCHMARK_PIECES_SIZE); benchmarking(1, BENCHMARK_PIECES_SIZE);
#else #else
// dev: generate files if it hasn't been done before, UI will NOT generate the files
//generateFilesForAllSizes(10);
PiecesFiles pf; 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")) {
@@ -126,7 +127,7 @@ void benchmarking(int min_size, int max_size) {
using std::chrono::milliseconds; using std::chrono::milliseconds;
std::cout << "| n | Number | Generation | File storing | File retrieving | File size |" << std::endl; std::cout << "| n | Number | Generation | File storing | File retrieving | File size |" << std::endl;
std::cout << "| - | - | - | - | - | - |" << std::endl; std::cout << "| -: | -: | :-: | :-: | :-: | -: |" << std::endl;
Generator gen; Generator gen;
PiecesFiles pf; PiecesFiles pf;

View File

@@ -2,28 +2,44 @@
#include <map> #include <map>
static const unsigned char data_fonts_pressstart_prstart_ttf[] = {
#include <data/fonts/pressstart/prstart.ttf.h>
};
static const unsigned char data_fonts_pressstart_prstartk_ttf[] = { 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_fonts_pressstart_prstart_ttf[] = { static const unsigned char data_images_keybinds_Rotate180_png[] = {
#include <data/fonts/pressstart/prstart.ttf.h> #include <data/images/keybinds/Rotate180.png.h>
}; };
static const unsigned char data_images_keybinds_Rotate0_png[] = { static const unsigned char data_images_keybinds_Rotate0_png[] = {
#include <data/images/keybinds/Rotate0.png.h> #include <data/images/keybinds/Rotate0.png.h>
}; };
static const unsigned char data_images_keybinds_Moveright_png[] = { static const unsigned char data_images_keybinds_RotateCCW_png[] = {
#include <data/images/keybinds/Moveright.png.h> #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[] = { static const unsigned char data_images_keybinds_RotateCW_png[] = {
#include <data/images/keybinds/RotateCW.png.h> #include <data/images/keybinds/RotateCW.png.h>
}; };
static const unsigned char data_images_keybinds_Pause_png[] = { static const unsigned char data_images_keybinds_Moveright_png[] = {
#include <data/images/keybinds/Pause.png.h> #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[] = { static const unsigned char data_images_keybinds_Hold_png[] = {
@@ -34,57 +50,41 @@ 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_RotateCCW_png[] = { static const unsigned char data_images_keybinds_Pause_png[] = {
#include <data/images/keybinds/RotateCCW.png.h> #include <data/images/keybinds/Pause.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_Rotate180_png[] = {
#include <data/images/keybinds/Rotate180.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_Harddrop_png[] = {
#include <data/images/keybinds/Harddrop.png.h>
}; };
static const Asset assets[] = { static const Asset assets[] = {
{data_fonts_pressstart_prstartk_ttf, sizeof(data_fonts_pressstart_prstartk_ttf)},
{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_images_keybinds_Rotate180_png, sizeof(data_images_keybinds_Rotate180_png)},
{data_images_keybinds_Rotate0_png, sizeof(data_images_keybinds_Rotate0_png)}, {data_images_keybinds_Rotate0_png, sizeof(data_images_keybinds_Rotate0_png)},
{data_images_keybinds_Moveright_png, sizeof(data_images_keybinds_Moveright_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_RotateCW_png, sizeof(data_images_keybinds_RotateCW_png)},
{data_images_keybinds_Pause_png, sizeof(data_images_keybinds_Pause_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_Hold_png, sizeof(data_images_keybinds_Hold_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_RotateCCW_png, sizeof(data_images_keybinds_RotateCCW_png)}, {data_images_keybinds_Pause_png, sizeof(data_images_keybinds_Pause_png)},
{data_images_keybinds_Moveleft_png, sizeof(data_images_keybinds_Moveleft_png)},
{data_images_keybinds_Rotate180_png, sizeof(data_images_keybinds_Rotate180_png)},
{data_images_keybinds_Retry_png, sizeof(data_images_keybinds_Retry_png)},
{data_images_keybinds_Harddrop_png, sizeof(data_images_keybinds_Harddrop_png)},
}; };
static const std::map<std::string, AssetName> assetMap = { static const std::map<std::string, AssetName> assetMap = {
{"data/fonts/pressstart/prstartk.ttf", AssetName::data_fonts_pressstart_prstartk_ttf},
{"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/images/keybinds/Rotate180.png", AssetName::data_images_keybinds_Rotate180_png},
{"data/images/keybinds/Rotate0.png", AssetName::data_images_keybinds_Rotate0_png}, {"data/images/keybinds/Rotate0.png", AssetName::data_images_keybinds_Rotate0_png},
{"data/images/keybinds/Moveright.png", AssetName::data_images_keybinds_Moveright_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/RotateCW.png", AssetName::data_images_keybinds_RotateCW_png},
{"data/images/keybinds/Pause.png", AssetName::data_images_keybinds_Pause_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/Hold.png", AssetName::data_images_keybinds_Hold_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/RotateCCW.png", AssetName::data_images_keybinds_RotateCCW_png}, {"data/images/keybinds/Pause.png", AssetName::data_images_keybinds_Pause_png},
{"data/images/keybinds/Moveleft.png", AssetName::data_images_keybinds_Moveleft_png},
{"data/images/keybinds/Rotate180.png", AssetName::data_images_keybinds_Rotate180_png},
{"data/images/keybinds/Retry.png", AssetName::data_images_keybinds_Retry_png},
{"data/images/keybinds/Harddrop.png", AssetName::data_images_keybinds_Harddrop_png},
}; };

View File

@@ -9,19 +9,19 @@ struct Asset {
}; };
enum class AssetName { enum class AssetName {
data_fonts_pressstart_prstartk_ttf,
data_fonts_pressstart_prstart_ttf, data_fonts_pressstart_prstart_ttf,
data_fonts_pressstart_prstartk_ttf,
data_images_keybinds_Rotate180_png,
data_images_keybinds_Rotate0_png, data_images_keybinds_Rotate0_png,
data_images_keybinds_Moveright_png, data_images_keybinds_RotateCCW_png,
data_images_keybinds_Retry_png,
data_images_keybinds_RotateCW_png, data_images_keybinds_RotateCW_png,
data_images_keybinds_Pause_png, data_images_keybinds_Moveright_png,
data_images_keybinds_Harddrop_png,
data_images_keybinds_Moveleft_png,
data_images_keybinds_Hold_png, data_images_keybinds_Hold_png,
data_images_keybinds_Softdrop_png, data_images_keybinds_Softdrop_png,
data_images_keybinds_RotateCCW_png, data_images_keybinds_Pause_png,
data_images_keybinds_Moveleft_png,
data_images_keybinds_Rotate180_png,
data_images_keybinds_Retry_png,
data_images_keybinds_Harddrop_png,
}; };

View File

@@ -2,7 +2,7 @@ add_rules("mode.debug", "mode.release")
includes("xmake/bin2c.lua") includes("xmake/bin2c.lua")
add_requires("sfml 3.0.0") add_requires("sfml 3.0.0", "zlib")
set_languages("c++20") set_languages("c++20")
@@ -10,8 +10,21 @@ set_rundir(".")
target("core") target("core")
set_kind("$(kind)") set_kind("$(kind)")
add_files("src/Pieces/*.cpp") add_files("src/Pieces/*.cpp", "src/Core/*.cpp", "src/Common/*.cpp")
add_files("src/Core/*.cpp") add_packages("zlib")
target("text")
set_default(false)
set_kind("binary")
add_files("./src/TextUI/*.cpp")
add_deps("core")
target("bmark")
set_default(false)
set_kind("binary")
add_files("./src/TextUI/*.cpp")
add_deps("core")
add_defines("BENCHMARK")
target("graph") target("graph")
set_default(true) set_default(true)
@@ -26,18 +39,13 @@ target("graph")
add_deps("core") add_deps("core")
add_packages("sfml") add_packages("sfml")
target("text") if is_mode("debug") then
set_default(false) add_defines("DEBUG")
set_kind("binary") end
add_files("./src/TextUI/*.cpp")
add_deps("core")
target("benchmark") if is_plat("mingw") then
set_default(false) add_ldflags("-static-libstdc++", "-static")
set_kind("binary") end
add_files("./src/TextUI/*.cpp")
add_deps("core")
add_defines("BENCHMARK")
-- --