From d92818351bb3a6e79b925b7e9b2b746195874899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Leclaire-Fournier?= Date: Sat, 27 Jan 2024 20:00:59 -0500 Subject: [PATCH] Paufinement de mirroir/warping --- GPA675Lab1GOL/GOLTeamH.cpp | 117 ++++++++++++++++++++++++++++++++---- GPA675Lab1GOL/GOLTeamH.h | 8 ++- GPA675Lab1GOL/GridTeamH.cpp | 88 ++++----------------------- GPA675Lab1GOL/GridTeamH.h | 26 +++----- 4 files changed, 131 insertions(+), 108 deletions(-) diff --git a/GPA675Lab1GOL/GOLTeamH.cpp b/GPA675Lab1GOL/GOLTeamH.cpp index 6447040..f0ec164 100644 --- a/GPA675Lab1GOL/GOLTeamH.cpp +++ b/GPA675Lab1GOL/GOLTeamH.cpp @@ -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,11 +468,13 @@ void GOLTeamH::processOneStep() ptrGrid += 2; ptrGridInt += 2; } + ptrGrid = nullptr; ptrGridInt = nullptr; - mData.switchToIntermediate(); //mise à jour de la grille - mIteration.value()++; + modifyBorderIfNecessary(reinterpret_cast(mData.data()), reinterpret_cast(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((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; +} diff --git a/GPA675Lab1GOL/GOLTeamH.h b/GPA675Lab1GOL/GOLTeamH.h index 10e7990..0158c20 100644 --- a/GPA675Lab1GOL/GOLTeamH.h +++ b/GPA675Lab1GOL/GOLTeamH.h @@ -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 \ No newline at end of file diff --git a/GPA675Lab1GOL/GridTeamH.cpp b/GPA675Lab1GOL/GridTeamH.cpp index 94ba3c3..4a125e7 100644 --- a/GPA675Lab1GOL/GridTeamH.cpp +++ b/GPA675Lab1GOL/GridTeamH.cpp @@ -4,18 +4,16 @@ #include #include - - // 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(row) + mHeight) % mHeight * mWidth + (static_cast(column) + mWidth) % mWidth]; - - } - else if (mBorderType == Mirror) { - - } - else if (mBorderType == Classic) { - return mData[(static_cast(row) - 1) * mWidth + (static_cast(column) - 1)]; - } + return mData[(static_cast(row) - 1) * mWidth + (static_cast(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(row) + mHeight) % mHeight * mWidth + (static_cast(column) + mWidth) % mWidth]= value; - - } - else if(mBorderType== Mirror){ - - } - else if(mBorderType== Classic){ - - mData[(static_cast(row) - 1) * mWidth + (static_cast(column) - 1)] = value; - } - + mData[(static_cast(row) - 1) * mWidth + (static_cast(column) - 1)] = value; } // Accesseur retournant la valeur d'une cellule à une certaine coordonnée. std::optional 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) { + if (column >= mWidth || row >= mHeight) + return std::nullopt; - } - else if (mBorderType == Classic) { - if (column >= mWidth || row >= mHeight) - return std::nullopt; - - return mData[(row - 1) * mWidth + (column - 1)]; - } - + 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(row) + mHeight) % mHeight * mWidth + (static_cast(column) + mWidth) % mWidth] = value; - } - else if (mBorderType == Mirror) { - - } - else if (mBorderType == Classic) { - if (column > mWidth || row > mHeight) - return; - - mData[(static_cast(row) - 1) * mWidth + (static_cast(column) - 1)] = value; - - } + mData[(static_cast(row) - 1) * mWidth + (static_cast(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; - } - - diff --git a/GPA675Lab1GOL/GridTeamH.h b/GPA675Lab1GOL/GridTeamH.h index 407da52..79c099c 100644 --- a/GPA675Lab1GOL/GridTeamH.h +++ b/GPA675Lab1GOL/GridTeamH.h @@ -19,7 +19,7 @@ // La classe point représente une grille dans l’espace 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; @@ -84,32 +78,28 @@ public: int tendencyAbs() const; float tendencyRel() const; - //Méthode de remplissage + // Méthode de remplissage void fill(CellType value, bool fillBorder); void fillAlternately(CellType initValue, bool fillBorder); void randomize(double percentAlive, bool fillBorder); - //Méthode de gestion de bordure + // Méthode de gestion de bordure void fillBorder(CellType value); - void fillBorderWarped(); - void fillBorderMirror(); - //Alternance entre les deux grilles + // Alternance entre les deux grilles void switchToIntermediate(); 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(); };