begin optimize Generator
Some checks failed
Linux arm64 / Build (push) Failing after 2m4s

This commit is contained in:
2025-07-19 23:39:22 +02:00
parent d5b51213c8
commit 46b9b8dd65
8 changed files with 158 additions and 59 deletions

View File

@@ -345,7 +345,7 @@ std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
// print only the position were the active piece is // print only the position were the active piece is
for (int y = gameboard.activePiecePosition.y + gameboard.activePiece->getLength() - 1; y >= gameboard.board.getBaseHeight(); y--) { for (int y = gameboard.activePiecePosition.y + gameboard.activePiece->getLength() - 1; y >= gameboard.board.getBaseHeight(); y--) {
for (int x = 0; x < gameboard.board.getWidth(); x++) { for (int x = 0; x < gameboard.board.getWidth(); x++) {
bool hasActivePiece = gameboard.activePiece->getPositions().contains(Position(x, y) - gameboard.activePiecePosition); bool hasActivePiece = gameboard.activePiece->containsSquare(Position(x, y) - gameboard.activePiecePosition);
if (hasActivePiece) { if (hasActivePiece) {
os << "*"; os << "*";
} }
@@ -361,7 +361,7 @@ std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
Block pieceBlockType = (gameboard.activePiece == nullptr) ? NOTHING : gameboard.activePiece->getBlockType(); Block pieceBlockType = (gameboard.activePiece == nullptr) ? NOTHING : gameboard.activePiece->getBlockType();
for (int y = gameboard.board.getBaseHeight() - 1; y >= 0; y--) { for (int y = gameboard.board.getBaseHeight() - 1; y >= 0; y--) {
for (int x = 0; x < gameboard.board.getWidth(); x++) { for (int x = 0; x < gameboard.board.getWidth(); x++) {
bool hasActivePiece = (gameboard.activePiece == nullptr) ? false : gameboard.activePiece->getPositions().contains(Position(x, y) - gameboard.activePiecePosition); bool hasActivePiece = (gameboard.activePiece == nullptr) ? false : gameboard.activePiece->containsSquare(Position(x, y) - gameboard.activePiecePosition);
// the active piece takes visual priority over the board // the active piece takes visual priority over the board
if (hasActivePiece) { if (hasActivePiece) {

View File

@@ -196,7 +196,7 @@ void GamePlayingAppMenu::drawFrame() const {
for (int y = 0; y < this->game.getNextPieces().at(i).getLength(); y++) { for (int y = 0; y < this->game.getNextPieces().at(i).getLength(); y++) {
for (int x = 0; x < this->game.getNextPieces().at(i).getLength(); x++) { for (int x = 0; x < this->game.getNextPieces().at(i).getLength(); x++) {
sf::RectangleShape cell(nextCellSize); sf::RectangleShape cell(nextCellSize);
if (this->game.getNextPieces().at(i).getPositions().contains(Position(x, y))) { if (this->game.getNextPieces().at(i).containsSquare(Position(x, y))) {
cell.setFillColor(pieceColor); cell.setFillColor(pieceColor);
lowestRank = y; lowestRank = y;
} }
@@ -223,7 +223,7 @@ void GamePlayingAppMenu::drawFrame() const {
for (int y = 0; y < this->game.getHeldPiece()->getLength(); y++) { for (int y = 0; y < this->game.getHeldPiece()->getLength(); y++) {
for (int x = 0; x < this->game.getHeldPiece()->getLength(); x++) { for (int x = 0; x < this->game.getHeldPiece()->getLength(); x++) {
sf::RectangleShape cell(holdCellSize); sf::RectangleShape cell(holdCellSize);
if (this->game.getHeldPiece()->getPositions().contains(Position(x, y))) { if (this->game.getHeldPiece()->containsSquare(Position(x, y))) {
cell.setFillColor(color); cell.setFillColor(color);
} }
else { else {

View File

@@ -29,7 +29,7 @@ std::vector<Polyomino>&& Generator::generatePolyominoes(int polyominoSize) {
void Generator::generate(int polyominoSize, int lastAddedPositionNumber, int nextAvaibleNumber, std::map<Position, int> candidatePositions) { void Generator::generate(int polyominoSize, int lastAddedPositionNumber, int nextAvaibleNumber, std::map<Position, int> candidatePositions) {
// recursion stop // recursion stop
if (polyominoSize == this->currentTestedShape.size()) { if (polyominoSize == this->currentTestedShape.size()) {
Polyomino candidate(this->currentTestedShape); Polyomino candidate(std::move(this->currentTestedShape));
// we sort the rotations of the polyominoes // we sort the rotations of the polyominoes
std::vector<Polyomino> candidateRotations; std::vector<Polyomino> candidateRotations;

View File

@@ -11,9 +11,9 @@
Piece::Piece(const Polyomino& polyomino, Block blockType) : Piece::Piece(const Polyomino& polyomino, Block blockType) :
polyomino(polyomino), polyomino(polyomino),
blockType(blockType) { blockType(blockType),
rotationState(NONE),
this->rotationState = NONE; positions(polyomino.getPositions()) {
} }
void Piece::rotate(Rotation rotation) { void Piece::rotate(Rotation rotation) {
@@ -25,6 +25,7 @@ void Piece::rotate(Rotation rotation) {
this->polyomino.rotateCCW(); this->polyomino.rotateCCW();
this->rotationState += rotation; this->rotationState += rotation;
this->positions = polyomino.getPositions();
} }
void Piece::defaultRotation() { void Piece::defaultRotation() {
@@ -36,10 +37,11 @@ void Piece::defaultRotation() {
this->polyomino.rotateCW(); this->polyomino.rotateCW();
this->rotationState = NONE; this->rotationState = NONE;
this->positions = polyomino.getPositions();
} }
const std::set<Position>& Piece::getPositions() const { const std::vector<Position>& Piece::getPositions() const {
return this->polyomino.getPositions(); return this->positions;
} }
int Piece::getLength() const { int Piece::getLength() const {
@@ -54,3 +56,7 @@ std::ostream& operator<<(std::ostream& os, const Piece& piece) {
os << getConsoleColorCode(piece.blockType) << piece.polyomino << getResetConsoleColorCode(); os << getConsoleColorCode(piece.blockType) << piece.polyomino << getResetConsoleColorCode();
return os; return os;
} }
bool Piece::containsSquare(const Position& position) const {
return polyomino.contains(position);
}

View File

@@ -16,6 +16,7 @@ class Piece {
Polyomino polyomino; // a polyomino representing the piece, (0, 0) is downleft Polyomino polyomino; // a polyomino representing the piece, (0, 0) is downleft
Block blockType; // the block type of the piece Block blockType; // the block type of the piece
Rotation rotationState; // the current rotation of the piece Rotation rotationState; // the current rotation of the piece
std::vector<Position> positions; // cache positions for easier use (particularly UI)
public: public:
/** /**
@@ -36,7 +37,13 @@ class Piece {
/** /**
* @return The list of positions of the piece * @return The list of positions of the piece
*/ */
const std::set<Position>& getPositions() const; const std::vector<Position>& getPositions() const;
/**
* @param the position of the square
* @return false if there is a hole
*/
bool containsSquare(const Position& position) const;
/** /**
* @return The length of the piece * @return The length of the piece

View File

@@ -119,7 +119,7 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
} }
// create piece // create piece
Piece readPiece(Polyomino(piecePositions, length), pieceBlock); Piece readPiece(Polyomino(std::move(piecePositions), length), pieceBlock);
nextPieceBlockType(pieceBlock); nextPieceBlockType(pieceBlock);
pieces.push_back(readPiece); pieces.push_back(readPiece);

View File

@@ -9,8 +9,7 @@
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
Polyomino::Polyomino(std::set<Position>&& positions) {
Polyomino::Polyomino(const std::set<Position>& positions) {
int minX = INT_MAX; int minX = INT_MAX;
int maxX = INT_MIN; int maxX = INT_MIN;
int minY = INT_MAX; int minY = INT_MAX;
@@ -25,55 +24,90 @@ Polyomino::Polyomino(const std::set<Position>& positions) {
this->length = std::max(maxX - minX + 1, maxY - minY + 1); this->length = std::max(maxX - minX + 1, maxY - minY + 1);
// we normalize here instead of calling this->normalize() to reduce the number of calculations for the generation algorithm // we normalize here instead of calling this->normalize() to reduce the number of calculations for the generation algorithm
std::set<Position> newPositions; Polyomino temp(PolyominoData{}, this->length);
for (Position position : positions) { for (Position position : positions) {
newPositions.insert(Position(position.x - minX, position.y - minY)); temp.insert(Position(position.x - minX, position.y - minY));
} }
this->positions = std::move(newPositions); this->positions = std::move(temp.positions);
} }
Polyomino::Polyomino(const std::set<Position>& positions, std::int8_t length) : Polyomino::Polyomino(std::set<Position>&& positions, std::int8_t length) : positions(), length(length){
positions(positions), for (Position position : positions) {
insert(position);
}
}
Polyomino::Polyomino(PolyominoData&& positions) : positions(positions) {
int minX = INT_MAX;
int maxX = INT_MIN;
int minY = INT_MAX;
int maxY = INT_MIN;
// tout s'appelle positions, osekour !
std::vector<Position> tempPositions = getPositions();
for (const Position position : tempPositions) {
if (position.x < minX) minX = position.x;
if (position.x > maxX) maxX = position.x;
if (position.y < minY) minY = position.y;
if (position.y > maxY) maxY = position.y;
}
this->length = std::max(maxX - minX + 1, maxY - minY + 1);
// we normalize here instead of calling this->normalize() to reduce the number of calculations for the generation algorithm
Polyomino temp(PolyominoData{}, this->length);
for (Position position : tempPositions) {
temp.insert(Position(position.x - minX, position.y - minY));
}
this->positions = std::move(temp.positions);
}
Polyomino::Polyomino(PolyominoData&& positions, std::int8_t length) :
positions(std::move(positions)),
length(length) { length(length) {
} }
void Polyomino::normalize() { void Polyomino::normalize() {
int minX = INT_MAX; int minX = INT_MAX;
int minY = INT_MAX; int minY = INT_MAX;
for (const Position position : this->positions) {
std::vector<Position> tempPositions = getPositions();
for (const Position position : tempPositions) {
if (position.x < minX) minX = position.x; if (position.x < minX) minX = position.x;
if (position.y < minY) minY = position.y; if (position.y < minY) minY = position.y;
} }
std::set<Position> newPositions; Polyomino temp(PolyominoData{}, this->length);
for (const Position position : this->positions) { for (const Position position : tempPositions) {
newPositions.insert(Position(position.x - minX, position.y - minY)); temp.insert(Position(position.x - minX, position.y - minY));
} }
this->positions = std::move(newPositions); this->positions = std::move(temp.positions);
} }
void Polyomino::rotateCW() { void Polyomino::rotateCW() {
std::set<Position> newPositions; Polyomino temp(PolyominoData{}, this->length);
for (const Position position : this->positions) { for (const Position position : getPositions()) {
newPositions.insert(Position(position.y, (length - 1) - (position.x))); temp.insert(Position(position.y, (length - 1) - (position.x)));
} }
this->positions = std::move(newPositions); this->positions = std::move(temp.positions);
} }
void Polyomino::rotate180() { void Polyomino::rotate180() {
std::set<Position> newPositions; Polyomino temp(PolyominoData{}, this->length);
for (const Position position : this->positions) { for (const Position position : getPositions()) {
newPositions.insert(Position((length - 1) - (position.x), (length - 1) - (position.y))); temp.insert(Position((length - 1) - (position.x), (length - 1) - (position.y)));
} }
this->positions = std::move(newPositions); this->positions = std::move(temp.positions);
} }
void Polyomino::rotateCCW() { void Polyomino::rotateCCW() {
std::set<Position> newPositions; Polyomino temp(PolyominoData{}, this->length);
for (const Position position : this->positions) { for (const Position position : getPositions()) {
newPositions.insert(Position((length - 1) - (position.y), position.x)); temp.insert(Position((length - 1) - (position.y), position.x));
} }
this->positions = std::move(newPositions); this->positions = std::move(temp.positions);
} }
void Polyomino::goToSpawnPosition() { void Polyomino::goToSpawnPosition() {
@@ -89,7 +123,7 @@ void Polyomino::goToSpawnPosition() {
} }
// calculates amount of squares per rows and columns // calculates amount of squares per rows and columns
for (const Position position : this->positions) { for (const Position position : getPositions()) {
linesCompleteness.at(0).at(position.y) += 1; // 0 = bottom to top = no rotation linesCompleteness.at(0).at(position.y) += 1; // 0 = bottom to top = no rotation
linesCompleteness.at(1).at((length - 1) - position.x) += 1; // 1 = right to left = CW linesCompleteness.at(1).at((length - 1) - position.x) += 1; // 1 = right to left = CW
linesCompleteness.at(2).at((length - 1) - position.y) += 1; // 2 = top to bottom = 180 linesCompleteness.at(2).at((length - 1) - position.y) += 1; // 2 = top to bottom = 180
@@ -156,19 +190,21 @@ void Polyomino::goToSpawnPosition() {
std::swap(verticalEmptyLines, horizontalEmptyLines); std::swap(verticalEmptyLines, horizontalEmptyLines);
} }
std::vector<Position> tempPositions = getPositions();
int minX = INT_MAX; int minX = INT_MAX;
int minY = INT_MAX; int minY = INT_MAX;
for (const Position position : this->positions) { for (const Position position : tempPositions) {
if (position.x < minX) minX = position.x; if (position.x < minX) minX = position.x;
if (position.y < minY) minY = position.y; if (position.y < minY) minY = position.y;
} }
// center the piece with an up bias // center the piece with an up bias
std::set<Position> newPositions; Polyomino temp(PolyominoData{}, this->length);
for (const Position position : positions) { for (const Position position : tempPositions) {
newPositions.insert(Position((position.x - minX) + (verticalEmptyLines / 2), (position.y - minY) + ((horizontalEmptyLines + 1) / 2))); temp.insert(Position((position.x - minX) + (verticalEmptyLines / 2), (position.y - minY) + ((horizontalEmptyLines + 1) / 2)));
} }
this->positions = std::move(newPositions); this->positions = std::move(temp.positions);
} }
void Polyomino::checkForFlattestSide(const std::vector<std::vector<int>>& linesCompleteness, bool currentFlattestSides[4], int& sideToBeOn, bool checkLeftSide) const { void Polyomino::checkForFlattestSide(const std::vector<std::vector<int>>& linesCompleteness, bool currentFlattestSides[4], int& sideToBeOn, bool checkLeftSide) const {
@@ -216,7 +252,7 @@ bool Polyomino::isConvex() const {
bool startedColumn = false; bool startedColumn = false;
bool completedColumn = false; bool completedColumn = false;
for (int i = 0; i < this->length; i++) { for (int i = 0; i < this->length; i++) {
if (this->positions.contains(Position(i, j))) { if (this->contains(Position(i, j))) {
if (completedLine) return false; if (completedLine) return false;
else startedLine = true; else startedLine = true;
} }
@@ -224,7 +260,7 @@ bool Polyomino::isConvex() const {
if (startedLine) completedLine = true; if (startedLine) completedLine = true;
} }
if (this->positions.contains(Position(j, i))) { if (this->contains(Position(j, i))) {
if (completedColumn) return false; if (completedColumn) return false;
else startedColumn = true; else startedColumn = true;
} }
@@ -252,7 +288,7 @@ bool Polyomino::hasHole() const {
void Polyomino::tryToInsertPosition(std::set<Position>& emptyPositions, const Position& candidate) const { void Polyomino::tryToInsertPosition(std::set<Position>& emptyPositions, const Position& candidate) const {
if (candidate.x >= this->length || candidate.x < 0 || candidate.y >= this->length || candidate.y < 0) return; if (candidate.x >= this->length || candidate.x < 0 || candidate.y >= this->length || candidate.y < 0) return;
if (this->positions.contains(candidate) || emptyPositions.contains(candidate)) return; if (this->contains(candidate) || emptyPositions.contains(candidate)) return;
// if it's a new empty square, try its neighbors // if it's a new empty square, try its neighbors
emptyPositions.insert(candidate); emptyPositions.insert(candidate);
@@ -262,10 +298,25 @@ void Polyomino::tryToInsertPosition(std::set<Position>& emptyPositions, const Po
tryToInsertPosition(emptyPositions, Position(candidate.x - 1, candidate.y)); tryToInsertPosition(emptyPositions, Position(candidate.x - 1, candidate.y));
} }
const std::set<Position>& Polyomino::getPositions() const { const PolyominoData& Polyomino::getPositionsData() const {
return this->positions; return this->positions;
} }
std::vector<Position> Polyomino::getPositions() const {
std::vector<Position> result;
for (int y = 0; y < this->length; y++) {
for (int x = 0; x < this->length; x++) {
int posIndex = y * this->length + x;
int longIndex = posIndex / (sizeof(std::uint64_t) * 8);
int bitIndex = posIndex % (sizeof(std::uint64_t) * 8);
if (this->positions[longIndex] & static_cast<std::uint64_t>(1) << (sizeof(std::uint64_t) * 8 - bitIndex)) {
result.push_back(Position(x, y));
}
}
}
return result;
}
int Polyomino::getLength() const { int Polyomino::getLength() const {
return this->length; return this->length;
} }
@@ -277,13 +328,12 @@ int Polyomino::getPolyominoSize() const {
bool Polyomino::operator<(const Polyomino& other) const { bool Polyomino::operator<(const Polyomino& other) const {
if (this->length != other.length) return this->length < other.length; if (this->length != other.length) return this->length < other.length;
for (int y = this->length - 1; y >= 0; y--) { for (int i = 0; i < this->positions.size(); i++) {
for (int x = 0; x < this->length; x++) { if (this->positions[i] != other.positions[i]) {
bool hasThisPosition = this->positions.contains(Position(x, y)); return this->positions[i] < other.positions[i];
bool hasOtherPosition = other.positions.contains(Position(x, y));
if (hasThisPosition != hasOtherPosition) return hasThisPosition;
} }
} }
return false; return false;
} }
@@ -294,7 +344,7 @@ bool Polyomino::operator==(const Polyomino& other) const {
std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino) { std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino) {
for (int y = polyomino.length - 1; y >= 0; y--) { for (int y = polyomino.length - 1; y >= 0; y--) {
for (int x = 0; x < polyomino.length; x++) { for (int x = 0; x < polyomino.length; x++) {
if (polyomino.positions.contains(Position(x, y))) { if (polyomino.contains(Position(x, y))) {
os << "*"; os << "*";
} }
else { else {
@@ -305,3 +355,17 @@ std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino) {
} }
return os; return os;
} }
bool Polyomino::contains(const Position& position) const {
int posIndex = position.y * this->length + position.x;
int longIndex = posIndex / (sizeof(std::uint64_t) * 8);
int bitIndex = posIndex % (sizeof(std::uint64_t) * 8);
return this->positions[longIndex] & static_cast<std::uint64_t>(1) << (sizeof(std::uint64_t) * 8 - bitIndex);
}
void Polyomino::insert(const Position& position) {
int posIndex = position.y * this->length + position.x;
int longIndex = posIndex / (sizeof(std::uint64_t) * 8);
int bitIndex = posIndex % (sizeof(std::uint64_t) * 8);
this->positions[longIndex] |= static_cast<std::uint64_t>(1) << (sizeof(std::uint64_t) * 8 - bitIndex);
}

View File

@@ -5,26 +5,32 @@
#include <vector> #include <vector>
#include <set> #include <set>
#include <iostream> #include <iostream>
#include <array>
using PolyominoData = std::array<std::uint64_t, 4>;
/** /**
* A mathematical object consisting of touching squares on a 2D grid * A mathematical object consisting of touching squares on a 2D grid
*/ */
class Polyomino { class Polyomino {
private: private:
std::set<Position> positions; // the squares composing the polyomino, (0,0) is downleft PolyominoData positions; // the squares composing the polyomino, stored in binary. MSB is downleft
std::int8_t length; // the size of the smallest square box in which the polyomino can fit on any rotation std::int8_t length; // the size of the smallest square box in which the polyomino can fit on any rotation
public: public:
/** /**
* Creates a polyomino with the specified positions and normalizes it, wheter it is actually a polyonimo is not checked * Creates a polyomino with the specified positions and normalizes it, wheter it is actually a polyonimo is not checked
*/ */
Polyomino(const std::set<Position>& positions); Polyomino(PolyominoData&& positions);
/** /**
* Creates a polyomino with the specified positions and length, wheter it is actually a polyonimo of this length is not checked * Creates a polyomino with the specified positions and length, wheter it is actually a polyonimo of this length is not checked
*/ */
Polyomino(const std::set<Position>& positions, std::int8_t length); Polyomino(PolyominoData&& positions, std::int8_t length);
// this is temporary. They are here for compatibility reasons for now
Polyomino(std::set<Position>&& positions);
Polyomino(std::set<Position>&& positions, std::int8_t length);
/** /**
* Translates the polyomino to the lowest unsigned values (lower row on y = 0, and left-most column on x = 0) * Translates the polyomino to the lowest unsigned values (lower row on y = 0, and left-most column on x = 0)
@@ -70,7 +76,7 @@ class Polyomino {
*/ */
bool hasHole() const; bool hasHole() const;
private : private:
/** /**
* Auxiliary method of hasHole() * Auxiliary method of hasHole()
*/ */
@@ -78,9 +84,14 @@ class Polyomino {
public: public:
/** /**
* @return The positions of the polyomino * @return The positions data of the polyomino
*/ */
const std::set<Position>& getPositions() const; const PolyominoData& getPositionsData() const;
/**
* @return The positions of the polyomino (deduces it from the binary representation)
*/
std::vector<Position> getPositions() const;
/** /**
* @return The length of the polyomino * @return The length of the polyomino
@@ -110,4 +121,15 @@ class Polyomino {
* @return A reference to the output stream * @return A reference to the output stream
*/ */
friend std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino); friend std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino);
/**
* @return True if it contains the position
*/
bool contains(const Position& position) const;
private:
/**
* @brief Insert a square at the position
*/
void insert(const Position& position);
}; };