This commit is contained in:
@@ -35,7 +35,7 @@ Bag::Bag(const std::shared_ptr<PiecesList>& piecesList) :
|
||||
}
|
||||
|
||||
for (const auto& piece : this->selectedPieces) {
|
||||
int pieceSize = this->piecesList->lookAtPiece(piece).getPositions().size();
|
||||
int pieceSize = this->piecesList->lookAtPiece(piece).getPositions().getSize();
|
||||
this->currentBags.at(pieceSize).push_back(piece);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
Piece::Piece(Polyomino&& polyomino, Block blockType) :
|
||||
polyomino(polyomino),
|
||||
blockType(blockType),
|
||||
rotationState(NONE),
|
||||
positions(polyomino.getPositions()) {
|
||||
rotationState(NONE) {
|
||||
}
|
||||
|
||||
void Piece::rotate(Rotation rotation) {
|
||||
@@ -25,7 +24,6 @@ void Piece::rotate(Rotation rotation) {
|
||||
this->polyomino.rotateCCW();
|
||||
|
||||
this->rotationState += rotation;
|
||||
this->positions = polyomino.getPositions();
|
||||
}
|
||||
|
||||
void Piece::defaultRotation() {
|
||||
@@ -37,11 +35,10 @@ void Piece::defaultRotation() {
|
||||
this->polyomino.rotateCW();
|
||||
|
||||
this->rotationState = NONE;
|
||||
this->positions = polyomino.getPositions();
|
||||
}
|
||||
|
||||
const std::vector<Position>& Piece::getPositions() const {
|
||||
return this->positions;
|
||||
const Polyomino& Piece::getPositions() const {
|
||||
return this->polyomino;
|
||||
}
|
||||
|
||||
int Piece::getLength() const {
|
||||
|
||||
@@ -16,7 +16,6 @@ class Piece {
|
||||
Polyomino polyomino; // a polyomino representing the piece, (0, 0) is downleft
|
||||
Block blockType; // the block type of the piece
|
||||
Rotation rotationState; // the current rotation of the piece
|
||||
std::vector<Position> positions; // cache positions for easier use (particularly UI)
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -37,7 +36,7 @@ class Piece {
|
||||
/**
|
||||
* @return The list of positions of the piece
|
||||
*/
|
||||
const std::vector<Position>& getPositions() const;
|
||||
const Polyomino& getPositions() const;
|
||||
|
||||
/**
|
||||
* @param the position of the square
|
||||
|
||||
@@ -53,14 +53,15 @@ bool PiecesFiles::savePieces(int polyominoSize, std::vector<Polyomino>& polyomin
|
||||
const int bitsNeeded = polyomino.getLength() * polyomino.getLength();
|
||||
const int bytesNeeded = bitsNeeded / 8 + 1;
|
||||
|
||||
static const Polyomino::PolyominoData byteMask = 0xFF;
|
||||
const Polyomino::PolyominoData& polyominoData = polyomino.getPositionsData();
|
||||
|
||||
// write the positions of the piece
|
||||
for (int i = 0; i < bytesNeeded; i++) {
|
||||
buffer << static_cast<std::uint8_t>(
|
||||
(
|
||||
polyomino.getPositionsData()[i / sizeof(std::uint64_t)] >>
|
||||
(56 - ((i % sizeof(std::uint64_t)) * 8))
|
||||
)
|
||||
& 0xFF);
|
||||
Polyomino::PolyominoData pData = polyominoData >> (i * 8);
|
||||
unsigned long data =
|
||||
(pData & byteMask).to_ulong();
|
||||
buffer << static_cast<std::uint8_t>(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,8 +122,8 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
|
||||
|
||||
for (int j = 0; j < bytesNeeded; j++) {
|
||||
buffer >> positionByte;
|
||||
polyominoData[j / sizeof(std::uint64_t)] |=
|
||||
(static_cast<std::uint64_t>(positionByte) << (56 - ((j % sizeof(std::uint64_t)) * 8)));
|
||||
Polyomino::PolyominoData tempByte(positionByte);
|
||||
polyominoData |= (tempByte << (j * 8));
|
||||
}
|
||||
|
||||
pieces.emplace_back(Polyomino(std::move(polyominoData), length), pieceBlock);
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#include <climits>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
|
||||
Polyomino::Polyomino(std::set<Position>&& positions) {
|
||||
Polyomino::Polyomino(std::set<Position>&& positions) : positions(0) {
|
||||
int minX = INT_MAX;
|
||||
int maxX = INT_MIN;
|
||||
int minY = INT_MAX;
|
||||
@@ -24,11 +25,11 @@ Polyomino::Polyomino(std::set<Position>&& positions) {
|
||||
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);
|
||||
Polyomino newPolyomino({}, this->length);
|
||||
for (Position position : positions) {
|
||||
temp.insert(Position(position.x - minX, position.y - minY));
|
||||
newPolyomino.insert(Position(position.x - minX, position.y - minY));
|
||||
}
|
||||
this->positions = std::move(temp.positions);
|
||||
this->positions = std::move(newPolyomino.positions);
|
||||
}
|
||||
|
||||
Polyomino::Polyomino(PolyominoData&& positions, std::int8_t length) :
|
||||
@@ -39,24 +40,21 @@ Polyomino::Polyomino(PolyominoData&& positions, std::int8_t length) :
|
||||
void Polyomino::normalize() {
|
||||
int minX = INT_MAX;
|
||||
int minY = INT_MAX;
|
||||
|
||||
std::vector<Position> tempPositions = getPositions();
|
||||
|
||||
for (const Position position : tempPositions) {
|
||||
for (const Position position : *this) {
|
||||
if (position.x < minX) minX = position.x;
|
||||
if (position.y < minY) minY = position.y;
|
||||
}
|
||||
|
||||
Polyomino temp({}, this->length);
|
||||
for (const Position position : tempPositions) {
|
||||
temp.insert(Position(position.x - minX, position.y - minY));
|
||||
Polyomino newPolyomino({}, this->length);
|
||||
for (const Position position : *this) {
|
||||
newPolyomino.insert(Position(position.x - minX, position.y - minY));
|
||||
}
|
||||
this->positions = std::move(temp.positions);
|
||||
this->positions = std::move(newPolyomino.positions);
|
||||
}
|
||||
|
||||
void Polyomino::rotateCW() {
|
||||
Polyomino temp({}, this->length);
|
||||
for (const Position position : getPositions()) {
|
||||
for (const Position position : *this) {
|
||||
temp.insert(Position(position.y, (length - 1) - (position.x)));
|
||||
}
|
||||
this->positions = std::move(temp.positions);
|
||||
@@ -64,7 +62,7 @@ void Polyomino::rotateCW() {
|
||||
|
||||
void Polyomino::rotate180() {
|
||||
Polyomino temp({}, this->length);
|
||||
for (const Position position : getPositions()) {
|
||||
for (const Position position : *this) {
|
||||
temp.insert(Position((length - 1) - (position.x), (length - 1) - (position.y)));
|
||||
}
|
||||
this->positions = std::move(temp.positions);
|
||||
@@ -72,7 +70,7 @@ void Polyomino::rotate180() {
|
||||
|
||||
void Polyomino::rotateCCW() {
|
||||
Polyomino temp({}, this->length);
|
||||
for (const Position position : getPositions()) {
|
||||
for (const Position position : *this) {
|
||||
temp.insert(Position((length - 1) - (position.y), position.x));
|
||||
}
|
||||
this->positions = std::move(temp.positions);
|
||||
@@ -91,7 +89,7 @@ void Polyomino::goToSpawnPosition() {
|
||||
}
|
||||
|
||||
// calculates amount of squares per rows and columns
|
||||
for (const Position position : getPositions()) {
|
||||
for (const Position position : *this) {
|
||||
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(2).at((length - 1) - position.y) += 1; // 2 = top to bottom = 180
|
||||
@@ -158,18 +156,17 @@ void Polyomino::goToSpawnPosition() {
|
||||
std::swap(verticalEmptyLines, horizontalEmptyLines);
|
||||
}
|
||||
|
||||
std::vector<Position> tempPositions = getPositions();
|
||||
|
||||
int minX = INT_MAX;
|
||||
int minY = INT_MAX;
|
||||
for (const Position position : tempPositions) {
|
||||
for (const Position position : *this) {
|
||||
if (position.x < minX) minX = position.x;
|
||||
if (position.y < minY) minY = position.y;
|
||||
}
|
||||
|
||||
// center the piece with an up bias
|
||||
Polyomino temp({}, this->length);
|
||||
for (const Position position : tempPositions) {
|
||||
for (const Position position : *this) {
|
||||
temp.insert(Position((position.x - minX) + (verticalEmptyLines / 2), (position.y - minY) + ((horizontalEmptyLines + 1) / 2)));
|
||||
}
|
||||
this->positions = std::move(temp.positions);
|
||||
@@ -242,19 +239,19 @@ bool Polyomino::isConvex() const {
|
||||
|
||||
bool Polyomino::hasHole() const {
|
||||
// add every empty square on the outer of the box containing the polyomino
|
||||
std::set<Position> emptyPositions;
|
||||
Polyomino temp({}, this->length);
|
||||
for (int i = 0; i < this->length - 1; i++) {
|
||||
this->tryToInsertPosition(emptyPositions, Position(i, 0)); // up row
|
||||
this->tryToInsertPosition(emptyPositions, Position(this->length - 1, i)); // rigth column
|
||||
this->tryToInsertPosition(emptyPositions, Position(this->length - 1 - i, this->length - 1)); // bottom row
|
||||
this->tryToInsertPosition(emptyPositions, Position(0, this->length - 1 - i)); // left column
|
||||
this->tryToInsertPosition(temp, Position(i, 0)); // up row
|
||||
this->tryToInsertPosition(temp, Position(this->length - 1, i)); // rigth column
|
||||
this->tryToInsertPosition(temp, Position(this->length - 1 - i, this->length - 1)); // bottom row
|
||||
this->tryToInsertPosition(temp, Position(0, this->length - 1 - i)); // left column
|
||||
}
|
||||
|
||||
// if we didn't reached all empty squares in the box then there was some contained within the polyomino, i.e. there was a hole
|
||||
return (emptyPositions.size() < (this->length * this->length) - this->positions.size());
|
||||
return (temp.getSize() < (this->length * this->length) - this->positions.size());
|
||||
}
|
||||
|
||||
void Polyomino::tryToInsertPosition(std::set<Position>& emptyPositions, const Position& candidate) const {
|
||||
void Polyomino::tryToInsertPosition(Polyomino& emptyPositions, const Position& candidate) const {
|
||||
if (candidate.x >= this->length || candidate.x < 0 || candidate.y >= this->length || candidate.y < 0) return;
|
||||
if (this->contains(candidate) || emptyPositions.contains(candidate)) return;
|
||||
|
||||
@@ -270,21 +267,6 @@ const Polyomino::PolyominoData& Polyomino::getPositionsData() const {
|
||||
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 - 1)) {
|
||||
result.push_back(Position(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Polyomino::getLength() const {
|
||||
return this->length;
|
||||
}
|
||||
@@ -296,9 +278,16 @@ int Polyomino::getPolyominoSize() const {
|
||||
bool Polyomino::operator<(const Polyomino& other) const {
|
||||
if (this->length != other.length) return this->length < other.length;
|
||||
|
||||
for (std::size_t i = 0; i < this->positions.size(); i++) {
|
||||
if (this->positions[i] != other.positions[i]) {
|
||||
return this->positions[i] < other.positions[i];
|
||||
assert(other.positions.any() && "The other polyomino is empty !");
|
||||
|
||||
static const PolyominoData longMask = 0xFFFFFFFFFFFFFFFF;
|
||||
const int longsNeeded = this->length * this->length / 64 + 1;
|
||||
|
||||
for (int i = 0; i < longsNeeded; i++) {
|
||||
unsigned long l1 = (this->positions >> (i * sizeof(std::uint64_t)) & longMask).to_ulong();
|
||||
unsigned long l2 = (other.positions >> (i * sizeof(std::uint64_t)) & longMask).to_ulong();
|
||||
if (l1 != l2) {
|
||||
return l1 < l2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,23 +313,30 @@ std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino) {
|
||||
return os;
|
||||
}
|
||||
|
||||
int Polyomino::getSize() const {
|
||||
return positions.count();
|
||||
}
|
||||
|
||||
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 - 1);
|
||||
return this->positions[getBitIndex(position)];
|
||||
}
|
||||
|
||||
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 - 1);
|
||||
this->positions.set(getBitIndex(position), true);
|
||||
}
|
||||
|
||||
void Polyomino::erase(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 - 1));
|
||||
this->positions.set(getBitIndex(position), false);
|
||||
}
|
||||
|
||||
std::size_t Polyomino::getBitIndex(const Position& position) const {
|
||||
return position.y * this->length + position.x;
|
||||
}
|
||||
|
||||
Polyomino::ConstIterator Polyomino::begin() const {
|
||||
return ConstIterator(*this, positions._Find_first());
|
||||
}
|
||||
|
||||
Polyomino::ConstIterator Polyomino::end() const {
|
||||
return ConstIterator(*this, positions.size());
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
|
||||
|
||||
/**
|
||||
@@ -13,8 +14,44 @@
|
||||
*/
|
||||
class Polyomino {
|
||||
public:
|
||||
static const std::size_t POLYOMINO_DATA_SIZE = 4;
|
||||
using PolyominoData = std::array<std::uint64_t, POLYOMINO_DATA_SIZE>;
|
||||
static const std::size_t MAX_LENGTH = 16;
|
||||
using PolyominoData = std::bitset<MAX_LENGTH * MAX_LENGTH>;
|
||||
|
||||
class ConstIterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = Position;
|
||||
using const_pointer = const Position*; // or also value_type*
|
||||
using const_reference = const Position&; // or also value_type&
|
||||
public:
|
||||
ConstIterator(const Polyomino& polyomino, std::size_t index) : m_Polyomino(polyomino), m_Index(index) {
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
const_reference operator*() const { return m_Position; }
|
||||
const_pointer operator->() { return &m_Position; }
|
||||
|
||||
// Prefix increment
|
||||
ConstIterator& operator++() {
|
||||
m_Index = m_Polyomino.getPositionsData()._Find_next(m_Index);
|
||||
updatePosition();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
friend bool operator== (const ConstIterator& a, const ConstIterator& b) { return a.m_Index == b.m_Index; };
|
||||
friend bool operator!= (const ConstIterator& a, const ConstIterator& b) { return a.m_Index != b.m_Index; };
|
||||
|
||||
private:
|
||||
void updatePosition() {
|
||||
m_Position = Position(m_Index % m_Polyomino.getLength(), m_Index / m_Polyomino.getLength());
|
||||
}
|
||||
|
||||
const Polyomino& m_Polyomino;
|
||||
std::size_t m_Index;
|
||||
Position m_Position;
|
||||
};
|
||||
|
||||
private:
|
||||
PolyominoData positions; // the squares composing the polyomino, stored in binary. MSB is downleft
|
||||
@@ -79,7 +116,7 @@ class Polyomino {
|
||||
/**
|
||||
* Auxiliary method of hasHole()
|
||||
*/
|
||||
void tryToInsertPosition(std::set<Position>& emptypositions, const Position& candidate) const;
|
||||
void tryToInsertPosition(Polyomino& emptypositions, const Position& candidate) const;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -87,16 +124,21 @@ class Polyomino {
|
||||
*/
|
||||
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
|
||||
*/
|
||||
int getLength() const;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int getSize() const;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
std::size_t getBitIndex(const Position& position) const;
|
||||
|
||||
/**
|
||||
* @return The number of squares in the polyomino
|
||||
*/
|
||||
@@ -135,4 +177,8 @@ class Polyomino {
|
||||
* @brief Removes a square at the position
|
||||
*/
|
||||
void erase(const Position& position);
|
||||
|
||||
ConstIterator begin() const;
|
||||
|
||||
ConstIterator end() const;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user