Paufinement de mirroir/warping

This commit is contained in:
Timothée Leclaire-Fournier 2024-01-27 20:00:59 -05:00
parent 85148b59e5
commit d92818351b
4 changed files with 131 additions and 108 deletions

View File

@ -100,7 +100,7 @@ GOL::ImplementationInformation GOLTeamH::information() const
void GOLTeamH::resize(size_t width, size_t height, State defaultState)
{
mData.resize(width, height, defaultState);
drawBorder();
setBorder();
countLifeStatusCells();
}
@ -218,11 +218,11 @@ void GOLTeamH::setBorderManagement(BorderManagement borderManagement)
{
mBorderManagement = borderManagement;
mIteration = 0;
drawBorder();
setBorder();
countLifeStatusCells();
}
void GOLTeamH::drawBorder()
void GOLTeamH::setBorder()
{
switch (mBorderManagement.value_or(GOL::BorderManagement::foreverDead)) {
case GOL::BorderManagement::foreverDead:
@ -231,12 +231,6 @@ void GOLTeamH::drawBorder()
case GOL::BorderManagement::foreverAlive:
mData.fillBorder(GridTeamH::CellType::alive);
break;
case GOL::BorderManagement::warping:
mData.setBorderManagement(GridTeamH::BorderManagement::Warpping);
break;
case GOL::BorderManagement::mirror:
mData.setBorderManagement(GridTeamH::BorderManagement::Mirror);
break;
}
}
@ -431,7 +425,6 @@ void GOLTeamH::processOneStep()
for (size_t j{ 1 }; j < heightNoBorder + 1; ++j) {
for (size_t i{ 1 }; i < widthNoBorder + 1; ++i) {
neighborsAliveCount = 0;
// Top
@ -475,10 +468,12 @@ void GOLTeamH::processOneStep()
ptrGrid += 2;
ptrGridInt += 2;
}
ptrGrid = nullptr;
ptrGridInt = nullptr;
mData.switchToIntermediate(); //mise à jour de la grille
modifyBorderIfNecessary(reinterpret_cast<uint8_t*>(mData.data()), reinterpret_cast<uint8_t*>(mData.intData()));
mData.switchToIntermediate(); // Mise à jour de la grille
mIteration.value()++;
mData.setAliveCount(aliveCount);
}
@ -625,3 +620,101 @@ void GOLTeamH::countLifeStatusCells()
}
mData.setAliveCount(aliveCount);
}
void GOLTeamH::modifyBorderIfNecessary(uint8_t* ptrGrid, uint8_t* ptrGridInt)
{
auto bm = mBorderManagement.value_or(BorderManagement::immutableAsIs);
auto width{ mData.width() }, height{ mData.height() }; // Pour éviter des appels de fonctions trop souvent.
auto rule{ mParsedRule }; // Pour la capture du lambda.
if (mBorderManagement.value() == GOL::BorderManagement::immutableAsIs ||
bm == GOL::BorderManagement::foreverAlive ||
bm == GOL::BorderManagement::foreverDead)
return;
auto* e_ptr = ptrGrid + (width - 1);
// Lambda pour une opération courante.
auto op = [rule](size_t count, uint8_t* ptrGrid) {
return static_cast<bool>((rule >> *(ptrGrid) * 16) & (1u << count));
};
// TOP
while (ptrGrid < e_ptr) {
*ptrGridInt = op(countNeighbors(ptrGrid, bm), ptrGrid);
ptrGrid++;
ptrGridInt++;
}
// DROITE
e_ptr += width * (height - 1);
while (ptrGrid < e_ptr) {
*ptrGridInt = op(countNeighbors(ptrGrid, bm), ptrGrid);
ptrGrid += width;
ptrGridInt += width;
}
// DESSOUS
e_ptr -= (width - 1);
while (ptrGrid > e_ptr) {
*ptrGridInt = op(countNeighbors(ptrGrid, bm), ptrGrid);
ptrGrid--;
ptrGridInt--;
}
// GAUCHE
e_ptr -= width * (height - 1);
while (ptrGrid > e_ptr) {
*ptrGridInt = op(countNeighbors(ptrGrid, bm), ptrGrid);
ptrGrid -= width;
ptrGridInt -= width;
}
}
size_t GOLTeamH::countNeighbors(uint8_t* ptrGrid, BorderManagement bm) const
{
auto width{ mData.width() }, height{ mData.height() }; // Pour éviter des appels de fonctions trop souvent.
size_t neighborsAliveCount{};
auto* tempPtr{ ptrGrid - (width + 1) };
// Petit lambda pour simplifier les opérations.
auto putInBounds = [ptrGrid, width, height, bm](uint8_t* ptr, uint8_t const* cellPtr) {
if (ptr < ptrGrid)
ptr += width * (bm == GOL::BorderManagement::mirror) ? 2 : height;
else if (ptr > ptrGrid + (width * height))
ptr -= width * (bm == GOL::BorderManagement::mirror) ? 2 : height;
if ((cellPtr - ptrGrid) % width == 0)
ptr += (bm == GOL::BorderManagement::mirror) ? 2 : width;
else if ((cellPtr - ptrGrid) % width == width - 1)
ptr -= (bm == GOL::BorderManagement::mirror) ? 2 : width;
return ptr;
};
neighborsAliveCount += *(putInBounds(tempPtr, ptrGrid));
tempPtr++;
neighborsAliveCount += *(putInBounds(tempPtr, ptrGrid));
tempPtr++;
neighborsAliveCount += *(putInBounds(tempPtr, ptrGrid));
// Milieu
tempPtr += (width - 2);
neighborsAliveCount += *(putInBounds(tempPtr, ptrGrid));
tempPtr += 2;
neighborsAliveCount += *(putInBounds(tempPtr, ptrGrid));
// Dessous
tempPtr += (width - 2);
neighborsAliveCount += *(putInBounds(tempPtr, ptrGrid));
tempPtr++;
neighborsAliveCount += *(putInBounds(tempPtr, ptrGrid));
tempPtr++;
neighborsAliveCount += *(putInBounds(tempPtr, ptrGrid));
return neighborsAliveCount;
}

