Skip to content

Commit cc0230f

Browse files
committed
Game of Life Optimizations
Adjust mutation logic. Use 1D get/set. Reduce code size.
1 parent 65b9176 commit cc0230f

File tree

1 file changed

+22
-23
lines changed

1 file changed

+22
-23
lines changed

wled00/FX.cpp

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5197,7 +5197,7 @@ static const char _data_FX_MODE_2DFRIZZLES[] PROGMEM = "Frizzles@X frequency,Y f
51975197
// 2D Cellular Automata Game of life //
51985198
///////////////////////////////////////////
51995199
typedef struct Cell {
5200-
uint8_t alive : 1, faded : 1, toggleStatus : 1, edgeCell: 1, oscillatorCheck : 1, spaceshipCheck : 1, unused : 2;
5200+
uint8_t alive : 1, faded : 1, toggleStatus : 1, edgeCell: 1, oscillatorCheck : 1, spaceshipCheck : 1, unused : 2;
52015201
} Cell;
52025202

52035203
uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https://natureofcode.com/book/chapter-7-cellular-automata/
@@ -5207,7 +5207,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
52075207
const unsigned maxIndex = cols * rows;
52085208

52095209
if (!SEGENV.allocateData(SEGMENT.length() * sizeof(Cell))) return mode_static(); // allocation failed
5210-
5210+
52115211
Cell *cells = reinterpret_cast<Cell*> (SEGENV.data);
52125212

52135213
uint16_t& generation = SEGENV.aux0, &gliderLength = SEGENV.aux1; // rename aux variables for clarity
@@ -5230,43 +5230,42 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
52305230

