@@ -28,6 +28,7 @@ public:
2828 const static LifeState BORN = 2 ;
2929 const static LifeState DYING = 3 ;
3030 const static LifeState DEAD = 0 ;
31+ const static LifeState GAME_OVER = 4 ;
3132
3233private:
3334
@@ -37,7 +38,10 @@ private:
3738 LifeState* _cells;
3839 LifeState* _nextCells;
3940
41+ bool _isReseting;
42+
4043 RGBColorType getColorForLifeState ( LifeState state ) const ;
44+
4145
4246protected:
4347 virtual void action ();
@@ -49,11 +53,12 @@ public:
4953 unsigned long updateMicros
5054 );
5155
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 ;
5762
5863 void drawToScreen ();
5964};
@@ -64,46 +69,47 @@ CellUniverse::CellUniverse(
6469) : TimerAction(updateMicros),
6570 _leds(matrix),
6671 _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 )
6874{
6975 memset (_cells,DEAD,matrix.rows ()*matrix.columns ()*sizeof (LifeState));
7076 memset (_nextCells,DEAD,matrix.rows ()*matrix.columns ()*sizeof (LifeState));
7177}
7278
73- void CellUniverse::setCellStatus (int row, int column, LifeState cellStatus) {
79+ void CellUniverse::setCellStatus (unsigned int row, unsigned int column, LifeState cellStatus) {
7480 if (row < 0 || row >= _leds.rows () || column < 0 || column >= _leds.columns ()) {
7581 return ;
7682 }
7783
78- int idx = row*_leds.columns () + column;
84+ unsigned int idx = row*_leds.columns () + column;
7985
8086 _cells[idx] = cellStatus;
8187}
8288
83- CellUniverse::LifeState CellUniverse::getCellStatus (int row, int column) const {
89+ CellUniverse::LifeState CellUniverse::getCellStatus (unsigned int row, unsigned int column) const {
8490 // 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 );
8793
8894 // double check just to be sure
8995 if (r < 0 || r >= _leds.rows () || c < 0 || c >= _leds.columns ()) {
9096 return CellUniverse::DEAD;
9197 }
9298
93- int idx = r*_leds.columns () + c;
99+ unsigned int idx = r*_leds.columns () + c;
94100
95101 return _cells[idx];
96102}
97103
98- bool CellUniverse::isAlive (int row, int column) const {
104+ bool CellUniverse::isAlive (unsigned int row, unsigned int column) const {
99105 return (this ->getCellStatus (row, column) == CellUniverse::ALIVE || this ->getCellStatus (row, column) == CellUniverse::BORN);
100106}
101107
102- int CellUniverse::countAliveNeighbors (int row, int column) const {
108+ int CellUniverse::countAliveNeighbors (unsigned int row, unsigned int column) const {
103109 int aliveCount = 0 ;
104110
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++ ) {
107113 if (this ->isAlive (y, x) && !(x == column && y == row)) {
108114 aliveCount++;
109115 }
@@ -114,9 +120,18 @@ int CellUniverse::countAliveNeighbors(int row, int column) const {
114120}
115121
116122void CellUniverse::action () {
123+ if (_isReseting) {
124+ delay (5000 );
125+ this ->createRandomState ();
126+ _isReseting = false ;
127+ return ;
128+ }
129+
117130 _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++ ) {
120135 LifeState newState = DEAD;
121136 LifeState currentState = this ->getCellStatus (y, x);
122137 int count = this ->countAliveNeighbors (y, x);
@@ -139,8 +154,11 @@ void CellUniverse::action() {
139154 }
140155 break ;
141156 }
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;
144162 _nextCells[idx] = newState;
145163
146164 RGBColorType cellColor = this ->getColorForLifeState (newState);
@@ -149,13 +167,49 @@ void CellUniverse::action() {
149167 }
150168 _leds.stopDrawing ();
151169
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 {
152183 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 ();
153207}
154208
155209void CellUniverse::drawToScreen () {
156210 _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++ ) {
159213 LifeState currentState = this ->getCellStatus (y, x);
160214 RGBColorType cellColor = this ->getColorForLifeState (currentState);
161215 _leds.image ().pixel (y, x) = cellColor;
@@ -176,6 +230,9 @@ RGBColorType CellUniverse::getColorForLifeState( LifeState state ) const {
176230 case DYING:
177231 cellColor = RED_COLOR;
178232 break ;
233+ case GAME_OVER:
234+ cellColor = BLACK_COLOR;
235+ break ;
179236 case DEAD:
180237 default :
181238 cellColor = BLACK_COLOR;
0 commit comments