]>
git.saurik.com Git - wxWidgets.git/blob - demos/life/game.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Life! game logic
4 // Author: Guillermo Rodriguez Garcia, <guille@iies.es>
8 // Copyright: (c) 2000, Guillermo Rodriguez Garcia
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ==========================================================================
14 // ==========================================================================
16 // --------------------------------------------------------------------------
18 // --------------------------------------------------------------------------
21 #pragma implementation "game.h"
24 // for compilers that support precompilation, includes "wx/wx.h"
25 #include "wx/wxprec.h"
31 // for all others, include the necessary headers
38 // ==========================================================================
40 // ==========================================================================
42 // --------------------------------------------------------------------------
44 // --------------------------------------------------------------------------
46 /* Format of the cell: (32 bit integer)
48 * 0yyyyyyy yyyyyy0x xxxxxxxxx xxx000ff
50 * y = y coordinate (13 bits)
51 * x = x coordinate (13 bits)
54 * OK, there is a reason for this, I promise :-). But I won't explain
55 * it now; it will be more clear when I implement the optimized life
56 * algorithm for large universes.
59 Life::Life(int width
, int height
)
62 Create(width
, height
);
70 void Life::Create(int width
, int height
)
72 wxASSERT(width
> 0 && height
> 0 && m_cells
.IsEmpty());
77 // preallocate memory to speed up initialization
78 m_cells
.Alloc(m_width
* m_height
);
79 m_changed
.Alloc(1000);
82 for (int j
= 0; j
< m_height
; j
++)
83 for (int i
= 0; i
< m_width
; i
++)
84 m_cells
.Add( MakeCell(i
, j
, FALSE
) );
95 // set all cells in the array to dead
96 for (int j
= 0; j
< m_height
; j
++)
97 for (int i
= 0; i
< m_width
; i
++)
98 m_cells
[j
* m_width
+ i
] &= ~CELL_ALIVE
;
101 Cell
Life::MakeCell(int i
, int j
, bool alive
) const
103 return (Cell
)((j
<< 18) | (i
<< 5) | (alive
? CELL_ALIVE
: CELL_DEAD
));
106 bool Life::IsAlive(int i
, int j
) const
108 wxASSERT(i
>= 0 && j
>= 0 && i
< m_width
&& j
< m_height
);
110 return (m_cells
[j
* m_width
+ i
] & CELL_ALIVE
);
113 bool Life::IsAlive(Cell c
) const { return (c
& CELL_ALIVE
); };
114 int Life::GetX(Cell c
) const { return (c
>> 5) & 0x1fff; };
115 int Life::GetY(Cell c
) const { return (c
>> 18); };
117 Cell
Life::SetCell(int i
, int j
, bool alive
)
119 wxASSERT(i
>= 0 && j
>= 0 && i
< m_width
&& j
< m_height
);
121 Cell c
= MakeCell(i
, j
, alive
);
123 m_cells
[j
* m_width
+ i
] = c
;
127 void Life::SetShape(LifeShape
& shape
)
129 wxASSERT((m_width
>= shape
.m_width
) && (m_height
>= shape
.m_height
));
131 int i0
= (m_width
- shape
.m_width
) / 2;
132 int j0
= (m_height
- shape
.m_height
) / 2;
133 char *p
= shape
.m_data
;
136 for (int j
= j0
; j
< j0
+ shape
.m_height
; j
++)
137 for (int i
= i0
; i
< i0
+ shape
.m_width
; i
++)
138 SetCell(i
, j
, *(p
++) == '*');
147 /* 1st pass. Find and mark deaths and births for this generation.
150 * An organism with <= 1 neighbors will die due to isolation.
151 * An organism with >= 4 neighbors will die due to starvation.
152 * New organisms are born in cells with exactly 3 neighbors.
154 for (j
= 0; j
< m_height
; j
++)
155 for (i
= 0; i
< m_width
; i
++)
157 int neighbors
= GetNeighbors(i
, j
);
158 bool alive
= IsAlive(i
, j
);
160 /* Set CELL_MARK if this cell must change, clear it
161 * otherwise. We cannot toggle the CELL_ALIVE bit yet
162 * because all deaths and births are simultaneous (it
163 * would affect neighbouring cells).
165 if ((!alive
&& neighbors
== 3) ||
166 (alive
&& (neighbors
<= 1 || neighbors
>= 4)))
168 m_cells
[j
* m_width
+ i
] |= CELL_MARK
;
169 m_changed
.Add( MakeCell(i
, j
, !alive
) );
172 m_cells
[j
* m_width
+ i
] &= ~CELL_MARK
;
175 /* 2nd pass. Stabilize.
177 for (j
= 0; j
< m_height
; j
++)
178 for (i
= 0; i
< m_width
; i
++)
180 /* Toggle CELL_ALIVE for those cells marked in the
181 * previous pass. Do not clear the CELL_MARK bit yet;
182 * it is useful to know which cells have changed and
183 * thus must be updated in the screen.
185 if (m_cells
[j
* m_width
+ i
] & CELL_MARK
)
186 m_cells
[j
* m_width
+ i
] ^= CELL_ALIVE
;
189 return (!m_changed
.IsEmpty());
192 int Life::GetNeighbors(int x
, int y
) const
194 wxASSERT(x
>= 0 && y
>= 0 && x
< m_width
&& y
< m_height
);
198 int i0
= (x
)? (x
- 1) : 0;
199 int j0
= (y
)? (y
- 1) : 0;
200 int i1
= (x
< (m_width
- 1))? (x
+ 1) : (m_width
- 1);
201 int j1
= (y
< (m_height
- 1))? (y
+ 1) : (m_height
- 1);
203 if (m_wrap
&& ( !x
|| !y
|| x
== (m_width
- 1) || y
== (m_height
- 1)))
205 // this is an outer cell and wraparound is on
206 for (int j
= y
- 1; j
<= y
+ 1; j
++)
207 for (int i
= x
- 1; i
<= x
+ 1; i
++)
208 if (IsAlive( ((i
< 0)? (i
+ m_width
) : (i
% m_width
)),
209 ((j
< 0)? (j
+ m_height
) : (j
% m_height
)) ))
214 // this is an inner cell, or wraparound is off
215 for (int j
= j0
; j
<= j1
; j
++)
216 for (int i
= i0
; i
<= i1
; i
++)
221 // do not count ourselves
222 if (IsAlive(x
, y
)) neighbors
--;