52315231
// Setup New Game of Life
52325232
if ((!paused && generation == 0) || setup) {
5233-
SEGENV.step = strip.now + 1250; // show initial state for 1.25 seconds
5233+
SEGENV.step = strip.now + 1280; // show initial state for 1.28 seconds
52345234
generation = 1;
52355235
paused = true;
52365236
//Setup Grid
52375237
memset(cells, 0, maxIndex * sizeof(Cell));
52385238

5239-
for (unsigned i = maxIndex; i--; ) {
5239+
for (unsigned i = 0; i < maxIndex; i++) {
52405240
bool isAlive = !hw_random8(3); // ~33%
52415241
cells[i].alive = isAlive;
52425242
cells[i].faded = !isAlive;
52435243
unsigned x = i % cols, y = i / cols;
52445244
cells[i].edgeCell = (x == 0 || x == cols-1 || y == 0 || y == rows-1);
52455245

5246-
SEGMENT.setPixelColorXY(x, y, isAlive ? SEGMENT.color_from_palette(hw_random8(), false, PALETTE_SOLID_WRAP, 0) : bgColor);
5246+
SEGMENT.setPixelColor(i, isAlive ? SEGMENT.color_from_palette(hw_random8(), false, PALETTE_SOLID_WRAP, 0) : bgColor);
52475247
}
52485248
}
52495249

52505250
if (paused || (strip.now - SEGENV.step < 1000 / map(SEGMENT.speed,0,255,1,42))) {
52515251
// Redraw if paused or between updates to remove blur
52525252
for (unsigned i = maxIndex; i--; ) {
52535253
if (!cells[i].alive) {
5254-
uint32_t cellColor = SEGMENT.getPixelColorXY(i % cols, i / cols);
5254+
uint32_t cellColor = SEGMENT.getPixelColor(i);
52555255
if (cellColor != bgColor) {
52565256
uint32_t newColor;
52575257
bool needsColor = false;
5258-
if (cells[i].faded) { newColor = bgColor; needsColor = true; }
5258+
if (cells[i].faded) { newColor = bgColor; needsColor = true; }
52595259
else {
52605260
uint32_t blended = color_blend(cellColor, bgColor, 2);
52615261
if (blended == cellColor) { blended = bgColor; cells[i].faded = 1; }
52625262
newColor = blended; needsColor = true;
52635263
}
5264-
if (needsColor) SEGMENT.setPixelColorXY(i % cols, i / cols, newColor);
5264+
if (needsColor) SEGMENT.setPixelColor(i, newColor);
52655265
}
52665266
}
52675267
}
52685268
return FRAMETIME;
5269-
52705269
}
52715270

52725271
// Repeat detection
@@ -5286,55 +5285,55 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
52865285

52875286
unsigned neighbors = 0, aliveParents = 0, parentIdx[3];
52885287
// Count alive neighbors
5289-
for (int i = 1; i >= -1; i--) for (int j = 1; j >= -1; j--) if (i || j) {
5290-
int nX = x + j, nY = y + i;
5288+
for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) if (i || j) {
5289+
int nX = x + j, nY = y + i;
52915290
if (cell.edgeCell) {
52925291
nX = (nX + cols) % cols;
52935292
nY = (nY + rows) % rows;
52945293
}
52955294
unsigned nIndex = nX + nY * cols;
52965295
Cell& neighbor = cells[nIndex];
52975296
if (neighbor.alive) {
5298-
if (++neighbors > 3) break;
5299-
if (!neighbor.toggleStatus) { // Alive and not dying
5297+
neighbors++;
5298+
if (!neighbor.toggleStatus && neighbors < 4) { // Alive and not dying
53005299
parentIdx[aliveParents++] = nIndex;
53015300
}
53025301
}
53035302
}
53045303

53055304
uint32_t newColor;
53065305
bool needsColor = false;
5307-
5306+
53085307
if (cell.alive && (neighbors < 2 || neighbors > 3)) { // Loneliness or Overpopulation
53095308
cell.toggleStatus = 1;
53105309
if (blur == 255) cell.faded = 1;
5311-
newColor = cell.faded ? bgColor : color_blend(SEGMENT.getPixelColorXY(x, y), bgColor, blur);
5310+
newColor = cell.faded ? bgColor : color_blend(SEGMENT.getPixelColor(cIndex), bgColor, blur);
53125311
needsColor = true;
53135312
}
53145313
else if (!cell.alive) {
5315-
if (neighbors == 3 && (!mutate || hw_random8(128)) || // Normal birth with 1/128 failure chance if mutate
5316-
(mutate && neighbors == 2 && !hw_random8(128))) { // Mutation birth with 2 neighbors with 1/128 chance if mutate
5314+
byte mutationRoll = mutate ? hw_random8(128) : 1; // if 0: 3 neighbor births fail and 2 neighbor births mutate
5315+
if ((neighbors == 3 && mutationRoll) || (mutate && neighbors == 2 && !mutationRoll)) { // Reproduction or Mutation
53175316
cell.toggleStatus = 1;
53185317
cell.faded = 0;
5319-
5318+
53205319
if (aliveParents) {
53215320
// Set color based on random neighbor
53225321
unsigned parentIndex = parentIdx[random8(aliveParents)];
5323-
birthColor = SEGMENT.getPixelColorXY(parentIndex % cols, parentIndex / cols);
5322+
birthColor = SEGMENT.getPixelColor(parentIndex);
53245323
}
53255324
newColor = birthColor;
53265325
needsColor = true;
53275326
}
53285327
else if (!cell.faded) {// No change, fade dead cells
5329-
uint32_t cellColor = SEGMENT.getPixelColorXY(x, y);
5328+
uint32_t cellColor = SEGMENT.getPixelColor(cIndex);
53305329
uint32_t blended = color_blend(cellColor, bgColor, blur);
53315330
if (blended == cellColor) { blended = bgColor; cell.faded = 1; }
53325331
newColor = blended;
53335332
needsColor = true;
53345333
}
53355334
}
53365335

5337-
if (needsColor) SEGMENT.setPixelColorXY(x, y, newColor);
5336+
if (needsColor) SEGMENT.setPixelColor(cIndex, newColor);
53385337
}
53395338
// Loop through cells, if toggle, swap alive status
53405339
for (unsigned i = maxIndex; i--; ) {
@@ -5344,8 +5343,8 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
53445343

53455344
if (repeatingOscillator || repeatingSpaceship || emptyGrid) {
53465345
generation = 0; // reset on next call
5347-
SEGENV.step += 1000; // pause final generation for 1 second
5348-
}
5346+
SEGENV.step += 1024; // pause final generation for ~1 second
5347+
}
53495348
else {
53505349
++generation;
53515350
SEGENV.step = strip.now;

0 commit comments

Comments
 (0)