156 lines
4.4 KiB
C++
156 lines
4.4 KiB
C++
#include "PiecesFiles.h"
|
|
|
|
#include "Generator.h"
|
|
#include "Piece.h"
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <filesystem>
|
|
#include <algorithm>
|
|
|
|
#include "../Common/Compression.h"
|
|
|
|
|
|
PiecesFiles::PiecesFiles() {
|
|
}
|
|
|
|
bool PiecesFiles::savePieces(int polyominoSize) const {
|
|
std::string filePath;
|
|
if (!this->getFilePath(polyominoSize, filePath)) {
|
|
return false;
|
|
}
|
|
|
|
Generator generator;
|
|
std::vector<Polyomino> polyominoes = generator.generatePolyominoes(polyominoSize);
|
|
|
|
return this->savePieces(polyominoSize, polyominoes);
|
|
}
|
|
|
|
bool PiecesFiles::savePieces(int polyominoSize, std::vector<Polyomino>& polyominoes) const {
|
|
std::string filePath;
|
|
if (!this->getFilePath(polyominoSize, filePath)) {
|
|
return false;
|
|
}
|
|
|
|
constexpr std::size_t INITIAL_CAPACITY = 2048;
|
|
DataBuffer buffer(INITIAL_CAPACITY);
|
|
|
|
// sorting the polyominoes is done after setting spawn position to ensure the order is always the same
|
|
for (Polyomino& nMino : polyominoes) {
|
|
nMino.goToSpawnPosition();
|
|
}
|
|
std::sort(polyominoes.begin(), polyominoes.end());
|
|
|
|
for (const Polyomino& polyomino : polyominoes) {
|
|
// write the characteristics of the piece
|
|
bool isConvex = polyomino.isConvex();
|
|
bool hasHole = (isConvex) ? false : polyomino.hasHole();
|
|
std::uint8_t infoByte = (isConvex << 7) + (hasHole << 6) + polyomino.getLength();
|
|
buffer << infoByte;
|
|
|
|
// write the positions of the piece
|
|
std::uint8_t positionByte;
|
|
for (const Position position : polyomino.getPositions()) {
|
|
positionByte = (position.x << 4) + position.y;
|
|
buffer << positionByte;
|
|
}
|
|
}
|
|
|
|
DataBuffer compressed = Compress(buffer);
|
|
|
|
return compressed.WriteFile(filePath);
|
|
}
|
|
|
|
bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std::vector<int>& convexPieces, std::vector<int>& holelessPieces, std::vector<int>& otherPieces) const {
|
|
std::string filePath;
|
|
if (!this->getFilePath(polyominoSize, filePath)) {
|
|
return false;
|
|
}
|
|
|
|
DataBuffer compressed;
|
|
if(!compressed.ReadFile(filePath))
|
|
return false;
|
|
|
|
DataBuffer buffer = Decompress(compressed, compressed.GetSize());
|
|
|
|
std::ifstream piecesFile(filePath, std::ios::binary);
|
|
if (!piecesFile.good()) {
|
|
return false;
|
|
}
|
|
|
|
pieces.clear();
|
|
convexPieces.clear();
|
|
holelessPieces.clear();
|
|
otherPieces.clear();
|
|
|
|
// we shift the first color of each size so that the small polyominoes (size 1-2-3) don't all have the same color
|
|
Block pieceBlock = firstPieceBlockType();
|
|
for (int i = 0; i < polyominoSize; i++) {
|
|
nextPieceBlockType(pieceBlock);
|
|
}
|
|
|
|
char convexMask = 0b1000'0000;
|
|
char holeMask = 0b0100'0000;
|
|
char lengthMask = 0b0011'1111;
|
|
char xMask = 0b1111'0000;
|
|
char yMask = 0b0000'1111;
|
|
|
|
std::uint8_t infoByte;
|
|
int i = 0;
|
|
while (!buffer.IsFinished()) {
|
|
// if (piecesFile.eof()) break;
|
|
buffer >> infoByte;
|
|
|
|
// read piece infos
|
|
bool isConvex = (infoByte & convexMask) >> 7;
|
|
bool hasHole = (infoByte & holeMask) >> 6;
|
|
int length = (infoByte & lengthMask);
|
|
|
|
// read positions
|
|
std::set<Position> piecePositions;
|
|
std::uint8_t positionByte;
|
|
for (int i = 0; i < polyominoSize; i++) {
|
|
buffer >> positionByte;
|
|
int x = ((unsigned char) positionByte & xMask) >> 4;
|
|
int y = positionByte & yMask;
|
|
piecePositions.insert(Position(x, y));
|
|
}
|
|
|
|
// create piece
|
|
Piece readPiece(Polyomino(std::move(piecePositions), length), pieceBlock);
|
|
nextPieceBlockType(pieceBlock);
|
|
|
|
pieces.push_back(readPiece);
|
|
if (isConvex) {
|
|
convexPieces.push_back(i);
|
|
}
|
|
else if (hasHole) {
|
|
otherPieces.push_back(i);
|
|
}
|
|
else {
|
|
holelessPieces.push_back(i);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool PiecesFiles::getFilePath(int polyominoSize, std::string& filePath) const {
|
|
std::string dataFolderPath = "data/pieces/";
|
|
|
|
if (!std::filesystem::exists(dataFolderPath)) {
|
|
std::filesystem::create_directories(dataFolderPath);
|
|
}
|
|
|
|
if (!std::filesystem::is_directory(dataFolderPath)) {
|
|
return false;
|
|
}
|
|
|
|
filePath = dataFolderPath + std::to_string(polyominoSize) + "minos.bin";
|
|
return true;
|
|
}
|