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