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