@@ -28,6 +28,7 @@ public:
28
28
const static LifeState BORN = 2 ;
29
29
const static LifeState DYING = 3 ;
30
30
const static LifeState DEAD = 0 ;
31
+ const static LifeState GAME_OVER = 4 ;
31
32
32
33
private:
33
34
@@ -37,7 +38,10 @@ private:
37
38
LifeState* _cells;
38
39
LifeState* _nextCells;
39
40
41
+ bool _isReseting;
42
+
40
43
RGBColorType getColorForLifeState ( LifeState state ) const ;
44
+
41
45
42
46
protected:
43
47
virtual void action ();
@@ -49,11 +53,12 @@ public:
49
53
unsigned long updateMicros
50
54
);
51
55
52
- void setCellStatus (int row, int column, LifeState cellStatus);
53
- LifeState getCellStatus (int row, int column) const ;
54
-
55
- bool isAlive (int row, int column) const ;
56
- int countAliveNeighbors (int row, int column) const ;
56
+ void setCellStatus (unsigned int row, unsigned int column, LifeState cellStatus);
57
+ LifeState getCellStatus (unsigned int row, unsigned int column) const ;
58
+ void createRandomState ();
59
+
60
+ bool isAlive (unsigned int row, unsigned int column) const ;
61
+ int countAliveNeighbors (unsigned int row, unsigned int column) const ;
57
62
58
63
void drawToScreen ();
59
64
};
@@ -64,46 +69,47 @@ CellUniverse::CellUniverse(
64
69
) : TimerAction(updateMicros),
65
70
_leds(matrix),
66
71
_cells(new LifeState[matrix.rows()*matrix.columns()]),
67
- _nextCells(new LifeState[matrix.rows()*matrix.columns()])
72
+ _nextCells(new LifeState[matrix.rows()*matrix.columns()]),
73
+ _isReseting(false )
68
74
{
69
75
memset (_cells,DEAD,matrix.rows ()*matrix.columns ()*sizeof (LifeState));
70
76
memset (_nextCells,DEAD,matrix.rows ()*matrix.columns ()*sizeof (LifeState));
71
77
}
72
78
73
- void CellUniverse::setCellStatus (int row, int column, LifeState cellStatus) {
79
+ void CellUniverse::setCellStatus (unsigned int row, unsigned int column, LifeState cellStatus) {
74
80
if (row < 0 || row >= _leds.rows () || column < 0 || column >= _leds.columns ()) {
75
81
return ;
76
82
}
77
83
78
- int idx = row*_leds.columns () + column;
84
+ unsigned int idx = row*_leds.columns () + column;
79
85
80
86
_cells[idx] = cellStatus;
81
87
}
82
88
83
- CellUniverse::LifeState CellUniverse::getCellStatus (int row, int column) const {
89
+ CellUniverse::LifeState CellUniverse::getCellStatus (unsigned int row, unsigned int column) const {
84
90
// this causes the matrix to be a toroidal array
85
- int r = row < 0 ? row + _leds.rows () : ( row >= _leds.rows () ? row - _leds.rows () : row );
86
- int c = column < 0 ? column + _leds.columns () : ( column >= _leds.columns () ? column - _leds.columns () : column );
91
+ unsigned int r = row < 0 ? row + _leds.rows () : ( row >= _leds.rows () ? row - _leds.rows () : row );
92
+ unsigned int c = column < 0 ? column + _leds.columns () : ( column >= _leds.columns () ? column - _leds.columns () : column );
87
93
88
94
// double check just to be sure
89
95
if (r < 0 || r >= _leds.rows () || c < 0 || c >= _leds.columns ()) {
90
96
return CellUniverse::DEAD;
91
97
}
92
98
93
- int idx = r*_leds.columns () + c;
99
+ unsigned int idx = r*_leds.columns () + c;
94
100
95
101
return _cells[idx];
96
102
}
97
103
98
- bool CellUniverse::isAlive (int row, int column) const {
104
+ bool CellUniverse::isAlive (unsigned int row, unsigned int column) const {
99
105
return (this ->getCellStatus (row, column) == CellUniverse::ALIVE || this ->getCellStatus (row, column) == CellUniverse::BORN);
100
106
}
101
107
102
- int CellUniverse::countAliveNeighbors (int row, int column) const {
108
+ int CellUniverse::countAliveNeighbors (unsigned int row, unsigned int column) const {
103
109
int aliveCount = 0 ;
104
110
105
- for (int x = column - 1 ; x <= column+1 ; x++) {
106
- for (int y = row - 1 ; y <= row + 1 ; y++ ) {
111
+ for (unsigned int x = column - 1 ; x <= column+1 ; x++) {
112
+ for (unsigned int y = row - 1 ; y <= row + 1 ; y++ ) {
107
113
if (this ->isAlive (y, x) && !(x == column && y == row)) {
108
114
aliveCount++;
109
115
}
@@ -114,9 +120,18 @@ int CellUniverse::countAliveNeighbors(int row, int column) const {
114
120
}
115
121
116
122
void CellUniverse::action () {
123
+ if (_isReseting) {
124
+ delay (5000 );
125
+ this ->createRandomState ();
126
+ _isReseting = false ;
127
+ return ;
128
+ }
129
+
117
130
_leds.startDrawing ();
118
- for (int x = 0 ; x < _leds.columns (); x++) {
119
- for (int y = 0 ; y < _leds.rows (); y++ ) {
131
+ bool isSame = true ;
132
+
133
+ for (unsigned int x = 0 ; x < _leds.columns (); x++) {
134
+ for (unsigned int y = 0 ; y < _leds.rows (); y++ ) {
120
135
LifeState newState = DEAD;
121
136
LifeState currentState = this ->getCellStatus (y, x);
122
137
int count = this ->countAliveNeighbors (y, x);
@@ -139,8 +154,11 @@ void CellUniverse::action() {
139
154
}
140
155
break ;
141
156
}
142
-
143
- int idx = y*_leds.columns () + x;
157
+ if (currentState != newState) {
158
+ isSame = false ;
159
+ }
160
+
161
+ unsigned int idx = y*_leds.columns () + x;
144
162
_nextCells[idx] = newState;
145
163
146
164
RGBColorType cellColor = this ->getColorForLifeState (newState);
@@ -149,13 +167,49 @@ void CellUniverse::action() {
149
167
}
150
168
_leds.stopDrawing ();
151
169
170
+ // determine if life needs to start over
171
+ if (isSame) {
172
+ for (unsigned int x = 0 ; x < _leds.columns (); x++ ) {
173
+ for (unsigned int y = 0 ; y < _leds.rows (); y++ ) {
174
+ if (this ->getCellStatus (y, x) == DEAD) {
175
+ this ->setCellStatus (y, x, GAME_OVER);
176
+ }
177
+ }
178
+ }
179
+ this ->drawToScreen ();
180
+ _isReseting = true ;
181
+ }
182
+ else {
152
183
memcpy (_cells, _nextCells, _leds.rows ()*_leds.columns ()*sizeof (LifeState));
184
+ }
185
+
186
+ }
187
+
188
+ void CellUniverse::createRandomState () {
189
+ unsigned int numTotalCells = _leds.rows ()*_leds.columns ();
190
+
191
+ for (unsigned int x = 0 ; x < _leds.columns (); x++ ) {
192
+ for (unsigned int y = 0 ; y < _leds.rows (); y++ ) {
193
+ this ->setCellStatus (y, x, CellUniverse::DEAD);
194
+ }
195
+ }
196
+
197
+ unsigned int countStartingCells = random (0.25 *numTotalCells, 0.75 *numTotalCells);
198
+
199
+ for (unsigned int i = 0 ; i < countStartingCells; i++ ) {
200
+ int randomRow = random (0 ,_leds.rows ());
201
+ int randomColumn = random (0 ,_leds.columns ());
202
+
203
+ this ->setCellStatus (randomRow, randomColumn, CellUniverse::BORN);
204
+ }
205
+
206
+ this ->drawToScreen ();
153
207
}
154
208
155
209
void CellUniverse::drawToScreen () {
156
210
_leds.startDrawing ();
157
- for (int x = 0 ; x < _leds.columns (); x++) {
158
- for (int y = 0 ; y < _leds.rows (); y++ ) {
211
+ for (unsigned int x = 0 ; x < _leds.columns (); x++) {
212
+ for (unsigned int y = 0 ; y < _leds.rows (); y++ ) {
159
213
LifeState currentState = this ->getCellStatus (y, x);
160
214
RGBColorType cellColor = this ->getColorForLifeState (currentState);
161
215
_leds.image ().pixel (y, x) = cellColor;
@@ -176,6 +230,9 @@ RGBColorType CellUniverse::getColorForLifeState( LifeState state ) const {
176
230
case DYING:
177
231
cellColor = RED_COLOR;
178
232
break ;
233
+ case GAME_OVER:
234
+ cellColor = BLACK_COLOR;
235
+ break ;
179
236
case DEAD:
180
237
default :
181
238
cellColor = BLACK_COLOR;
0 commit comments