Ajoute première implémentation

This commit is contained in:
Timothée Leclaire-Fournier 2024-01-20 00:15:21 -05:00
parent 42a4f5dfba
commit 212ed985ea
4 changed files with 241 additions and 59 deletions

View File

@ -121,6 +121,21 @@ void GOLTeamH::setBorderManagement(GOL::BorderManagement borderManagement)
{ {
mBorderManagement = borderManagement; mBorderManagement = borderManagement;
mIteration = 0; 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) 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) void GOLTeamH::fill(State state)
{ {
mData.fill(state); if (mBorderManagement == GOL::BorderManagement::immutableAsIs)
mData.fill(state, true);
else
mData.fill(state, false);
mIteration = 0; mIteration = 0;
} }
void GOLTeamH::fillAlternately(State firstCell) void GOLTeamH::fillAlternately(State firstCell)
{ {
mData.fillAternately(firstCell); if (mBorderManagement == GOL::BorderManagement::immutableAsIs)
mData.fillAternately(firstCell, true);
else
mData.fillAternately(firstCell, false);
mIteration = 0; mIteration = 0;
} }
void GOLTeamH::randomize(double percentAlive) void GOLTeamH::randomize(double percentAlive)
{ {
mData.randomize(percentAlive); if (mBorderManagement == GOL::BorderManagement::immutableAsIs)
mData.randomize(percentAlive, true);
else
mData.randomize(percentAlive, false);
mIteration = 0; mIteration = 0;
} }
@ -169,14 +196,68 @@ void GOLTeamH::setSolidColor(State state, Color const& color)
mAliveColor = color; mAliveColor = color;
} }
// TODO: performance
void GOLTeamH::processOneStep() void GOLTeamH::processOneStep()
{ {
// On commence à itérer sur les côtés. En règlant ces cas particuliers, on auto& grid{ mData.data() };
// peut éviter des branches dans la boucle principale. Le branch predictor auto& intGrid{ mData.intData() };
// aime cela.
for (size_t i{}; i < mData.width(); ++i) {
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 s_ptr = buffer;
auto e_ptr = &buffer[buffer_size]; auto e_ptr = &buffer[buffer_size];
auto& grid = mData.data();
// On itère sur chaque éléments du tableau et on associe la couleur. // On itère sur chaque éléments du tableau et on associe la couleur.
for (const auto& i : mData.data()) { for (size_t index{ width() + 2 };
if (i == GridTeamH::CellType::alive) { index < (width() + 2) * (height() + 1);
*s_ptr &= 0; // Clear index++) {
*s_ptr |= MAX_ALPHA << 24; // Alpha = 255
*s_ptr |= mAliveColor.red << 16; if (mData.isInBorder(index))
*s_ptr |= mAliveColor.green << 8; continue;
*s_ptr |= mAliveColor.blue;
} auto var = static_cast<uint8_t>(grid[index]);
else {
*s_ptr &= 0; *s_ptr &= 0; // Clear
*s_ptr |= MAX_ALPHA << 24; *s_ptr |= MAX_ALPHA << 24; // Alpha = 255
*s_ptr |= mDeadColor.red << 16;
*s_ptr |= mDeadColor.green << 8; *s_ptr |= mAliveColor.red * var << 16;
*s_ptr |= mDeadColor.blue; *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++; s_ptr++;
// Sanity check, pour éviter des problèmes
if (s_ptr >= e_ptr)
break;
} }
} }

View File

@ -45,6 +45,6 @@ private:
GridTeamH mData; GridTeamH mData;
Color mDeadColor, mAliveColor; Color mDeadColor, mAliveColor;
// Fonction utilisée à l'interne. // Fonctions utilisées à l'interne.
std::optional<unsigned char> convertCharToNumber(const char c); std::optional<unsigned char> convertCharToNumber(const char c);
}; };

View File

