initial commit

This commit is contained in:
2025-02-25 12:07:16 +01:00
commit 0657bc9b25
34 changed files with 3069 additions and 0 deletions

85
src/Pieces/Generator.cpp Normal file
View File

@@ -0,0 +1,85 @@
#include "Generator.h"
#include "Polyomino.h"
#include <Vector>
#include <Set>
#include <Map>
#include <algorithm>
Generator::Generator() {
}
std::vector<Polyomino> Generator::generatePolyominos(unsigned int order) {
// initialization
this->validPolyominos.clear();
this->currentTestedShape.clear();
// no polyomino with 0 cells
if (order == 0) return this->validPolyominos;
// start generating from the monomino
this->currentTestedShape.insert(Cell{0, 0});
// generate polyominos
std::map<Cell, int> candidateCells;
this->generate(order, 0, 1, candidateCells);
return this->validPolyominos;
}
void Generator::generate(unsigned int order, int lastAddedCellNumber, int nextAvaibleNumber, std::map<Cell, int> candidateCells) {
// recursion stop
if (order == this->currentTestedShape.size()) {
// we test the polyomino formed by the current shape
Polyomino candidate(this->currentTestedShape);
// we sort the rotations of the polyominos
std::vector<Polyomino> candidateRotations;
for (int i = 0; i < 4; i++) {
candidate.normalize();
candidateRotations.push_back(candidate);
if (!(i==3)) candidate.rotateCW();
}
std::sort(candidateRotations.begin(), candidateRotations.end());
// we keep the polyomino only if it was generated in its lowest rotation
if (candidate == candidateRotations.at(0)) {
this->validPolyominos.push_back(candidate);
}
return;
}
// generate the list of candidate cells
for (Cell cell : this->currentTestedShape) {
this->tryToAddCandidateCell(Cell{cell.x, cell.y + 1}, nextAvaibleNumber, candidateCells);
this->tryToAddCandidateCell(Cell{cell.x + 1, cell.y}, nextAvaibleNumber, candidateCells);
this->tryToAddCandidateCell(Cell{cell.x, cell.y - 1}, nextAvaibleNumber, candidateCells);
this->tryToAddCandidateCell(Cell{cell.x - 1, cell.y}, nextAvaibleNumber, candidateCells);
}
// generate polyominos for all cells with a higher number than the last one
for (auto [key, val] : candidateCells) {
if (val > lastAddedCellNumber) {
this->currentTestedShape.insert(key);
this->generate(order, val, nextAvaibleNumber, (order == this->currentTestedShape.size()) ? std::map<Cell, int>() : candidateCells);
this->currentTestedShape.erase(key);
}
}
}
void Generator::tryToAddCandidateCell(const Cell& candidate, int& nextAvaibleNumber, std::map<Cell, int>& candidateCells) {
// we declared the first cell as the lower-left square, since we always start with a monomino at (0,0) we can test with hard values
if (candidate.y < 0 || (candidate.y == 0 && candidate.x < 0)) return;
// if the cell was already marked then we should not mark it again
if (candidateCells.contains(candidate)) return;
// if the candidate overlaps with the shape there is no reason to add it
if (this->currentTestedShape.contains(candidate)) return;
// once all tests passed we can add the cell
candidateCells.insert({candidate, nextAvaibleNumber});
nextAvaibleNumber++;
}