initial commit
This commit is contained in:
85
src/Pieces/Generator.cpp
Normal file
85
src/Pieces/Generator.cpp
Normal 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++;
|
||||
}
|
||||
Reference in New Issue
Block a user