View File

@ -18,7 +18,7 @@
// - - - - - - - - - - - - - - - - - - - - - - -
// Classe GOLTeamH
//
// Cette classe nosu permet de créer et de manipuler un jeu de la vie.
// Cette classe nous permet de créer et de manipuler un jeu de la vie.
// Elle se base sur l'utilisation de la classe GridTeamH afin de gérer les mouvement dans la grid
// - - - - - - - - - - - - - - - - - - - - - - -
@ -54,7 +54,7 @@ public:
void resize(size_t width, size_t height, State defaultState) override;
bool setRule(std::string const& rule) override;
void setBorderManagement(BorderManagement borderManagement) override;
void drawBorder();
void setBorder();
void setState(int x, int y, State state) override;
void fill(State state) override;
void fillAlternately(State firstCell) override;
@ -94,6 +94,10 @@ private:
void fillDataFromPattern(std::string const& pattern, sizeQueried& sq,
int centerX, int centerY);
void countLifeStatusCells();
// Fonction qui modifie le border selon la règle
void modifyBorderIfNecessary(uint8_t* ptrGrid, uint8_t* ptrGridInt);
size_t countNeighbors(uint8_t* ptrGrid, BorderManagement bm) const;
};
#endif GOLTEAMH_H

View File

@ -4,18 +4,16 @@
#include <optional>
#include <utility>
// Constructeur Grid par défaut
GridTeamH::GridTeamH()
: GridTeamH(100, 100, CellType::dead,Classic)
: GridTeamH(100, 100, CellType::dead)
{
}
GridTeamH::GridTeamH(size_t width, size_t height, CellType initValue, BorderManagement borderType)
GridTeamH::GridTeamH(size_t width, size_t height, CellType initValue)
:mWidth{ width }, mHeight{ height }, mEngine(mRandomDevice()), mDistribution(0.0, 1.0)
, mAliveCount{}, mLastGenAliveCount{}
, mData{}, mIntermediateData{}, mBorderType{ Classic }
, mData{}, mIntermediateData{}
{
resize(width, height, initValue);
}
@ -109,75 +107,29 @@ void GridTeamH::dealloc()
// Accesseur retournant la valeur d'une cellule à une certaine coordonnée.
GridTeamH::CellType GridTeamH::value(int column, int row) const
{
if (mBorderType == Warpping) {
return mData[(static_cast<unsigned long long>(row) + mHeight) % mHeight * mWidth + (static_cast<unsigned long long>(column) + mWidth) % mWidth];
}
else if (mBorderType == Mirror) {
}
else if (mBorderType == Classic) {
return mData[(static_cast<unsigned long long>(row) - 1) * mWidth + (static_cast<unsigned long long>(column) - 1)];
}
}
// Mutateur modifiant la valeur d'une cellule à une certaine coordonnée.
void GridTeamH::setValue(int column, int row, CellType value)
{
if(mBorderType== Warpping){
mData[(static_cast<unsigned long long>(row) + mHeight) % mHeight * mWidth + (static_cast<unsigned long long>(column) + mWidth) % mWidth]= value;
}
else if(mBorderType== Mirror){
}
else if(mBorderType== Classic){
mData[(static_cast<unsigned long long>(row) - 1) * mWidth + (static_cast<unsigned long long>(column) - 1)] = value;
}
}
// Accesseur retournant la valeur d'une cellule à une certaine coordonnée.
std::optional<GridTeamH::CellType> GridTeamH::at(int column, int row) const
{
if (mBorderType == Warpping) {
// Logique de gestion des bords toroïdaux
column = (column + mWidth) % mWidth;
row = (row + mHeight) % mHeight;
}
else if (mBorderType == Mirror) {
}
else if (mBorderType == Classic) {
if (column >= mWidth || row >= mHeight)
return std::nullopt;
return mData[(row - 1) * mWidth + (column - 1)];
}
}
// Mutateur modifiant la valeur d'une cellule à une certaine coordonnée.
void GridTeamH::setAt(int column, int row, CellType value)
{
if (mBorderType == Warpping) {
// Logique de gestion des bords toroïdaux
column = (column + mWidth) % mWidth;
row = (row + mHeight) % mHeight;
mData[(static_cast<unsigned long long>(row) + mHeight) % mHeight * mWidth + (static_cast<unsigned long long>(column) + mWidth) % mWidth] = value;
}
else if (mBorderType == Mirror) {
}
else if (mBorderType == Classic) {
if (column > mWidth || row > mHeight)
return;
mData[(static_cast<unsigned long long>(row) - 1) * mWidth + (static_cast<unsigned long long>(column) - 1)] = value;
}
}
void GridTeamH::setAliveCount(size_t aliveCount)
@ -283,11 +235,11 @@ void GridTeamH::randomize(double percentAlive, bool fillBorder)
void GridTeamH::fillBorder(CellType value)
{
fillBorderManipulations(mData, value);
fillBorderManipulations(mIntermediateData, value);
fillBorderOperation(mData, value);
fillBorderOperation(mIntermediateData, value);
}
void GridTeamH::fillBorderManipulations(DataType ptr, CellType value) const
void GridTeamH::fillBorderOperation(DataType ptr, CellType value) const
{
auto* e_ptr = ptr + (mWidth - 1);
@ -319,26 +271,10 @@ void GridTeamH::fillBorderManipulations(DataType ptr, CellType value) const
}
}
// TODO
void GridTeamH::fillBorderWarped()
{
}
// TODO
void GridTeamH::fillBorderMirror()
{
}
void GridTeamH::switchToIntermediate()
{
// Swap pour la performance.
auto* temp{ mData };
mData = mIntermediateData;
mIntermediateData = temp;
}