@ -35,37 +35,44 @@ size_t GridTeamH::size() const
return mWidth * mHeight; 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. // 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) void GridTeamH::resize(size_t width, size_t height, CellType initValue)
{ {
// TODO: Performance de resize avec beaucoup d'appel? mData.resize((width + 2) * (height + 2));
// Investiguer reserve + resize mIntermediateData.resize((width + 2) * (width + 2));
mData.resize(width * height);
mWidth = width; mWidth = width;
mHeight = height; mHeight = height;
fill(initValue); fill(initValue, false);
} }
// Accesseur retournant la valeur d'une cellule à une certaine coordonnée. // Accesseur retournant la valeur d'une cellule à une certaine coordonnée.
GridTeamH::CellType GridTeamH::value(int column, int row) const 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. // Mutateur modifiant la valeur d'une cellule à une certaine coordonnée.
void GridTeamH::setValue(int column, int row, CellType value) 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. // Accesseur retournant la valeur d'une cellule à une certaine coordonnée.
std::optional<GridTeamH::CellType> GridTeamH::at(int column, int row) const std::optional<GridTeamH::CellType> GridTeamH::at(int column, int row) const
{ {
if (column > mWidth || row > mHeight) if (column >= mWidth || row >= mHeight)
return std::nullopt; 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<6E>e. // Mutateur modifiant la valeur d'une cellule à une certaine coordonn<6E>e.
@ -74,19 +81,33 @@ void GridTeamH::setAt(int column, int row, CellType value)
if (column > mWidth || row > mHeight) if (column > mWidth || row > mHeight)
return; 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. // Accesseur en lecture seule sur le "buffer" de la grille.
GridTeamH::DataType const& GridTeamH::data() const GridTeamH::DataType const& GridTeamH::data() const
{ {
return mData; return mData;
} }
// Accesseur en lecture/écriture sur le "buffer" de la grille. // Accesseur en lecture/écriture sur le "buffer" de la grille.
GridTeamH::DataType& GridTeamH::data() GridTeamH::DataType& GridTeamH::data()
{ {
return mData; 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 // https://en.cppreference.com/w/cpp/algorithm/count
size_t GridTeamH::totalDead() const size_t GridTeamH::totalDead() const
{ {
@ -98,6 +119,7 @@ float GridTeamH::totalDeadRel() const
return static_cast<float>(totalDead()) / static_cast<float>(size()); return static_cast<float>(totalDead()) / static_cast<float>(size());
} }
// TODO: FIX
size_t GridTeamH::totalAlive() const size_t GridTeamH::totalAlive() const
{ {
return std::count_if(mData.begin(), mData.end(), [](auto& i) { return i == CellType::alive; }); 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<float>(totalAlive()) / static_cast<float>(size()); return static_cast<float>(totalAlive()) / static_cast<float>(size());
} }
void GridTeamH::fill(CellType value) void GridTeamH::fill(CellType value, bool fillBorder)
{ {
for (auto& i : mData) if (fillBorder) {
i = value; 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; auto otherValue = (initValue == CellType::alive) ? CellType::dead : CellType::alive;
for (size_t i{}; i < mData.size(); i++) if (fillBorder) {
mData[i] = !(i % 2) ? initValue : otherValue; 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) mData[index] = !(index % 2) ? initValue : otherValue;
{ }
for (auto& i : mData) {
if (mDistribution(mEngine) < percentAlive)
i = CellType::alive;
else
i = CellType::dead;
} }
} }
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);
}

View File

@ -26,6 +26,7 @@ public:
size_t width() const; size_t width() const;
size_t height() const; size_t height() const;
size_t size() const; size_t size() const;
size_t realSize() const;
void resize(size_t width, size_t height, CellType initValue = CellType{}); void resize(size_t width, size_t height, CellType initValue = CellType{});
@ -40,18 +41,28 @@ public:
DataType const& data() const; DataType const& data() const;
DataType& data(); DataType& data();
DataType const& intData() const;
DataType& intData();
size_t totalDead() const; size_t totalDead() const;
float totalDeadRel() const; float totalDeadRel() const;
size_t totalAlive() const; size_t totalAlive() const;
float totalAliveRel() const; float totalAliveRel() const;
void fill(CellType value); void fill(CellType value, bool fillBorder);
void fillAternately(CellType initValue); void fillAternately(CellType initValue, bool fillBorder);
void randomize(double percentAlive); void randomize(double percentAlive, bool fillBorder);
void fillBorder(CellType value);
void fillBorderWarped();
void fillBorderMirror();
void switchToIntermediate();
bool isInBorder(size_t index) const;
private: private:
DataType mData; DataType mData, mIntermediateData;
size_t mWidth, mHeight; size_t mWidth, mHeight;
// Pour la génération de nombres aléatoires // Pour la génération de nombres aléatoires
@ -59,3 +70,11 @@ private:
std::mt19937 mEngine; std::mt19937 mEngine;
std::uniform_real_distribution<> mDistribution; std::uniform_real_distribution<> mDistribution;
}; };
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));
}