added distribution modes

This commit is contained in:
2025-03-29 18:48:37 +01:00
parent 3538403f40
commit 57620c70a2
9 changed files with 246 additions and 28 deletions

View File

@@ -7,26 +7,54 @@
#include <utility>
#include <cstdlib>
static const double SMALLEST_CONSIDERED_PROPORTION = 0.01; // the smallest a proportion can get before it is considered equal to 0
Bag::Bag(const std::shared_ptr<PiecesList>& piecesList) :
piecesList(piecesList) {
this->currentBag = this->piecesList->getSelectedPieces();
this->nextBag.clear();
this->highestSize = this->piecesList->getHighestLoadedSize();
this->selectedPieces = this->piecesList->getSelectedPieces();
this->distributionMode = this->piecesList->getDistributionMode();
this->propotionsPerSize = this->piecesList->getProportionsPerSize();
this->currentBags.clear();
this->nextBags.clear();
this->sizesBag.clear();
this->sizesProgression.clear();
if (this->distributionMode == DEFAULT) {
this->currentBags.push_back(this->selectedPieces);
this->nextBags.push_back({});
}
else {
for (int i = 0; i <= this->highestSize; i++) {
this->currentBags.push_back(PieceBag());
this->nextBags.push_back(PieceBag());
this->sizesProgression.push_back(0);
}
for (const auto& piece : this->selectedPieces) {
int pieceSize = this->piecesList->lookAtPiece(piece).getPositions().size();
this->currentBags.at(pieceSize).push_back(piece);
}
}
this->prepareNext();
}
void Bag::jumpToNextBag() {
if (this->currentBag.size() < this->nextBag.size()) {
std::swap(this->currentBag, this->nextBag);
for (int i = 0; i < this->currentBags.size(); i++) {
if (this->currentBags.at(i).size() < this->nextBags.at(i).size()) {
std::swap(this->currentBags.at(i), this->nextBags.at(i));
}
for (const auto& piece : this->nextBags.at(i)) {
this->currentBags.at(i).push_back(piece);
}
this->nextBags.at(i).clear();
}
for (const std::pair<int, int>& pieceIndex : this->nextBag) {
this->currentBag.push_back(pieceIndex);
}
this->nextBag.clear();
this->prepareNext();
}
@@ -43,13 +71,40 @@ Piece Bag::getNext() {
}
void Bag::prepareNext() {
if (this->currentBag.empty()) {
std::swap(this->currentBag, this->nextBag);
if (this->distributionMode == DEFAULT) {
this->getNextPieceFromBag(0);
}
else {
if (this->sizesBag.empty()) {
for (int i = 0; i <= this->highestSize; i++) {
if (this->propotionsPerSize.at(i) >= SMALLEST_CONSIDERED_PROPORTION
&& !(this->currentBags.at(i).empty() && this->nextBags.at(i).empty())) {
while (this->sizesProgression.at(i) < 1) {
this->sizesBag.push_back(i);
this->sizesProgression.at(i) += this->propotionsPerSize.at(i);
}
this->sizesProgression.at(i) -= 1;
}
}
}
int nextSizeIndex = std::rand() % this->sizesBag.size();
int nextSize = this->sizesBag.at(nextSizeIndex);
this->sizesBag.erase(this->sizesBag.begin() + nextSizeIndex);
this->getNextPieceFromBag(nextSize);
}
}
void Bag::getNextPieceFromBag(int bagIndex) {
if (this->currentBags.at(bagIndex).empty()) {
std::swap(this->currentBags.at(bagIndex), this->nextBags.at(bagIndex));
}
int indexIndex = std::rand() % this->currentBag.size();
this->next = this->currentBag.at(indexIndex);
int indexIndex = std::rand() % this->currentBags.at(bagIndex).size();
this->next = this->currentBags.at(bagIndex).at(indexIndex);
this->nextBag.push_back(this->next);
this->currentBag.erase(this->currentBag.begin() + indexIndex);
this->nextBags.at(bagIndex).push_back(this->next);
this->currentBags.at(bagIndex).erase(this->currentBags.at(bagIndex).begin() + indexIndex);
}

View File

@@ -7,6 +7,8 @@
#include <memory>
#include <utility>
using PieceBag = std::vector<std::pair<int, int>>;
/**
* A litteral bag of pieces, in which you take each of its piece randomly one by one then start again with a new bag
@@ -14,10 +16,15 @@
class Bag {
private:
std::shared_ptr<PiecesList> piecesList; // the list of loaded pieces
int highestSize; // the highest size of piece in the bag
std::vector<std::pair<int, int>> selectedPieces; // the list of pieces that can be given to the player
PiecesDistributionMode distributionMode; // the distribution mode
std::vector<double> propotionsPerSize; // the proportion of pieces for each size
std::pair<int, int> next; // the next piece to give
std::vector<std::pair<int, int>> currentBag; // the list of pieces that are still to be taken out before starting a new bag
std::vector<std::pair<int, int>> nextBag; // the list of pieces that have been taken out of the current bag and have been placed in the next
std::vector<PieceBag> currentBags; // for each size, the list of pieces that are still to be taken out before starting a new bag
std::vector<PieceBag> nextBags; // for each size, the list of pieces that have been taken out of the current bag and have been placed in the next
std::vector<int> sizesBag; // the list each of bags that are still to have a piece taken out of them
std::vector<double> sizesProgression; // how close each size is to meet its quota of pieces
public:
/**
@@ -26,7 +33,7 @@ class Bag {
Bag(const std::shared_ptr<PiecesList>& piecesList);
/**
* Ignores the remaining pieces in the current bag and startd fresh from a new bag
* Ignores the remaining pieces in the current bag and start fresh from a new bag
*/
void jumpToNextBag();
@@ -44,7 +51,12 @@ class Bag {
private:
/**
* Prepare the next picked piece in advance
* Prepares the next picked piece in advance
*/
void prepareNext();
/**
* Gets the next picked piece from the specified bag
*/
void getNextPieceFromBag(int bagIndex);
};

View File

@@ -11,6 +11,10 @@ PiecesList::PiecesList() {
this->highestLoadedSize = 0;
this->selectedPieces.clear();
this->distributionMode = DEFAULT;
this->proportionsPerSize.clear();
this->customProportionsPerSize.clear();
// we need to have something at index 0 even if there is no pieces of size 0
this->loadedPieces.clear();
this->convexPieces.clear();
@@ -87,6 +91,14 @@ void PiecesList::unselectAll() {
this->selectedPieces.clear();
}
bool PiecesList::setDistributionMode(PiecesDistributionMode distributionMode) {
if (distributionMode == DEFAULT || distributionMode == UNIFORM || distributionMode == CUSTOM) {
this->distributionMode = distributionMode;
return true;
}
return false;
}
int PiecesList::getHighestLoadedSize() const {
return this->highestLoadedSize;
}
@@ -101,13 +113,42 @@ std::vector<std::pair<int, int>> PiecesList::getSelectedPieces() const {
return this->selectedPieces;
}
PiecesDistributionMode PiecesList::getDistributionMode() const {
return this->distributionMode;
}
bool PiecesList::changeCustomDistribution(int size, double distribution) {
if (size < 1 || size > this->highestLoadedSize || distribution > 1) {
return false;
}
this->customProportionsPerSize.at(size) = distribution;
return true;
}
std::vector<double> PiecesList::getProportionsPerSize() const {
if (this->distributionMode == CUSTOM) {
return this->customProportionsPerSize;
}
else {
return this->proportionsPerSize;
}
}
Piece PiecesList::getPiece(const std::pair<int, int>& pieceIndex) const {
return this->loadedPieces.at(pieceIndex.first).at(pieceIndex.second);
}
const Piece& PiecesList::lookAtPiece(const std::pair<int, int>& pieceIndex) const {
return this->loadedPieces.at(pieceIndex.first).at(pieceIndex.second);
}
void PiecesList::pushBackEmptyVectors() {
this->loadedPieces.push_back(std::vector<Piece>());
this->convexPieces.push_back(std::vector<int>());
this->holelessPieces.push_back(std::vector<int>());
this->otherPieces.push_back(std::vector<int>());
this->proportionsPerSize.push_back(1);
this->customProportionsPerSize.push_back(1);
}

View File

@@ -6,6 +6,16 @@
#include <utility>
/**
* The type of pieces distribution managed by the game
*/
enum PiecesDistributionMode {
DEFAULT,
UNIFORM,
CUSTOM
};
/**
* A container for all loaded pieces to prevent loading and copying them multiple times,
* also allows for the player to select a list of pieces to be used in a game
@@ -18,6 +28,9 @@ class PiecesList {
std::vector<std::vector<int>> holelessPieces; // the list of holeless loaded pieces by size
std::vector<std::vector<int>> otherPieces; // the list of other loaded pieces by size
std::vector<std::pair<int, int>> selectedPieces; // the list of all currently selected pieces
PiecesDistributionMode distributionMode; // the current pieces distribution mode
std::vector<double> proportionsPerSize; // the proportion of piece for each sizes
std::vector<double> customProportionsPerSize; // the proportion of piece for each sizes when the distribution mode is set to custom
public:
/**
@@ -66,6 +79,19 @@ class PiecesList {
*/
void unselectAll();
/**
* Changes the current pieces distribution mode
* @return If the mode is supported
*/
bool setDistributionMode(PiecesDistributionMode distributionMode);
/**
* Changes the distribution of the specified size for when the distribution mode is set to custom,
* the specified distribution must lower or equal to 1
* @return If the new distribution was applied
*/
bool changeCustomDistribution(int size, double distribution);
/**
* @return The highest loaded size of pieces
*/
@@ -81,10 +107,25 @@ class PiecesList {
*/
std::vector<std::pair<int, int>> getSelectedPieces() const;
/**
* @return The current distribution mode
*/
PiecesDistributionMode getDistributionMode() const;
/**
* @return The proportion of pieces for each loaded size
*/
std::vector<double> getProportionsPerSize() const;
/**
* @return A copy of the piece corresponding to the specified index
*/
Piece getPiece(const std::pair<int, int>& pieceIndex) const;
/**
* @return The piece corresponding to the specified index
*/
const Piece& lookAtPiece(const std::pair<int, int>& pieceIndex) const;
private:
/**

View File

@@ -40,7 +40,7 @@ GamePlayingAppMenu::GamePlayingAppMenu(std::shared_ptr<MenuStack> menuStack, std
this->nextCellSizeZoom = this->nextQueuePosition[0].size.y;
for (const auto& piece : this->settings->getMenu().getPiecesList().getSelectedPieces()) {
float nextPieceCellSizeZoom = ((int) this->nextQueuePosition[0].size.y) / this->settings->getMenu().getPiecesList().getPiece(piece).getLength();
float nextPieceCellSizeZoom = ((int) this->nextQueuePosition[0].size.y) / this->settings->getMenu().getPiecesList().lookAtPiece(piece).getLength();
this->nextCellSizeZoom = std::min(this->nextCellSizeZoom, nextPieceCellSizeZoom);
}

View File

@@ -10,6 +10,8 @@
static const sf::Vector2u BASE_WINDOW_SIZE = {80, 50};
static const int WINDOW_SIZE_MULTIPLIERS[] = {4, 6, 10, 14, 20, 30, 40};
static const int WINDOW_SIZE_LAST_MODE = (sizeof(WINDOW_SIZE_MULTIPLIERS) / sizeof(int)) - 1;
static const int START_TIMER_MAX = 4;
static const int DISTRIBUTION_MAX = 10;
Settings::Settings() {
@@ -67,13 +69,20 @@ void Settings::loadSettingsFromFile() {
// piece distribution
settingsFile.get(byte);
//TODO
if (byte == 2) {
for (int i = 1; i <= 15; i++) {
this->menu.getPiecesList().setDistributionMode(PiecesDistributionMode(byte));
this->distributions.clear();
this->distributions.push_back(0);
for (int i = 1; i <= 15; i++) {
if (byte == CUSTOM) {
settingsFile.get(byte);
//TODO
this->distributions.push_back(i);
}
else {
this->distributions.push_back(1);
}
}
this->confirmDistribution();
// selected pieces
char pieceType;
@@ -131,9 +140,16 @@ void Settings::saveSettingsToFile() const {
settingsFile.write(&byte, 1);
// piece distribution
//TODO
byte = this->menu.readPiecesList().getDistributionMode();
settingsFile.write(&byte, 1);
if (this->menu.readPiecesList().getDistributionMode() == CUSTOM) {
for (int i = 1; i <= 15; i++) {
byte = this->distributions.at(i);
settingsFile.write(&byte, 1);
}
}
// selected pieces
for (const auto& [type, value] : this->selectedPieces) {
byte = type;
@@ -189,7 +205,7 @@ void Settings::changeVideoMode(sf::RenderWindow& window) const {
}
bool Settings::lengthenStartTimer() {
if (this->startTimerLength < 4) {
if (this->startTimerLength < START_TIMER_MAX) {
this->startTimerLength++;
return true;
}
@@ -240,6 +256,36 @@ void Settings::confirmSelectedPieces() {
}
}
bool Settings::setDistributionMode (PiecesDistributionMode distributionMode) {
return this->menu.getPiecesList().setDistributionMode(distributionMode);
}
bool Settings::increaseDistribution(int size) {
if (size < 1 || size > MAXIMUM_PIECES_SIZE) return false;
if (this->distributions.at(size) < DISTRIBUTION_MAX) {
this->distributions.at(size)++;
return true;
}
return false;
}
bool Settings::decreaseDistribution(int size) {
if (size < 1 || size > MAXIMUM_PIECES_SIZE) return false;
if (this->distributions.at(size) > 0) {
this->distributions.at(size)--;
return true;
}
return false;
}
void Settings::confirmDistribution() {
for (int i = 1; i <= 15; i++) {
this->menu.getPiecesList().changeCustomDistribution(i, (double) this->distributions.at(i) / (DISTRIBUTION_MAX + 0.001));
}
}
Menu& Settings::getMenu() {
return this->menu;
}

View File

@@ -27,6 +27,7 @@ class Settings {
int startTimerLength;
Gamemode gamemode;
std::vector<std::pair<PiecesType, int>> selectedPieces;
std::vector<int> distributions;
public:
Settings();
@@ -59,6 +60,14 @@ class Settings {
void confirmSelectedPieces();
bool setDistributionMode (PiecesDistributionMode distributionMode);
bool increaseDistribution(int size);
bool decreaseDistribution(int size);
void confirmDistribution();
Menu& getMenu();
Keybinds& getKeybinds();

View File

@@ -80,7 +80,7 @@ void resetSettingsFile() {
settingsFile.write(&byte, 1);
// piece distribution
byte = 0;
byte = DEFAULT;
settingsFile.write(&byte, 1);
// selected pieces