View File

@ -19,7 +19,7 @@
// La classe point représente une grille dans lespace 2d des réels.
// Deux tableaux sont utilisés, un réel et un intermédiaire.
//Elle comporte des méthodes pour manipuler les cellules de la grille et en sortir des statstiques.
// Elle comporte des méthodes pour manipuler les cellules de la grille et en sortir des statistiques.
class GridTeamH
{
@ -28,15 +28,9 @@ public:
using CellType = GOL::State;
using DataType = CellType*;
enum BorderManagement {
Warpping,
Classic,
Mirror,
};
// Définition des constructeurs / destructeur
GridTeamH();
GridTeamH(size_t width, size_t height, CellType initValue = CellType{}, BorderManagement borderType = Classic);
GridTeamH(size_t width, size_t height, CellType initValue = CellType{});
GridTeamH(GridTeamH const&);
GridTeamH(GridTeamH&&) noexcept;
@ -60,7 +54,7 @@ public:
void setAt(int column, int row, CellType value);
void setAliveCount(size_t aliveCount);
void setBorderManagement(BorderManagement borderType) { mBorderType = borderType; }
// Accesseurs du "buffer" de la grille
DataType const& data() const;
DataType& data();
@ -68,7 +62,7 @@ public:
DataType const& intData() const;
DataType& intData();
//méthode pour les statistiques
// Méthode pour les statistiques
size_t totalDead() const;
float totalDeadRel() const;
@ -91,8 +85,6 @@ public:
// Méthode de gestion de bordure
void fillBorder(CellType value);
void fillBorderWarped();
void fillBorderMirror();
// Alternance entre les deux grilles
void switchToIntermediate();
@ -101,15 +93,13 @@ private:
DataType mData, mIntermediateData;
size_t mWidth, mHeight, mAliveCount, mLastGenAliveCount;
BorderManagement mBorderType;
// Pour la génération de nombres aléatoires
std::random_device mRandomDevice;
std::mt19937 mEngine;
std::uniform_real_distribution<> mDistribution;
// Méthodes utilisées en interne
void fillBorderManipulations(DataType ptr, CellType value) const;
void fillBorderOperation(DataType ptr, CellType value) const;
void dealloc();
};