diff --git a/GPA675Lab1GOL/GOLTeamH.cpp b/GPA675Lab1GOL/GOLTeamH.cpp index 948cfd1..0c5f456 100644 --- a/GPA675Lab1GOL/GOLTeamH.cpp +++ b/GPA675Lab1GOL/GOLTeamH.cpp @@ -121,6 +121,21 @@ void GOLTeamH::setBorderManagement(GOL::BorderManagement borderManagement) { mBorderManagement = borderManagement; mIteration = 0; + + switch (borderManagement) { + case GOL::BorderManagement::foreverDead: + mData.fillBorder(GridTeamH::CellType::dead); + break; + case GOL::BorderManagement::foreverAlive: + mData.fillBorder(GridTeamH::CellType::alive); + break; + case GOL::BorderManagement::warping: + mData.fillBorderWarped(); + break; + case GOL::BorderManagement::mirror: + mData.fillBorderWarped(); + break; + } } void GOLTeamH::setState(int x, int y, State state) @@ -131,19 +146,31 @@ void GOLTeamH::setState(int x, int y, State state) void GOLTeamH::fill(State state) { - mData.fill(state); + if (mBorderManagement == GOL::BorderManagement::immutableAsIs) + mData.fill(state, true); + else + mData.fill(state, false); + mIteration = 0; } void GOLTeamH::fillAlternately(State firstCell) { - mData.fillAternately(firstCell); + if (mBorderManagement == GOL::BorderManagement::immutableAsIs) + mData.fillAternately(firstCell, true); + else + mData.fillAternately(firstCell, false); + mIteration = 0; } void GOLTeamH::randomize(double percentAlive) { - mData.randomize(percentAlive); + if (mBorderManagement == GOL::BorderManagement::immutableAsIs) + mData.randomize(percentAlive, true); + else + mData.randomize(percentAlive, false); + mIteration = 0; } @@ -169,14 +196,68 @@ void GOLTeamH::setSolidColor(State state, Color const& color) mAliveColor = color; } -// TODO: performance void GOLTeamH::processOneStep() { - // On commence à itérer sur les côtés. En règlant ces cas particuliers, on - // peut éviter des branches dans la boucle principale. Le branch predictor - // aime cela. - for (size_t i{}; i < mData.width(); ++i) { - + auto& grid{ mData.data() }; + auto& intGrid{ mData.intData() }; + + if (mBorderManagement == GOL::BorderManagement::foreverDead) { + size_t aliveCount{}; + size_t offset{ width() + 2 }; + auto* ptr{ &grid[0]}; + + for (size_t i{}; i < mData.realSize() - offset - 1; ++i) { + + if (mData.isInBorder(i)) { + ptr++; + continue; + } + + aliveCount = 0; + + // Top + ptr -= offset + 1; + if (*ptr == GOL::State::alive) + aliveCount++; + ptr++; + if (*ptr == GOL::State::alive) + aliveCount++; + ptr++; + if (*ptr == GOL::State::alive) + aliveCount++; + + // Milieu + ptr += offset - 2; + if (*ptr == GOL::State::alive) + aliveCount++; + ptr += 2; + if (*ptr == GOL::State::alive) + aliveCount++; + + + // Dessous + ptr += offset - 2; + if (*ptr == GOL::State::alive) + aliveCount++; + ptr++; + if (*ptr == GOL::State::alive) + aliveCount++; + ptr++; + if (*ptr == GOL::State::alive) + aliveCount++; + + if (grid[i] == GOL::State::alive) + intGrid[i] = (mParsedRuleSurvive.test(aliveCount)) ? GOL::State::alive : GOL::State::dead; + else + intGrid[i] = (mParsedRuleRevive.test(aliveCount)) ? GOL::State::alive : GOL::State::dead; + + // On retourne à une place plus loin qu'à l'origine. + ptr -= offset; + } + ptr = nullptr; + + mData.switchToIntermediate(); + mIteration.value()++; } } @@ -187,29 +268,30 @@ void GOLTeamH::updateImage(uint32_t* buffer, size_t buffer_size) const auto s_ptr = buffer; auto e_ptr = &buffer[buffer_size]; + auto& grid = mData.data(); - // On itère sur chaque éléments du tableau et on associe la couleur. - for (const auto& i : mData.data()) { - if (i == GridTeamH::CellType::alive) { - *s_ptr &= 0; // Clear - *s_ptr |= MAX_ALPHA << 24; // Alpha = 255 - *s_ptr |= mAliveColor.red << 16; - *s_ptr |= mAliveColor.green << 8; - *s_ptr |= mAliveColor.blue; - } - else { - *s_ptr &= 0; - *s_ptr |= MAX_ALPHA << 24; - *s_ptr |= mDeadColor.red << 16; - *s_ptr |= mDeadColor.green << 8; - *s_ptr |= mDeadColor.blue; - } + // On itère sur chaque éléments du tableau et on associe la couleur. + for (size_t index{ width() + 2 }; + index < (width() + 2) * (height() + 1); + index++) { + + if (mData.isInBorder(index)) + continue; + + auto var = static_cast(grid[index]); + + *s_ptr &= 0; // Clear + *s_ptr |= MAX_ALPHA << 24; // Alpha = 255 + + *s_ptr |= mAliveColor.red * var << 16; + *s_ptr |= mAliveColor.green * var << 8; + *s_ptr |= mAliveColor.blue * var; + + *s_ptr |= mDeadColor.red * (1 - var) << 16; + *s_ptr |= mDeadColor.green * (1 - var) << 8; + *s_ptr |= mDeadColor.blue * (1 - var); s_ptr++; - - // Sanity check, pour éviter des problèmes - if (s_ptr >= e_ptr) - break; } } @@ -219,4 +301,4 @@ std::optional GOLTeamH::convertCharToNumber(const char c) return std::nullopt; return (c - 48); -} +} \ No newline at end of file diff --git a/GPA675Lab1GOL/GOLTeamH.h b/GPA675Lab1GOL/GOLTeamH.h index 204ef06..44b5c7b 100644 --- a/GPA675Lab1GOL/GOLTeamH.h +++ b/GPA675Lab1GOL/GOLTeamH.h @@ -45,6 +45,6 @@ private: GridTeamH mData; Color mDeadColor, mAliveColor; - // Fonction utilisée à l'interne. + // Fonctions utilisées à l'interne. std::optional convertCharToNumber(const char c); }; \ No newline at end of file diff --git a/GPA675Lab1GOL/GridTeamH.cpp b/GPA675Lab1GOL/GridTeamH.cpp index a234884..375378a 100644 --- a/GPA675Lab1GOL/GridTeamH.cpp +++ b/GPA675Lab1GOL/GridTeamH.cpp @@ -35,37 +35,44 @@ size_t GridTeamH::size() const return mWidth * mHeight; } +size_t GridTeamH::realSize() const +{ + return (mWidth + 2) * (mHeight + 2); +} + // Mutateur modifiant la taille de la grille et initialise le contenu par la valeur spécifiée. void GridTeamH::resize(size_t width, size_t height, CellType initValue) { - // TODO: Performance de resize avec beaucoup d'appel? - // Investiguer reserve + resize - mData.resize(width * height); + mData.resize((width + 2) * (height + 2)); + mIntermediateData.resize((width + 2) * (width + 2)); mWidth = width; mHeight = height; - fill(initValue); + fill(initValue, false); } // Accesseur retournant la valeur d'une cellule à une certaine coordonnée. GridTeamH::CellType GridTeamH::value(int column, int row) const { - return mData[(column - 1) * (row - 1)]; + size_t offset{ mWidth + 2 }; + return mData[offset * row + (column - 1)]; } // Mutateur modifiant la valeur d'une cellule à une certaine coordonnée. void GridTeamH::setValue(int column, int row, CellType value) { - mData[(column - 1) * (row - 1)] = value; + size_t offset{ mWidth + 2 }; + mData[offset * row + (column - 1)] = value; } // Accesseur retournant la valeur d'une cellule à une certaine coordonnée. std::optional GridTeamH::at(int column, int row) const { - if (column > mWidth || row > mHeight) + if (column >= mWidth || row >= mHeight) return std::nullopt; - return mData[(column - 1) * (row - 1)]; + size_t offset{ mWidth + 2 }; + return mData[offset * row + (column - 1)]; } // Mutateur modifiant la valeur d'une cellule à une certaine coordonn�e. @@ -74,19 +81,33 @@ void GridTeamH::setAt(int column, int row, CellType value) if (column > mWidth || row > mHeight) return; - mData[(column - 1) * (row - 1)] = value; + size_t offset{ mWidth + 2 }; + mData[offset * row + (column - 1)] = value; } + // Accesseur en lecture seule sur le "buffer" de la grille. GridTeamH::DataType const& GridTeamH::data() const { return mData; } + // Accesseur en lecture/écriture sur le "buffer" de la grille. GridTeamH::DataType& GridTeamH::data() { return mData; } +GridTeamH::DataType const& GridTeamH::intData() const +{ + return mIntermediateData; +} + +GridTeamH::DataType& GridTeamH::intData() +{ + return mIntermediateData; +} + +// TODO: FIX // https://en.cppreference.com/w/cpp/algorithm/count size_t GridTeamH::totalDead() const { @@ -98,6 +119,7 @@ float GridTeamH::totalDeadRel() const return static_cast(totalDead()) / static_cast(size()); } +// TODO: FIX size_t GridTeamH::totalAlive() const { return std::count_if(mData.begin(), mData.end(), [](auto& i) { return i == CellType::alive; }); @@ -108,26 +130,85 @@ float GridTeamH::totalAliveRel() const return static_cast(totalAlive()) / static_cast(size()); } -void GridTeamH::fill(CellType value) +void GridTeamH::fill(CellType value, bool fillBorder) { - for (auto& i : mData) - i = value; + if (fillBorder) { + for (auto& i : mData) + i = value; + } + else { + for (size_t index{}; index < mData.size(); index++) { + if (isInBorder(index)) + continue; + + mData[index] = value; + } + } } -void GridTeamH::fillAternately(CellType initValue) +void GridTeamH::fillAternately(CellType initValue, bool fillBorder) { auto otherValue = (initValue == CellType::alive) ? CellType::dead : CellType::alive; - for (size_t i{}; i < mData.size(); i++) - mData[i] = !(i % 2) ? initValue : otherValue; -} + if (fillBorder) { + for (size_t i{}; i < mData.size(); i++) + mData[i] = !(i % 2) ? initValue : otherValue; + } + else { + for (size_t index{}; index < mData.size(); index++) { + if (isInBorder(index)) + continue; -void GridTeamH::randomize(double percentAlive) -{ - for (auto& i : mData) { - if (mDistribution(mEngine) < percentAlive) - i = CellType::alive; - else - i = CellType::dead; + mData[index] = !(index % 2) ? initValue : otherValue; + } } } + +void GridTeamH::randomize(double percentAlive, bool fillBorder) +{ + if (fillBorder) { + for (auto& i : mData) { + if (mDistribution(mEngine) < percentAlive) + i = CellType::alive; + else + i = CellType::dead; + } + } + else { + for (size_t index{}; index < mData.size() - 1; index++) { + if (isInBorder(index)) + continue; + + if (mDistribution(mEngine) < percentAlive) + mData[index] = CellType::alive; + else + mData[index] = CellType::dead; + } + } +} + +void GridTeamH::fillBorder(CellType value) +{ + for (size_t index{}; index < mData.size(); index++) { + if (isInBorder(index)) + mData[index] = value; + } +} + +void GridTeamH::fillBorderWarped() +{ + +} + +void GridTeamH::fillBorderMirror() +{ + +} + +void GridTeamH::switchToIntermediate() +{ + // Swap pour la performance. + mData.swap(mIntermediateData); +} + + diff --git a/GPA675Lab1GOL/GridTeamH.h b/GPA675Lab1GOL/GridTeamH.h index b1d9ab1..b1dd34c 100644 --- a/GPA675Lab1GOL/GridTeamH.h +++ b/GPA675Lab1GOL/GridTeamH.h @@ -26,6 +26,7 @@ public: size_t width() const; size_t height() const; size_t size() const; + size_t realSize() const; void resize(size_t width, size_t height, CellType initValue = CellType{}); @@ -39,6 +40,9 @@ public: // Accesseurs du "buffer" de la grille DataType const& data() const; DataType& data(); + + DataType const& intData() const; + DataType& intData(); size_t totalDead() const; float totalDeadRel() const; @@ -46,16 +50,31 @@ public: size_t totalAlive() const; float totalAliveRel() const; - void fill(CellType value); - void fillAternately(CellType initValue); - void randomize(double percentAlive); + void fill(CellType value, bool fillBorder); + void fillAternately(CellType initValue, bool fillBorder); + void randomize(double percentAlive, bool fillBorder); + + void fillBorder(CellType value); + void fillBorderWarped(); + void fillBorderMirror(); + + void switchToIntermediate(); + bool isInBorder(size_t index) const; private: - DataType mData; + DataType mData, mIntermediateData; size_t mWidth, mHeight; // Pour la génération de nombres aléatoires std::random_device mRandomDevice; std::mt19937 mEngine; std::uniform_real_distribution<> mDistribution; -}; \ No newline at end of file +}; + +inline bool GridTeamH::isInBorder(size_t index) const +{ + return(index % (mWidth + 2) < 1 + || index % (mWidth + 2) > mWidth + || index < mWidth + 2 + || index > (mWidth + 2) * (mHeight + 1)); +} \ No newline at end of file