This commit is contained in:
@@ -345,7 +345,7 @@ std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
|
||||
// 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 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) {
|
||||
os << "*";
|
||||
}
|
||||
@@ -361,7 +361,7 @@ std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
|
||||
Block pieceBlockType = (gameboard.activePiece == nullptr) ? NOTHING : gameboard.activePiece->getBlockType();
|
||||
for (int y = gameboard.board.getBaseHeight() - 1; y >= 0; y--) {
|
||||
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
|
||||
if (hasActivePiece) {
|
||||
|
||||
@@ -196,7 +196,7 @@ void GamePlayingAppMenu::drawFrame() const {
|
||||
for (int y = 0; y < this->game.getNextPieces().at(i).getLength(); y++) {
|
||||
for (int x = 0; x < this->game.getNextPieces().at(i).getLength(); x++) {
|
||||
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);
|
||||
lowestRank = y;
|
||||
}
|
||||
@@ -223,7 +223,7 @@ void GamePlayingAppMenu::drawFrame() const {
|
||||
for (int y = 0; y < this->game.getHeldPiece()->getLength(); y++) {
|
||||
for (int x = 0; x < this->game.getHeldPiece()->getLength(); x++) {
|
||||
sf::RectangleShape cell(holdCellSize);
|
||||
if (this->game.getHeldPiece()->getPositions().contains(Position(x, y))) {
|
||||
if (this->game.getHeldPiece()->containsSquare(Position(x, y))) {
|
||||
cell.setFillColor(color);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -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) {
|
||||
// recursion stop
|
||||
if (polyominoSize == this->currentTestedShape.size()) {
|
||||
Polyomino candidate(this->currentTestedShape);
|
||||
Polyomino candidate(std::move(this->currentTestedShape));
|
||||
|
||||
// we sort the rotations of the polyominoes
|
||||
std::vector<Polyomino> candidateRotations;
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
Piece::Piece(const Polyomino& polyomino, Block blockType) :
|
||||
polyomino(polyomino),
|
||||
blockType(blockType) {
|
||||
|
||||
this->rotationState = NONE;
|
||||
blockType(blockType),
|
||||
rotationState(NONE),
|
||||
positions(polyomino.getPositions()) {
|
||||
}
|
||||
|
||||
void Piece::rotate(Rotation rotation) {
|
||||
@@ -25,6 +25,7 @@ void Piece::rotate(Rotation rotation) {
|
||||
this->polyomino.rotateCCW();
|
||||
|
||||
this->rotationState += rotation;
|
||||
this->positions = polyomino.getPositions();
|
||||
}
|
||||
|
||||
void Piece::defaultRotation() {
|
||||
@@ -36,10 +37,11 @@ void Piece::defaultRotation() {
|
||||
this->polyomino.rotateCW();
|
||||
|
||||
this->rotationState = NONE;
|
||||
this->positions = polyomino.getPositions();
|
||||
}
|
||||
|
||||
const std::set<Position>& Piece::getPositions() const {
|
||||
return this->polyomino.getPositions();
|
||||
const std::vector<Position>& Piece::getPositions() const {
|
||||
return this->positions;
|
||||
}
|
||||
|
||||
int Piece::getLength() const {
|
||||
@@ -54,3 +56,7 @@ std::ostream& operator<<(std::ostream& os, const Piece& piece) {
|
||||
os << getConsoleColorCode(piece.blockType) << piece.polyomino << getResetConsoleColorCode();
|
||||
return os;
|
||||
}
|
||||
|
||||
bool Piece::containsSquare(const Position& position) const {
|
||||
return polyomino.contains(position);
|
||||
}
|
||||
@@ -16,6 +16,7 @@ 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:
|
||||
/**
|
||||
@@ -36,7 +37,13 @@ class 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
|
||||
|
||||
@@ -119,7 +119,7 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
|
||||
}
|
||||
|
||||
// create piece
|
||||
Piece readPiece(Polyomino(piecePositions, length), pieceBlock);
|
||||
Piece readPiece(Polyomino(std::move(piecePositions), length), pieceBlock);
|
||||
nextPieceBlockType(pieceBlock);
|
||||
|
||||
pieces.push_back(readPiece);
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
|
||||
Polyomino::Polyomino(const std::set<Position>& positions) {
|
||||
Polyomino::Polyomino(std::set<Position>&& positions) {
|
||||
int minX = INT_MAX;
|
||||
int maxX = INT_MIN;
|
||||
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);
|
||||
|
||||
// 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) {
|
||||
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) :
|
||||
positions(positions),
|
||||
Polyomino::Polyomino(std::set<Position>&& positions, std::int8_t length) : positions(), length(length){
|
||||
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) {
|
||||
}
|
||||
|
||||
void Polyomino::normalize() {
|
||||
int minX = 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.y < minY) minY = position.y;
|
||||
}
|
||||
|
||||
std::set<Position> newPositions;
|
||||
for (const Position position : this->positions) {
|
||||
newPositions.insert(Position(position.x - minX, position.y - minY));
|
||||
Polyomino temp(PolyominoData{}, this->length);
|
||||
for (const Position position : tempPositions) {
|
||||
temp.insert(Position(position.x - minX, position.y - minY));
|
||||
}
|
||||
this->positions = std::move(newPositions);
|
||||
this->positions = std::move(temp.positions);
|
||||
}
|
||||
|
||||
void Polyomino::rotateCW() {
|
||||
std::set<Position> newPositions;
|
||||
for (const Position position : this->positions) {
|
||||
newPositions.insert(Position(position.y, (length - 1) - (position.x)));
|
||||
Polyomino temp(PolyominoData{}, this->length);
|
||||
for (const Position position : getPositions()) {
|
||||
temp.insert(Position(position.y, (length - 1) - (position.x)));
|
||||
}
|
||||
this->positions = std::move(newPositions);
|
||||
this->positions = std::move(temp.positions);
|
||||
}
|
||||
|
||||
void Polyomino::rotate180() {
|
||||
std::set<Position> newPositions;
|
||||
for (const Position position : this->positions) {
|
||||
newPositions.insert(Position((length - 1) - (position.x), (length - 1) - (position.y)));
|
||||
Polyomino temp(PolyominoData{}, this->length);
|
||||
for (const Position position : getPositions()) {
|
||||
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() {
|
||||
std::set<Position> newPositions;
|
||||
for (const Position position : this->positions) {
|
||||
newPositions.insert(Position((length - 1) - (position.y), position.x));
|
||||
Polyomino temp(PolyominoData{}, this->length);
|
||||
for (const Position position : getPositions()) {
|
||||
temp.insert(Position((length - 1) - (position.y), position.x));
|
||||
}
|
||||
this->positions = std::move(newPositions);
|
||||
this->positions = std::move(temp.positions);
|
||||
}
|
||||
|
||||
void Polyomino::goToSpawnPosition() {
|
||||
@@ -89,7 +123,7 @@ void Polyomino::goToSpawnPosition() {
|
||||
}
|
||||
|
||||
// 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(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
|
||||
@@ -156,19 +190,21 @@ void Polyomino::goToSpawnPosition() {
|
||||
std::swap(verticalEmptyLines, horizontalEmptyLines);
|
||||
}
|
||||
|
||||
std::vector<Position> tempPositions = getPositions();
|
||||
|
||||
int minX = 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.y < minY) minY = position.y;
|
||||
}
|
||||
|
||||
// center the piece with an up bias
|
||||
std::set<Position> newPositions;
|
||||
for (const Position position : positions) {
|
||||
newPositions.insert(Position((position.x - minX) + (verticalEmptyLines / 2), (position.y - minY) + ((horizontalEmptyLines + 1) / 2)));
|
||||
Polyomino temp(PolyominoData{}, this->length);
|
||||
for (const Position position : tempPositions) {
|
||||
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 {
|
||||
@@ -216,7 +252,7 @@ bool Polyomino::isConvex() const {
|
||||
bool startedColumn = false;
|
||||
bool completedColumn = false;
|
||||
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;
|
||||
else startedLine = true;
|
||||
}
|
||||
@@ -224,7 +260,7 @@ bool Polyomino::isConvex() const {
|
||||
if (startedLine) completedLine = true;
|
||||
}
|
||||
|
||||
if (this->positions.contains(Position(j, i))) {
|
||||
if (this->contains(Position(j, i))) {
|
||||
if (completedColumn) return false;
|
||||
else startedColumn = true;
|
||||
}
|
||||
@@ -252,7 +288,7 @@ bool Polyomino::hasHole() 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 (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
|
||||
emptyPositions.insert(candidate);
|
||||
@@ -262,10 +298,25 @@ void Polyomino::tryToInsertPosition(std::set<Position>& emptyPositions, const Po
|
||||
tryToInsertPosition(emptyPositions, Position(candidate.x - 1, candidate.y));
|
||||
}
|
||||
|
||||
const std::set<Position>& Polyomino::getPositions() const {
|
||||
const 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)) {
|
||||
result.push_back(Position(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Polyomino::getLength() const {
|
||||
return this->length;
|
||||
}
|
||||
@@ -277,13 +328,12 @@ int Polyomino::getPolyominoSize() const {
|
||||
bool Polyomino::operator<(const Polyomino& other) const {
|
||||
if (this->length != other.length) return this->length < other.length;
|
||||
|
||||
for (int y = this->length - 1; y >= 0; y--) {
|
||||
for (int x = 0; x < this->length; x++) {
|
||||
bool hasThisPosition = this->positions.contains(Position(x, y));
|
||||
bool hasOtherPosition = other.positions.contains(Position(x, y));
|
||||
if (hasThisPosition != hasOtherPosition) return hasThisPosition;
|
||||
for (int i = 0; i < this->positions.size(); i++) {
|
||||
if (this->positions[i] != other.positions[i]) {
|
||||
return this->positions[i] < other.positions[i];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -294,7 +344,7 @@ bool Polyomino::operator==(const Polyomino& other) const {
|
||||
std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino) {
|
||||
for (int y = polyomino.length - 1; y >= 0; y--) {
|
||||
for (int x = 0; x < polyomino.length; x++) {
|
||||
if (polyomino.positions.contains(Position(x, y))) {
|
||||
if (polyomino.contains(Position(x, y))) {
|
||||
os << "*";
|
||||
}
|
||||
else {
|
||||
@@ -305,3 +355,17 @@ std::ostream& operator<<(std::ostream& os, const Polyomino& polyomino) {
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -5,26 +5,32 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
using PolyominoData = std::array<std::uint64_t, 4>;
|
||||
|
||||
/**
|
||||
* A mathematical object consisting of touching squares on a 2D grid
|
||||
*/
|
||||
class Polyomino {
|
||||
private:
|
||||
std::set<Position> positions; // the squares composing the polyomino, (0,0) is downleft
|
||||
std::int8_t length; // the size of the smallest square box in which the polyomino can fit on any rotation
|
||||
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
|
||||
|
||||
public:
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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)
|
||||
@@ -70,7 +76,7 @@ class Polyomino {
|
||||
*/
|
||||
bool hasHole() const;
|
||||
|
||||
private :
|
||||
private:
|
||||
/**
|
||||
* Auxiliary method of hasHole()
|
||||
*/
|
||||
@@ -78,9 +84,14 @@ class Polyomino {
|
||||
|
||||
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
|
||||
@@ -110,4 +121,15 @@ class Polyomino {
|
||||
* @return A reference to the output stream
|
||||
*/
|
||||
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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user