]> git.saurik.com Git - wxWidgets.git/blame - demos/life/game.cpp
Manual fixes
[wxWidgets.git] / demos / life / game.cpp
CommitLineData
2480be69
GRG
1/////////////////////////////////////////////////////////////////////////////
2// Name: game.cpp
3// Purpose: Life! game logic
4// Author: Guillermo Rodriguez Garcia, <guille@iies.es>
5// Modified by:
6// Created: Jan/2000
7// RCS-ID: $Id$
8// Copyright: (c) 2000, Guillermo Rodriguez Garcia
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ==========================================================================
e0a40292 13// headers, declarations, constants
2480be69
GRG
14// ==========================================================================
15
2480be69
GRG
16#ifdef __GNUG__
17 #pragma implementation "game.h"
18#endif
19
e0a40292
GRG
20#include "wx/log.h"
21#include "game.h"
2480be69 22
e0a40292
GRG
23#include <stdlib.h> // for abort
24#include <string.h> // for memset
2480be69 25
2480be69 26
b59102d5 27#define ARRAYSIZE 1024 // size of the static array for BeginFind & co.
e0a40292 28#define ALLOCBOXES 16 // number of cellboxes to alloc at once
2480be69
GRG
29
30// ==========================================================================
e0a40292 31// CellBox
2480be69
GRG
32// ==========================================================================
33
e0a40292
GRG
34#define HASH(x, y) (((x >> 3) & 0x7f) << 7) + ((y >> 3) & 0x7f)
35#define HASHSIZE 32768
36#define MAXDEAD 8
37
38
39class CellBox
40{
41public:
4ac99f4b 42 // members
e0a40292
GRG
43 inline bool IsAlive(int dx, int dy) const;
44 inline bool SetCell(int dx, int dy, bool alive);
45
46 // attributes
47 wxInt32 m_x, m_y; // position in universe
48 wxUint32 m_live1, m_live2; // alive cells (1 bit per cell)
49 wxUint32 m_old1, m_old2; // old values for m_live1, 2
50 wxUint32 m_on[8]; // neighbouring info
51 wxUint32 m_dead; // been dead for n generations
52 CellBox *m_up, *m_dn, *m_lf, *m_rt; // neighbour CellBoxes
53 CellBox *m_prev, *m_next; // in linked list
54 CellBox *m_hprev, *m_hnext; // in hash table
55};
56
57
58// IsAlive:
59// Returns whether cell dx, dy in this box is alive
60//
61bool CellBox::IsAlive(int dx, int dy) const
62{
63 if (dy > 3)
64 return (m_live2 & 1 << ((dy - 4) * 8 + dx));
65 else
66 return (m_live1 & 1 << ((dy) * 8 + dx));
67}
68
69// SetCell:
70// Sets cell dx, dy in this box to 'alive', returns TRUE if
71// the previous value was different, FALSE if it was the same.
72//
73bool CellBox::SetCell(int dx, int dy, bool alive)
74{
75 if (IsAlive(dx, dy) != alive)
76 {
77 if (dy > 3)
78 m_live2 ^= 1 << ((dy - 4) * 8 + dx);
79 else
80 m_live1 ^= 1 << ((dy) * 8 + dx);
81
82 // reset this here to avoid updating problems
83 m_dead = 0;
84
85 return TRUE;
86 }
87 else
88 return FALSE;
89}
90
91
92// ==========================================================================
2480be69 93// Life
e0a40292
GRG
94// ==========================================================================
95
96// --------------------------------------------------------------------------
97// Ctor and dtor
2480be69
GRG
98// --------------------------------------------------------------------------
99
e0a40292 100Life::Life()
4ac99f4b 101{
e0a40292
GRG
102 m_numcells = 0;
103 m_boxes = new CellBox *[HASHSIZE];
104 m_head = NULL;
105 m_available = NULL;
106 for (int i = 0; i < HASHSIZE; i++)
107 m_boxes[i] = NULL;
108
109 m_cells = new Cell[ARRAYSIZE];
110 m_ncells = 0;
111 m_findmore = FALSE;
112 m_changed = FALSE;
2480be69
GRG
113}
114
115Life::~Life()
116{
e0a40292
GRG
117 Clear();
118
119 delete[] m_boxes;
4ac99f4b 120 delete[] m_cells;
2480be69
GRG
121}
122
e0a40292
GRG
123// Clear:
124// Clears the board, freeing all storage.
4ac99f4b 125//
e0a40292 126void Life::Clear()
2480be69 127{
e0a40292 128 CellBox *c, *nc;
2480be69 129
e0a40292 130 m_numcells = 0;
4ac99f4b 131
e0a40292
GRG
132 // clear the hash table pointers
133 for (int i = 0; i < HASHSIZE; i++)
134 m_boxes[i] = NULL;
4ac99f4b 135
e0a40292
GRG
136 // free used boxes
137 c = m_head;
138 while (c)
139 {
140 nc = c->m_next;
141 delete c;
4ac99f4b 142 c = nc;
e0a40292
GRG
143 }
144 m_head = NULL;
2480be69 145
e0a40292
GRG
146 // free available boxes
147 c = m_available;
148 while (c)
149 {
150 nc = c->m_next;
151 delete c;
4ac99f4b 152 c = nc;
e0a40292
GRG
153 }
154 m_available = NULL;
155}
156
157// --------------------------------------------------------------------------
158// Test and set individual cells
159// --------------------------------------------------------------------------
160
161// IsAlive:
162// Returns whether cell (x, y) is alive.
163//
164bool Life::IsAlive(wxInt32 x, wxInt32 y)
165{
166 CellBox *c = LinkBox(x, y, FALSE);
2480be69 167
e0a40292 168 return (c && c->IsAlive( x - c->m_x, y - c->m_y ));
2480be69
GRG
169}
170
e0a40292
GRG
171// SetCell:
172// Sets or clears cell (x, y), according to the 'alive' param.
173//
174void Life::SetCell(wxInt32 x, wxInt32 y, bool alive)
175{
176 CellBox *c = LinkBox(x, y);
177 wxUint32 dx = x - c->m_x;
178 wxUint32 dy = y - c->m_y;
179
180 if (c->SetCell(dx, dy, alive))
181 {
182 if (alive)
183 m_numcells++;
184 else
185 m_numcells--;
186 }
4ac99f4b 187}
e0a40292
GRG
188
189void Life::SetShape(const LifeShape& shape)
2480be69 190{
e0a40292
GRG
191 char *p = shape.m_data;
192
193 int i0 = -(shape.m_width / 2);
194 int j0 = -(shape.m_height / 2);
195 int i1 = i0 + shape.m_width - 1;
196 int j1 = j0 + shape.m_height - 1;
197
198 Clear();
199 for (int j = j0; j <= j1; j++)
200 for (int i = i0; i <= i1; i++)
201 SetCell(i, j, *(p++) == '*');
2480be69
GRG
202}
203
e0a40292
GRG
204// --------------------------------------------------------------------------
205// Cellbox management functions
206// --------------------------------------------------------------------------
207
208// CreateBox:
33e39147 209// Creates a box in x, y, either taking it from the list
e0a40292
GRG
210// of available boxes, or allocating a new one.
211//
212CellBox* Life::CreateBox(wxInt32 x, wxInt32 y, wxUint32 hv)
2480be69 213{
e0a40292
GRG
214 CellBox *c;
215
216 // if there are no available boxes, alloc a few more
217 if (!m_available)
218 for (int i = 1; i <= ALLOCBOXES; i++)
219 {
220 c = new CellBox();
221
222 if (!c)
223 {
224 // TODO: handle memory errors. Note that right now, if we
225 // couldn't allocate at least one cellbox, we will crash
226 // before leaving CreateBox(). Probably we should try to
227 // allocate some boxes *before* the m_available list goes
228 // empty, so that we have a margin to handle errors
229 // gracefully.
230 wxLogFatalError(_("Out of memory! Aborting..."));
231
232 // the above call should abort, but it doesn't :-?
233 abort();
234
4ac99f4b 235 break;
e0a40292 236 }
4ac99f4b 237
e0a40292
GRG
238 c->m_next = m_available;
239 m_available = c;
240 }
241
242 // take a cellbox from the list of available boxes
243 c = m_available;
244 m_available = c->m_next;
245
246 // reset everything
247 memset((void *) c, 0, sizeof(CellBox));
248 c->m_x = x;
249 c->m_y = y;
250
251 // insert c in the list
252 c->m_next = m_head;
253 m_head = c;
254 if (c->m_next) c->m_next->m_prev = c;
255
256 // insert c in the hash table
257 c->m_hnext = m_boxes[hv];
258 m_boxes[hv] = c;
259 if (c->m_hnext) c->m_hnext->m_hprev = c;
260
261 return c;
2480be69
GRG
262}
263
e0a40292
GRG
264// LinkBox:
265// Returns a pointer to the box (x, y); if it didn't exist yet,
266// it returns NULL or creates a new one, depending on the 'create'
267// parameter.
268//
269CellBox* Life::LinkBox(wxInt32 x, wxInt32 y, bool create)
2480be69 270{
e0a40292
GRG
271 wxUint32 hv;
272 CellBox *c;
273
274 x &= 0xfffffff8;
275 y &= 0xfffffff8;
276 hv = HASH(x, y);
277
278 // search in the hash table
279 for (c = m_boxes[hv]; c; c = c->m_hnext)
280 if ((c->m_x == x) && (c->m_y == y)) return c;
281
282 // if not found, and (create == TRUE), create a new one
283 return create? CreateBox(x, y, hv) : NULL;
2480be69
GRG
284}
285
e0a40292
GRG
286// KillBox:
287// Removes this box from the list and the hash table and
288// puts it in the list of available boxes.
289//
290void Life::KillBox(CellBox *c)
2480be69 291{
e0a40292
GRG
292 wxUint32 hv = HASH(c->m_x, c->m_y);
293
294 // remove from the list
295 if (c != m_head)
296 c->m_prev->m_next = c->m_next;
297 else
298 m_head = c->m_next;
299
4ac99f4b 300 // remove from the hash table
e0a40292
GRG
301 if (c != m_boxes[hv])
302 c->m_hprev->m_hnext = c->m_hnext;
303 else
304 m_boxes[hv] = c->m_hnext;
305
4ac99f4b 306 // update neighbours
e0a40292
GRG
307 if (c->m_next) c->m_next->m_prev = c->m_prev;
308 if (c->m_hnext) c->m_hnext->m_hprev = c->m_hprev;
309 if (c->m_up) c->m_up->m_dn = NULL;
310 if (c->m_dn) c->m_dn->m_up = NULL;
311 if (c->m_lf) c->m_lf->m_rt = NULL;
312 if (c->m_rt) c->m_rt->m_lf = NULL;
2480be69 313
e0a40292
GRG
314 // append to the list of available boxes
315 c->m_next = m_available;
316 m_available = c;
2480be69
GRG
317}
318
e0a40292
GRG
319// --------------------------------------------------------------------------
320// FindMore & co.
321// --------------------------------------------------------------------------
2480be69 322
e0a40292
GRG
323// Post eight cells to the cell arrays (changed cells only)
324void Life::DoLine(wxInt32 i, wxInt32 j, wxUint32 live, wxUint32 old)
2480be69 325{
e0a40292 326 wxUint32 diff = (live ^ old) & 0x000000ff;
2480be69 327
e0a40292 328 if (!diff) return;
2480be69 329
e0a40292
GRG
330 for (wxInt32 k = 8; k; k--, i++)
331 {
332 if (diff & 0x01)
333 {
334 m_cells[m_ncells].i = i;
335 m_cells[m_ncells].j = j;
336 m_ncells++;
337 }
338 diff >>= 1;
339 live >>= 1;
340 }
2480be69 341}
4ac99f4b 342
e0a40292
GRG
343// Post eight cells to the cell arrays (alive cells only)
344void Life::DoLine(wxInt32 i, wxInt32 j, wxUint32 live)
345{
346 if (! (live & 0x000000ff)) return;
347
348 for (wxInt32 k = 8; k; k--, i++)
349 {
350 if (live & 0x01)
351 {
352 m_cells[m_ncells].i = i;
353 m_cells[m_ncells].j = j;
354 m_ncells++;
355 }
356 live >>= 1;
357 }
4ac99f4b 358}
2480be69 359
e0a40292 360void Life::BeginFind(wxInt32 i0, wxInt32 j0, wxInt32 i1, wxInt32 j1, bool changed)
2480be69 361{
e0a40292
GRG
362 // TODO: optimize for the case where the maximum number of
363 // cellboxes that fit in the specified viewport is smaller
364 // than the current total of boxes; iterating over the list
365 // should then be faster than searching in the hash table.
4ac99f4b 366
e0a40292
GRG
367 m_i0 = m_i = i0 & 0xfffffff8;
368 m_j0 = m_j = j0 & 0xfffffff8;
369 m_i1 = (i1 + 7) & 0xfffffff8;
370 m_j1 = (j1 + 7) & 0xfffffff8;
4ac99f4b 371
e0a40292
GRG
372 m_findmore = TRUE;
373 m_changed = changed;
374}
2480be69 375
e0a40292
GRG
376bool Life::FindMore(Cell *cells[], size_t *ncells)
377{
378 CellBox *c;
379 *cells = m_cells;
380 m_ncells = 0;
2480be69 381
e0a40292
GRG
382 if (m_changed)
383 {
384 for ( ; m_j <= m_j1; m_j += 8, m_i = m_i0)
385 for ( ; m_i <= m_i1; m_i += 8)
386 {
387 if ((c = LinkBox(m_i, m_j, FALSE)) == NULL)
388 continue;
4ac99f4b 389
e0a40292
GRG
390 // check whether there is enough space left in the array
391 if (m_ncells > (ARRAYSIZE - 64))
392 {
393 *ncells = m_ncells;
394 return FALSE;
395 }
4ac99f4b 396
e0a40292
GRG
397 DoLine(m_i, m_j , c->m_live1, c->m_old1 );
398 DoLine(m_i, m_j + 1, c->m_live1 >> 8, c->m_old1 >> 8 );
399 DoLine(m_i, m_j + 2, c->m_live1 >> 16, c->m_old1 >> 16);
400 DoLine(m_i, m_j + 3, c->m_live1 >> 24, c->m_old1 >> 24);
401 DoLine(m_i, m_j + 4, c->m_live2, c->m_old2 );
402 DoLine(m_i, m_j + 5, c->m_live2 >> 8, c->m_old2 >> 8 );
403 DoLine(m_i, m_j + 6, c->m_live2 >> 16, c->m_old2 >> 16);
404 DoLine(m_i, m_j + 7, c->m_live2 >> 24, c->m_old2 >> 24);
405 }
406 }
407 else
4ac99f4b 408 {
e0a40292
GRG
409 for ( ; m_j <= m_j1; m_j += 8, m_i = m_i0)
410 for ( ; m_i <= m_i1; m_i += 8)
411 {
412 if ((c = LinkBox(m_i, m_j, FALSE)) == NULL)
413 continue;
4ac99f4b 414
e0a40292
GRG
415 // check whether there is enough space left in the array
416 if (m_ncells > (ARRAYSIZE - 64))
417 {
418 *ncells = m_ncells;
419 return FALSE;
420 }
4ac99f4b 421
e0a40292
GRG
422 DoLine(m_i, m_j , c->m_live1 );
423 DoLine(m_i, m_j + 1, c->m_live1 >> 8 );
424 DoLine(m_i, m_j + 2, c->m_live1 >> 16);
425 DoLine(m_i, m_j + 3, c->m_live1 >> 24);
426 DoLine(m_i, m_j + 4, c->m_live2 );
427 DoLine(m_i, m_j + 5, c->m_live2 >> 8 );
428 DoLine(m_i, m_j + 6, c->m_live2 >> 16);
429 DoLine(m_i, m_j + 7, c->m_live2 >> 24);
430 }
431 }
4ac99f4b 432
e0a40292
GRG
433 *ncells = m_ncells;
434 m_findmore = FALSE;
435 return TRUE;
2480be69 436}
4ac99f4b 437
e0a40292
GRG
438// --------------------------------------------------------------------------
439// Evolution engine
440// --------------------------------------------------------------------------
2480be69 441
33e39147 442extern unsigned char *g_tab;
e0a40292
GRG
443extern int g_tab1[];
444extern int g_tab2[];
445
446// NextTic:
447// Advance one step in evolution :-)
4ac99f4b 448//
2480be69
GRG
449bool Life::NextTic()
450{
e0a40292 451 CellBox *c, *up, *dn, *lf, *rt;
33e39147 452 wxUint32 t1, t2, t3;
e0a40292 453 bool changed = FALSE;
4ac99f4b 454
e0a40292 455 m_numcells = 0;
4ac99f4b 456
e0a40292
GRG
457 // Stage 1:
458 // Compute neighbours of each cell
4ac99f4b 459 //
e0a40292 460 // WARNING: unrolled loops and lengthy code follows!
4ac99f4b 461 //
e0a40292 462 c = m_head;
2480be69 463
e0a40292
GRG
464 while (c)
465 {
466 if (! (c->m_live1 || c->m_live2))
467 {
468 c = c->m_next;
4ac99f4b
RD
469 continue;
470 }
e0a40292
GRG
471 up = c->m_up;
472 dn = c->m_dn;
473 lf = c->m_lf;
474 rt = c->m_rt;
2480be69 475
4ac99f4b 476 // up
e0a40292
GRG
477 t1 = c->m_live1 & 0x000000ff;
478 if (t1)
2480be69 479 {
e0a40292
GRG
480 if (!up)
481 {
482 up = LinkBox(c->m_x, c->m_y - 8);
4ac99f4b 483 up->m_dn = c;
e0a40292
GRG
484 }
485 t2 = g_tab1[t1];
486 up->m_on[7] += t2;
4ac99f4b 487 c->m_on[1] += t2;
e0a40292
GRG
488 c->m_on[0] += g_tab2[t1];
489 }
2480be69 490
e0a40292
GRG
491 // down
492 t1 = (c->m_live2 & 0xff000000) >> 24;
493 if (t1)
494 {
495 if (!dn)
2480be69 496 {
e0a40292 497 dn = LinkBox(c->m_x, c->m_y + 8);
4ac99f4b 498 dn->m_up = c;
e0a40292
GRG
499 }
500 t2 = g_tab1[t1];
501 dn->m_on[0] += t2;
4ac99f4b 502 c->m_on[6] += t2;
e0a40292
GRG
503 c->m_on[7] += g_tab2[t1];
504 }
4ac99f4b 505
e0a40292
GRG
506 t1 = c->m_live1;
507 t2 = c->m_live2;
4ac99f4b 508
e0a40292
GRG
509 // left
510 if (t1 & 0x01010101)
511 {
512 if (!lf)
513 {
4ac99f4b 514 lf = LinkBox(c->m_x - 8, c->m_y);
e0a40292
GRG
515 lf->m_rt = c;
516 }
517 if (t1 & 0x00000001)
518 {
519 if (!lf->m_up)
520 {
4ac99f4b 521 lf->m_up = LinkBox(c->m_x - 8, c->m_y - 8);
e0a40292
GRG
522 lf->m_up->m_dn = lf;
523 }
524 lf->m_up->m_on[7] += 0x10000000;
525 lf->m_on[0] += 0x10000000;
526 lf->m_on[1] += 0x10000000;
527 }
528 if (t1 & 0x00000100)
529 {
4ac99f4b
RD
530 lf->m_on[0] += 0x10000000;
531 lf->m_on[1] += 0x10000000;
532 lf->m_on[2] += 0x10000000;
533 }
e0a40292
GRG
534 if (t1 & 0x00010000)
535 {
4ac99f4b
RD
536 lf->m_on[1] += 0x10000000;
537 lf->m_on[2] += 0x10000000;
538 lf->m_on[3] += 0x10000000;
e0a40292
GRG
539 }
540 if (t1 & 0x01000000)
541 {
4ac99f4b
RD
542 lf->m_on[2] += 0x10000000;
543 lf->m_on[3] += 0x10000000;
544 lf->m_on[4] += 0x10000000;
e0a40292
GRG
545 }
546 }
547 if (t2 & 0x01010101)
548 {
549 if (!lf)
550 {
4ac99f4b 551 lf = LinkBox(c->m_x - 8, c->m_y);
e0a40292
GRG
552 lf->m_rt = c;
553 }
554 if (t2 & 0x00000001)
555 {
4ac99f4b
RD
556 lf->m_on[3] += 0x10000000;
557 lf->m_on[4] += 0x10000000;
558 lf->m_on[5] += 0x10000000;
559 }
e0a40292
GRG
560 if (t2 & 0x00000100)
561 {
4ac99f4b
RD
562 lf->m_on[4] += 0x10000000;
563 lf->m_on[5] += 0x10000000;
564 lf->m_on[6] += 0x10000000;
565 }
e0a40292
GRG
566 if (t2 & 0x00010000)
567 {
4ac99f4b
RD
568 lf->m_on[5] += 0x10000000;
569 lf->m_on[6] += 0x10000000;
570 lf->m_on[7] += 0x10000000;
e0a40292 571 }
4ac99f4b 572 if (t2 & 0x01000000)
e0a40292
GRG
573 {
574 if (!lf->m_dn)
575 {
4ac99f4b 576 lf->m_dn = LinkBox(c->m_x - 8, c->m_y + 8);
e0a40292
GRG
577 lf->m_dn->m_up = lf;
578 }
579 lf->m_on[6] += 0x10000000;
580 lf->m_on[7] += 0x10000000;
581 lf->m_dn->m_on[0] += 0x10000000;
2480be69 582 }
2480be69
GRG
583 }
584
e0a40292
GRG
585 // right
586 if (t1 & 0x80808080)
587 {
588 if (!rt)
589 {
4ac99f4b 590 rt = LinkBox(c->m_x + 8, c->m_y);
e0a40292
GRG
591 rt->m_lf = c;
592 }
593 if (t1 & 0x00000080)
594 {
595 if (!rt->m_up)
596 {
4ac99f4b 597 rt->m_up = LinkBox(c->m_x + 8, c->m_y - 8);
e0a40292
GRG
598 rt->m_up->m_dn = rt;
599 }
600 rt->m_up->m_on[7] += 0x00000001;
601 rt->m_on[0] += 0x00000001;
602 rt->m_on[1] += 0x00000001;
603 }
604 if (t1 & 0x00008000)
605 {
4ac99f4b
RD
606 rt->m_on[0] += 0x00000001;
607 rt->m_on[1] += 0x00000001;
608 rt->m_on[2] += 0x00000001;
609 }
e0a40292
GRG
610 if (t1 & 0x00800000)
611 {
4ac99f4b
RD
612 rt->m_on[1] += 0x00000001;
613 rt->m_on[2] += 0x00000001;
614 rt->m_on[3] += 0x00000001;
e0a40292
GRG
615 }
616 if (t1 & 0x80000000)
617 {
4ac99f4b
RD
618 rt->m_on[2] += 0x00000001;
619 rt->m_on[3] += 0x00000001;
620 rt->m_on[4] += 0x00000001;
e0a40292
GRG
621 }
622 }
623 if (t2 & 0x80808080)
624 {
625 if (!rt)
626 {
4ac99f4b 627 rt = LinkBox(c->m_x + 8, c->m_y);
e0a40292
GRG
628 rt->m_lf = c;
629 }
630 if (t2 & 0x00000080)
631 {
4ac99f4b
RD
632 rt->m_on[3] += 0x00000001;
633 rt->m_on[4] += 0x00000001;
634 rt->m_on[5] += 0x00000001;
635 }
e0a40292
GRG
636 if (t2 & 0x00008000)
637 {
4ac99f4b
RD
638 rt->m_on[4] += 0x00000001;
639 rt->m_on[5] += 0x00000001;
640 rt->m_on[6] += 0x00000001;
641 }
e0a40292
GRG
642 if (t2 & 0x00800000)
643 {
4ac99f4b
RD
644 rt->m_on[5] += 0x00000001;
645 rt->m_on[6] += 0x00000001;
646 rt->m_on[7] += 0x00000001;
e0a40292 647 }
4ac99f4b 648 if (t2 & 0x80000000)
e0a40292
GRG
649 {
650 if (!rt->m_dn)
651 {
4ac99f4b 652 rt->m_dn = LinkBox(c->m_x + 8, c->m_y + 8);
e0a40292
GRG
653 rt->m_dn->m_up = rt;
654 }
655 rt->m_on[6] += 0x00000001;
656 rt->m_on[7] += 0x00000001;
657 rt->m_dn->m_on[0] += 0x00000001;
658 }
659 }
4ac99f4b 660
e0a40292 661 // inner cells
4ac99f4b
RD
662 int i;
663 for (i = 1; i <= 3; i++)
e0a40292
GRG
664 {
665 t1 = ((c->m_live1) >> (i * 8)) & 0x000000ff;
666 if (t1)
667 {
668 c->m_on[i - 1] += g_tab1[t1];
669 c->m_on[i ] += g_tab2[t1];
670 c->m_on[i + 1] += g_tab1[t1];
671 }
672 }
4ac99f4b 673 for (i = 0; i <= 2; i++)
e0a40292
GRG
674 {
675 t1 = ((c->m_live2) >> (i * 8)) & 0x000000ff;
676 if (t1)
677 {
678 c->m_on[i + 3] += g_tab1[t1];
679 c->m_on[i + 4] += g_tab2[t1];
680 c->m_on[i + 5] += g_tab1[t1];
681 }
2480be69
GRG
682 }
683
e0a40292
GRG
684 c->m_up = up;
685 c->m_dn = dn;
686 c->m_lf = lf;
687 c->m_rt = rt;
688 c = c->m_next;
689 }
2480be69 690
e0a40292
GRG
691 // Stage 2:
692 // Stabilize
693 //
694 // WARNING: to be optimized and unrolled soon.
4ac99f4b 695 //
e0a40292 696 c = m_head;
4ac99f4b 697
e0a40292
GRG
698 while (c)
699 {
700 t1 = c->m_live1;
701 c->m_old1 = t1;
702 t2 = 0;
4ac99f4b 703
33e39147
GRG
704 t3 = c->m_on[0];
705 t2 |= g_tab[ ((t3 & 0x0000ffff) << 4 ) + ((t1 ) & 0xf) ];
706 t2 |= g_tab[ ((t3 & 0xffff0000) >> 12) + ((t1 >> 4 ) & 0xf) ] << 4;
707 t3 = c->m_on[1];
708 t2 |= g_tab[ ((t3 & 0x0000ffff) << 4 ) + ((t1 >> 8 ) & 0xf) ] << 8;
709 t2 |= g_tab[ ((t3 & 0xffff0000) >> 12) + ((t1 >> 12) & 0xf) ] << 12;
710 t3 = c->m_on[2];
711 t2 |= g_tab[ ((t3 & 0x0000ffff) << 4 ) + ((t1 >> 16) & 0xf) ] << 16;
712 t2 |= g_tab[ ((t3 & 0xffff0000) >> 12) + ((t1 >> 20) & 0xf) ] << 20;
713 t3 = c->m_on[3];
714 t2 |= g_tab[ ((t3 & 0x0000ffff) << 4 ) + ((t1 >> 24) & 0xf) ] << 24;
715 t2 |= g_tab[ ((t3 & 0xffff0000) >> 12) + ((t1 >> 28) & 0xf) ] << 28;
716
717 c->m_on[0] = c->m_on[1] = c->m_on[2] = c->m_on[3] = 0;
e0a40292 718 c->m_live1 = t2;
2480be69 719
e0a40292
GRG
720 t1 = c->m_live2;
721 c->m_old2 = t1;
722 t2 = 0;
2480be69 723
33e39147
GRG
724 t3 = c->m_on[4];
725 t2 |= g_tab[ ((t3 & 0x0000ffff) << 4 ) + ((t1 ) & 0xf) ];
726 t2 |= g_tab[ ((t3 & 0xffff0000) >> 12) + ((t1 >> 4 ) & 0xf) ] << 4;
727 t3 = c->m_on[5];
728 t2 |= g_tab[ ((t3 & 0x0000ffff) << 4 ) + ((t1 >> 8 ) & 0xf) ] << 8;
729 t2 |= g_tab[ ((t3 & 0xffff0000) >> 12) + ((t1 >> 12) & 0xf) ] << 12;
730 t3 = c->m_on[6];
731 t2 |= g_tab[ ((t3 & 0x0000ffff) << 4 ) + ((t1 >> 16) & 0xf) ] << 16;
732 t2 |= g_tab[ ((t3 & 0xffff0000) >> 12) + ((t1 >> 20) & 0xf) ] << 20;
733 t3 = c->m_on[7];
734 t2 |= g_tab[ ((t3 & 0x0000ffff) << 4 ) + ((t1 >> 24) & 0xf) ] << 24;
735 t2 |= g_tab[ ((t3 & 0xffff0000) >> 12) + ((t1 >> 28) & 0xf) ] << 28;
736
737 c->m_on[4] = c->m_on[5] = c->m_on[6] = c->m_on[7] = 0;
e0a40292 738 c->m_live2 = t2;
2480be69 739
e0a40292
GRG
740 // keep track of changes
741 changed |= ((c->m_live1 ^ c->m_old1) || (c->m_live2 ^ c->m_old2));
4ac99f4b 742
e0a40292
GRG
743 // mark, and discard if necessary, dead boxes
744 if (c->m_live1 || c->m_live2)
745 {
746 c->m_dead = 0;
747 c = c->m_next;
748 }
749 else
750 {
751 CellBox *aux = c->m_next;
752 if (c->m_dead++ > MAXDEAD)
4ac99f4b
RD
753 KillBox(c);
754
e0a40292
GRG
755 c = aux;
756 }
757 }
2480be69 758
e0a40292 759 return changed;
2480be69
GRG
760}
761
33e39147
GRG
762// ==========================================================================
763// LifeModule
764// ==========================================================================
765
766// A module to pregenerate lookup tables without having to do it
767// from the application.
768
769class LifeModule: public wxModule
770{
771DECLARE_DYNAMIC_CLASS(LifeModule)
772
773public:
774 LifeModule() {};
775 bool OnInit();
776 void OnExit();
777};
778
779IMPLEMENT_DYNAMIC_CLASS(LifeModule, wxModule)
780
781bool LifeModule::OnInit()
782{
783 // see below
784 g_tab = new unsigned char [0xfffff];
785
786 if (!g_tab) return FALSE;
787
788 for (wxUint32 i = 0; i < 0xfffff; i++)
789 {
790 wxUint32 val = i >> 4;
791 wxUint32 old = i & 0x0000f;
792 wxUint32 live = 0;
793
794 for (int j = 0; j < 4; j++)
795 {
796 live >>= 1;
797
798 if (((val & 0xf) == 3) || (((val & 0xf) == 2) && (old & 0x1)))
799 live |= 0x8;
800
801 old >>= 1;
802 val >>= 4;
803 }
804
805 g_tab[i] = (unsigned char) live;
806 }
807
808 return TRUE;
809}
810
811void LifeModule::OnExit()
812{
813 delete [] g_tab;
814}
815
816
817// This table converts from number of neighbors (like in on[]) to
818// bits, for a set of four cells. It takes as index a five-digit
819// hexadecimal value (0xNNNNB) where Ns hold number of neighbors
820// for each cell and B holds their previous state.
821//
822unsigned char *g_tab;
e0a40292
GRG
823
824// This table converts from bits (like in live1, live2) to number
825// of neighbors for each cell in the upper or lower row.
826//
827int g_tab1[]=
828{
829 0x00000000,
830 0x00000011,
831 0x00000111,
832 0x00000122,
833 0x00001110,
834 0x00001121,
835 0x00001221,
836 0x00001232,
837 0x00011100,
838 0x00011111,
839 0x00011211,
840 0x00011222,
841 0x00012210,
842 0x00012221,
843 0x00012321,
844 0x00012332,
845 0x00111000,
846 0x00111011,
847 0x00111111,
848 0x00111122,
849 0x00112110,
850 0x00112121,
851 0x00112221,
852 0x00112232,
853 0x00122100,
854 0x00122111,
855 0x00122211,
856 0x00122222,
857 0x00123210,
858 0x00123221,
859 0x00123321,
860 0x00123332,
861 0x01110000,
862 0x01110011,
863 0x01110111,
864 0x01110122,
865 0x01111110,
866 0x01111121,
867 0x01111221,
868 0x01111232,
869 0x01121100,
870 0x01121111,
871 0x01121211,
872 0x01121222,
873 0x01122210,
874 0x01122221,
875 0x01122321,
876 0x01122332,
877 0x01221000,
878 0x01221011,
879 0x01221111,
880 0x01221122,
881 0x01222110,
882 0x01222121,
883 0x01222221,
884 0x01222232,
885 0x01232100,
886 0x01232111,
887 0x01232211,
888 0x01232222,
889 0x01233210,
890 0x01233221,
891 0x01233321,
892 0x01233332,
893 0x11100000,
894 0x11100011,
895 0x11100111,
896 0x11100122,
897 0x11101110,
898 0x11101121,
899 0x11101221,
900 0x11101232,
901 0x11111100,
902 0x11111111,
903 0x11111211,
904 0x11111222,
905 0x11112210,
906 0x11112221,
907 0x11112321,
908 0x11112332,
909 0x11211000,
910 0x11211011,
911 0x11211111,
912 0x11211122,
913 0x11212110,
914 0x11212121,
915 0x11212221,
916 0x11212232,
917 0x11222100,
918 0x11222111,
919 0x11222211,
920 0x11222222,
921 0x11223210,
922 0x11223221,
923 0x11223321,
924 0x11223332,
925 0x12210000,
926 0x12210011,
927 0x12210111,
928 0x12210122,
929 0x12211110,
930 0x12211121,
931 0x12211221,
932 0x12211232,
933 0x12221100,
934 0x12221111,
935 0x12221211,
936 0x12221222,
937 0x12222210,
938 0x12222221,
939 0x12222321,
940 0x12222332,
941 0x12321000,
942 0x12321011,
943 0x12321111,
944 0x12321122,
945 0x12322110,
946 0x12322121,
947 0x12322221,
948 0x12322232,
949 0x12332100,
950 0x12332111,
951 0x12332211,
952 0x12332222,
953 0x12333210,
954 0x12333221,
955 0x12333321,
956 0x12333332,
957 0x11000000,
958 0x11000011,
959 0x11000111,
960 0x11000122,
961 0x11001110,
962 0x11001121,
963 0x11001221,
964 0x11001232,
965 0x11011100,
966 0x11011111,
967 0x11011211,
968 0x11011222,
969 0x11012210,
970 0x11012221,
971 0x11012321,
972 0x11012332,
973 0x11111000,
974 0x11111011,
975 0x11111111,
976 0x11111122,
977 0x11112110,
978 0x11112121,
979 0x11112221,
33e39147 980 0x11112232,
e0a40292
GRG
981 0x11122100,
982 0x11122111,
983 0x11122211,
984 0x11122222,
985 0x11123210,
986 0x11123221,
987 0x11123321,
988 0x11123332,
989 0x12110000,
990 0x12110011,
991 0x12110111,
992 0x12110122,
993 0x12111110,
994 0x12111121,
995 0x12111221,
996 0x12111232,
997 0x12121100,
998 0x12121111,
999 0x12121211,
1000 0x12121222,
1001 0x12122210,
1002 0x12122221,
1003 0x12122321,
1004 0x12122332,
1005 0x12221000,
1006 0x12221011,
1007 0x12221111,
1008 0x12221122,
1009 0x12222110,
1010 0x12222121,
1011 0x12222221,
1012 0x12222232,
1013 0x12232100,
1014 0x12232111,
1015 0x12232211,
1016 0x12232222,
1017 0x12233210,
1018 0x12233221,
1019 0x12233321,
1020 0x12233332,
1021 0x22100000,
1022 0x22100011,
1023 0x22100111,
1024 0x22100122,
1025 0x22101110,
1026 0x22101121,
1027 0x22101221,
1028 0x22101232,
1029 0x22111100,
1030 0x22111111,
1031 0x22111211,
1032 0x22111222,
1033 0x22112210,
1034 0x22112221,
1035 0x22112321,
1036 0x22112332,
1037 0x22211000,
1038 0x22211011,
1039 0x22211111,
1040 0x22211122,
1041 0x22212110,
1042 0x22212121,
1043 0x22212221,
1044 0x22212232,
1045 0x22222100,
1046 0x22222111,
1047 0x22222211,
1048 0x22222222,
1049 0x22223210,
1050 0x22223221,
1051 0x22223321,
1052 0x22223332,
1053 0x23210000,
1054 0x23210011,
1055 0x23210111,
1056 0x23210122,
1057 0x23211110,
1058 0x23211121,
1059 0x23211221,
1060 0x23211232,
1061 0x23221100,
1062 0x23221111,
1063 0x23221211,
1064 0x23221222,
1065 0x23222210,
1066 0x23222221,
1067 0x23222321,
1068 0x23222332,
1069 0x23321000,
1070 0x23321011,
1071 0x23321111,
1072 0x23321122,
1073 0x23322110,
1074 0x23322121,
1075 0x23322221,
1076 0x23322232,
1077 0x23332100,
1078 0x23332111,
1079 0x23332211,
1080 0x23332222,
1081 0x23333210,
1082 0x23333221,
1083 0x23333321,
1084 0x23333332
1085};
1086
1087// This table converts from bits (like in live1, live2) to number
1088// of neighbors for each cell in the same row (excluding ourselves)
1089//
1090int g_tab2[]=
1091{
1092 0x00000000,
1093 0x00000010,
1094 0x00000101,
1095 0x00000111,
1096 0x00001010,
1097 0x00001020,
1098 0x00001111,
1099 0x00001121,
1100 0x00010100,
1101 0x00010110,
1102 0x00010201,
1103 0x00010211,
1104 0x00011110,
1105 0x00011120,
1106 0x00011211,
1107 0x00011221,
1108 0x00101000,
1109 0x00101010,
1110 0x00101101,
1111 0x00101111,
1112 0x00102010,
1113 0x00102020,
1114 0x00102111,
1115 0x00102121,
1116 0x00111100,
1117 0x00111110,
1118 0x00111201,
1119 0x00111211,
1120 0x00112110,
1121 0x00112120,
1122 0x00112211,
1123 0x00112221,
1124 0x01010000,
1125 0x01010010,
1126 0x01010101,
1127 0x01010111,
1128 0x01011010,
1129 0x01011020,
1130 0x01011111,
1131 0x01011121,
1132 0x01020100,
1133 0x01020110,
1134 0x01020201,
1135 0x01020211,
1136 0x01021110,
1137 0x01021120,
1138 0x01021211,
1139 0x01021221,
1140 0x01111000,
1141 0x01111010,
1142 0x01111101,
1143 0x01111111,
1144 0x01112010,
1145 0x01112020,
1146 0x01112111,
1147 0x01112121,
1148 0x01121100,
1149 0x01121110,
1150 0x01121201,
1151 0x01121211,
1152 0x01122110,
1153 0x01122120,
1154 0x01122211,
1155 0x01122221,
1156 0x10100000,
1157 0x10100010,
1158 0x10100101,
1159 0x10100111,
1160 0x10101010,
1161 0x10101020,
1162 0x10101111,
1163 0x10101121,
1164 0x10110100,
1165 0x10110110,
1166 0x10110201,
1167 0x10110211,
1168 0x10111110,
1169 0x10111120,
1170 0x10111211,
1171 0x10111221,
1172 0x10201000,
1173 0x10201010,
1174 0x10201101,
1175 0x10201111,
1176 0x10202010,
1177 0x10202020,
1178 0x10202111,
1179 0x10202121,
1180 0x10211100,
1181 0x10211110,
1182 0x10211201,
1183 0x10211211,
1184 0x10212110,
1185 0x10212120,
1186 0x10212211,
1187 0x10212221,
1188 0x11110000,
1189 0x11110010,
1190 0x11110101,
1191 0x11110111,
1192 0x11111010,
1193 0x11111020,
1194 0x11111111,
1195 0x11111121,
1196 0x11120100,
1197 0x11120110,
1198 0x11120201,
1199 0x11120211,
1200 0x11121110,
1201 0x11121120,
1202 0x11121211,
1203 0x11121221,
1204 0x11211000,
1205 0x11211010,
1206 0x11211101,
1207 0x11211111,
1208 0x11212010,
1209 0x11212020,
1210 0x11212111,
1211 0x11212121,
1212 0x11221100,
1213 0x11221110,
1214 0x11221201,
1215 0x11221211,
1216 0x11222110,
1217 0x11222120,
1218 0x11222211,
1219 0x11222221,
1220 0x01000000,
1221 0x01000010,
1222 0x01000101,
1223 0x01000111,
1224 0x01001010,
1225 0x01001020,
1226 0x01001111,
1227 0x01001121,
1228 0x01010100,
1229 0x01010110,
1230 0x01010201,
1231 0x01010211,
1232 0x01011110,
1233 0x01011120,
1234 0x01011211,
1235 0x01011221,
1236 0x01101000,
1237 0x01101010,
1238 0x01101101,
1239 0x01101111,
1240 0x01102010,
1241 0x01102020,
1242 0x01102111,
1243 0x01102121,
1244 0x01111100,
1245 0x01111110,
1246 0x01111201,
1247 0x01111211,
1248 0x01112110,
1249 0x01112120,
1250 0x01112211,
1251 0x01112221,
1252 0x02010000,
1253 0x02010010,
1254 0x02010101,
1255 0x02010111,
1256 0x02011010,
1257 0x02011020,
1258 0x02011111,
1259 0x02011121,
1260 0x02020100,
1261 0x02020110,
1262 0x02020201,
1263 0x02020211,
1264 0x02021110,
1265 0x02021120,
1266 0x02021211,
1267 0x02021221,
1268 0x02111000,
1269 0x02111010,
1270 0x02111101,
1271 0x02111111,
1272 0x02112010,
1273 0x02112020,
1274 0x02112111,
1275 0x02112121,
1276 0x02121100,
1277 0x02121110,
1278 0x02121201,
1279 0x02121211,
1280 0x02122110,
1281 0x02122120,
1282 0x02122211,
1283 0x02122221,
1284 0x11100000,
1285 0x11100010,
1286 0x11100101,
1287 0x11100111,
1288 0x11101010,
1289 0x11101020,
1290 0x11101111,
1291 0x11101121,
1292 0x11110100,
1293 0x11110110,
1294 0x11110201,
1295 0x11110211,
1296 0x11111110,
1297 0x11111120,
1298 0x11111211,
1299 0x11111221,
1300 0x11201000,
1301 0x11201010,
1302 0x11201101,
1303 0x11201111,
1304 0x11202010,
1305 0x11202020,
1306 0x11202111,
1307 0x11202121,
1308 0x11211100,
1309 0x11211110,
1310 0x11211201,
1311 0x11211211,
1312 0x11212110,
1313 0x11212120,
1314 0x11212211,
1315 0x11212221,
1316 0x12110000,
1317 0x12110010,
1318 0x12110101,
1319 0x12110111,
1320 0x12111010,
1321 0x12111020,
1322 0x12111111,
1323 0x12111121,
1324 0x12120100,
1325 0x12120110,
1326 0x12120201,
1327 0x12120211,
1328 0x12121110,
1329 0x12121120,
1330 0x12121211,
1331 0x12121221,
1332 0x12211000,
1333 0x12211010,
1334 0x12211101,
1335 0x12211111,
1336 0x12212010,
1337 0x12212020,
1338 0x12212111,
1339 0x12212121,
1340 0x12221100,
1341 0x12221110,
1342 0x12221201,
1343 0x12221211,
1344 0x12222110,
1345 0x12222120,
1346 0x12222211,
1347 0x12222221
1348};