3f66f6a5b3
This keyword is not expanded by Git which means it's not replaced with the correct revision value in the releases made using git-based scripts and it's confusing to have lines with unexpanded "$Id$" in the released files. As expanding them with Git is not that simple (it could be done with git archive and export-subst attribute) and there are not many benefits in having them in the first place, just remove all these lines. If nothing else, this will make an eventual transition to Git simpler. Closes #14487. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1503 lines
34 KiB
C++
1503 lines
34 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: game.cpp
|
|
// Purpose: Life! game logic
|
|
// Author: Guillermo Rodriguez Garcia, <guille@iies.es>
|
|
// Modified by:
|
|
// Created: Jan/2000
|
|
// Copyright: (c) 2000, Guillermo Rodriguez Garcia
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ==========================================================================
|
|
// headers, declarations, constants
|
|
// ==========================================================================
|
|
|
|
// For compilers that support precompilation, includes "wx/wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
|
|
#include "wx/log.h"
|
|
#include "wx/module.h"
|
|
#include "game.h"
|
|
|
|
#include <string.h> // for memset
|
|
|
|
|
|
#define CELLSARRAYSIZE 1024 // static array for BeginFind & co.
|
|
#define ALLOCBOXES 16 // number of cellboxes to alloc at once
|
|
#define MAXDEAD 8 // tics before removing cellbox from list
|
|
|
|
|
|
// ==========================================================================
|
|
// CellBox
|
|
// ==========================================================================
|
|
|
|
#define HASH(x, y) (((x >> 3) & 0x7f) << 7) + ((y >> 3) & 0x7f)
|
|
|
|
#define HASHSIZE 16384 // hash table size (do not change!)
|
|
#define CELLBOX 8 // cells in a cellbox (do not change!)
|
|
|
|
|
|
class LifeCellBox
|
|
{
|
|
public:
|
|
// members
|
|
inline bool IsAlive(int dx, int dy) const;
|
|
inline bool SetCell(int dx, int dy, bool alive);
|
|
|
|
// attributes
|
|
wxInt32 m_x, m_y; // position in universe
|
|
wxUint32 m_live1, m_live2; // alive cells (1 bit per cell)
|
|
wxUint32 m_old1, m_old2; // old values for m_live1, 2
|
|
wxUint32 m_on[8]; // neighbouring info
|
|
wxUint32 m_dead; // been dead for n generations
|
|
LifeCellBox *m_up, *m_dn, *m_lf, *m_rt; // neighbour CellBoxes
|
|
LifeCellBox *m_prev, *m_next; // in linked list
|
|
LifeCellBox *m_hprev, *m_hnext; // in hash table
|
|
};
|
|
|
|
|
|
// IsAlive:
|
|
// Returns whether cell dx, dy in this box is alive
|
|
//
|
|
bool LifeCellBox::IsAlive(int dx, int dy) const
|
|
{
|
|
if (dy > 3)
|
|
return (m_live2 & 1 << ((dy - 4) * 8 + dx)) ? true : false ;
|
|
else
|
|
return (m_live1 & 1 << ((dy) * 8 + dx)) ? true : false ;
|
|
}
|
|
|
|
// SetCell:
|
|
// Sets cell dx, dy in this box to 'alive', returns true if
|
|
// the previous value was different, false if it was the same.
|
|
//
|
|
bool LifeCellBox::SetCell(int dx, int dy, bool alive)
|
|
{
|
|
if (IsAlive(dx, dy) != alive)
|
|
{
|
|
if (dy > 3)
|
|
m_live2 ^= 1 << ((dy - 4) * 8 + dx);
|
|
else
|
|
m_live1 ^= 1 << ((dy) * 8 + dx);
|
|
|
|
// reset this here to avoid updating problems
|
|
m_dead = 0;
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
// ==========================================================================
|
|
// Life
|
|
// ==========================================================================
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Ctor and dtor
|
|
// --------------------------------------------------------------------------
|
|
|
|
Life::Life()
|
|
{
|
|
// pattern description
|
|
m_name = wxEmptyString;
|
|
m_rules = wxEmptyString;
|
|
m_description = wxEmptyString;
|
|
|
|
// pattern data
|
|
m_numcells = 0;
|
|
m_boxes = new LifeCellBox *[HASHSIZE];
|
|
m_head = NULL;
|
|
m_available = NULL;
|
|
for (int i = 0; i < HASHSIZE; i++)
|
|
m_boxes[i] = NULL;
|
|
|
|
// state vars for BeginFind & FindMore
|
|
m_cells = new LifeCell[CELLSARRAYSIZE];
|
|
m_ncells = 0;
|
|
m_findmore = false;
|
|
m_changed = false;
|
|
}
|
|
|
|
Life::~Life()
|
|
{
|
|
Clear();
|
|
|
|
delete[] m_boxes;
|
|
delete[] m_cells;
|
|
}
|
|
|
|
// Clear:
|
|
// Clears the board, freeing all storage.
|
|
//
|
|
void Life::Clear()
|
|
{
|
|
LifeCellBox *c, *nc;
|
|
|
|
// clear the hash table pointers
|
|
for (int i = 0; i < HASHSIZE; i++)
|
|
m_boxes[i] = NULL;
|
|
|
|
// free used boxes
|
|
c = m_head;
|
|
while (c)
|
|
{
|
|
nc = c->m_next;
|
|
delete c;
|
|
c = nc;
|
|
}
|
|
m_head = NULL;
|
|
|
|
// free available boxes
|
|
c = m_available;
|
|
while (c)
|
|
{
|
|
nc = c->m_next;
|
|
delete c;
|
|
c = nc;
|
|
}
|
|
m_available = NULL;
|
|
|
|
// reset state
|
|
m_name = wxEmptyString;
|
|
m_rules = wxEmptyString;
|
|
m_description = wxEmptyString;
|
|
m_numcells = 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Test and set individual cells
|
|
// --------------------------------------------------------------------------
|
|
|
|
// IsAlive:
|
|
// Returns whether cell (x, y) is alive.
|
|
//
|
|
bool Life::IsAlive(wxInt32 x, wxInt32 y)
|
|
{
|
|
LifeCellBox *c = LinkBox(x, y, false);
|
|
|
|
return (c && c->IsAlive( x - c->m_x, y - c->m_y ));
|
|
}
|
|
|
|
// SetCell:
|
|
// Sets or clears cell (x, y), according to the 'alive' param.
|
|
//
|
|
void Life::SetCell(wxInt32 x, wxInt32 y, bool alive)
|
|
{
|
|
LifeCellBox *c = LinkBox(x, y);
|
|
wxUint32 dx = x - c->m_x;
|
|
wxUint32 dy = y - c->m_y;
|
|
|
|
if (c->SetCell(dx, dy, alive))
|
|
{
|
|
if (alive)
|
|
m_numcells++;
|
|
else
|
|
m_numcells--;
|
|
}
|
|
}
|
|
|
|
void Life::SetPattern(const LifePattern& pattern)
|
|
{
|
|
wxArrayString data = pattern.m_shape;
|
|
wxString line;
|
|
long x = 0,
|
|
y = 0;
|
|
|
|
Clear();
|
|
for (size_t n = 0; n < data.GetCount(); n++)
|
|
{
|
|
line = data[n];
|
|
|
|
if ( (line.GetChar(0) != wxT('*')) &&
|
|
(line.GetChar(0) != wxT('.')) )
|
|
{
|
|
// assume that it is a digit or a minus sign
|
|
line.BeforeFirst(wxT(' ')).ToLong(&x);
|
|
line.AfterFirst(wxT(' ')).ToLong(&y);
|
|
}
|
|
else
|
|
{
|
|
// pattern data
|
|
for (size_t k = 0; k < line.Len(); k++)
|
|
SetCell(x + k, y, line.GetChar(k) == wxT('*'));
|
|
|
|
y++;
|
|
}
|
|
}
|
|
|
|
m_name = pattern.m_name;
|
|
m_rules = pattern.m_rules;
|
|
m_description = pattern.m_description;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Cellbox management functions
|
|
// --------------------------------------------------------------------------
|
|
|
|
// CreateBox:
|
|
// Creates a box in x, y, either taking it from the list
|
|
// of available boxes, or allocating a new one.
|
|
//
|
|
LifeCellBox* Life::CreateBox(wxInt32 x, wxInt32 y, wxUint32 hv)
|
|
{
|
|
LifeCellBox *c;
|
|
|
|
// if there are no available boxes, alloc a few more
|
|
if (!m_available)
|
|
for (int i = 1; i <= ALLOCBOXES; i++)
|
|
{
|
|
c = new LifeCellBox();
|
|
|
|
if (!c)
|
|
{
|
|
// TODO: handle memory errors. Note that right now, if we
|
|
// couldn't allocate at least one cellbox, we will crash
|
|
// before leaving CreateBox(). Probably we should try to
|
|
// allocate some boxes *before* the m_available list goes
|
|
// empty, so that we have a margin to handle errors
|
|
// gracefully.
|
|
wxLogFatalError(_("Out of memory! Aborting..."));
|
|
|
|
// NOTREACHED
|
|
}
|
|
|
|
c->m_next = m_available;
|
|
m_available = c;
|
|
}
|
|
|
|
// take a cellbox from the list of available boxes
|
|
c = m_available;
|
|
m_available = c->m_next;
|
|
|
|
// reset everything
|
|
memset((void *) c, 0, sizeof(LifeCellBox));
|
|
c->m_x = x;
|
|
c->m_y = y;
|
|
|
|
// insert c in the list
|
|
c->m_next = m_head;
|
|
m_head = c;
|
|
if (c->m_next) c->m_next->m_prev = c;
|
|
|
|
// insert c in the hash table
|
|
c->m_hnext = m_boxes[hv];
|
|
m_boxes[hv] = c;
|
|
if (c->m_hnext) c->m_hnext->m_hprev = c;
|
|
|
|
return c;
|
|
}
|
|
|
|
// LinkBox:
|
|
// Returns a pointer to the box (x, y); if it didn't exist yet,
|
|
// it returns NULL or creates a new one, depending on the value
|
|
// of the 'create' parameter.
|
|
//
|
|
LifeCellBox* Life::LinkBox(wxInt32 x, wxInt32 y, bool create)
|
|
{
|
|
wxUint32 hv;
|
|
LifeCellBox *c;
|
|
|
|
x &= 0xfffffff8;
|
|
y &= 0xfffffff8;
|
|
hv = HASH(x, y);
|
|
|
|
// search in the hash table
|
|
for (c = m_boxes[hv]; c; c = c->m_hnext)
|
|
if ((c->m_x == x) && (c->m_y == y)) return c;
|
|
|
|
// if not found, and (create == true), create a new one
|
|
return create? CreateBox(x, y, hv) : (LifeCellBox*) NULL;
|
|
}
|
|
|
|
// KillBox:
|
|
// Removes this box from the list and the hash table and
|
|
// puts it in the list of available boxes.
|
|
//
|
|
void Life::KillBox(LifeCellBox *c)
|
|
{
|
|
wxUint32 hv = HASH(c->m_x, c->m_y);
|
|
|
|
// remove from the list
|
|
if (c != m_head)
|
|
c->m_prev->m_next = c->m_next;
|
|
else
|
|
m_head = c->m_next;
|
|
|
|
// remove from the hash table
|
|
if (c != m_boxes[hv])
|
|
c->m_hprev->m_hnext = c->m_hnext;
|
|
else
|
|
m_boxes[hv] = c->m_hnext;
|
|
|
|
// update neighbours
|
|
if (c->m_next) c->m_next->m_prev = c->m_prev;
|
|
if (c->m_hnext) c->m_hnext->m_hprev = c->m_hprev;
|
|
if (c->m_up) c->m_up->m_dn = NULL;
|
|
if (c->m_dn) c->m_dn->m_up = NULL;
|
|
if (c->m_lf) c->m_lf->m_rt = NULL;
|
|
if (c->m_rt) c->m_rt->m_lf = NULL;
|
|
|
|
// append to the list of available boxes
|
|
c->m_next = m_available;
|
|
m_available = c;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Navigation
|
|
// --------------------------------------------------------------------------
|
|
|
|
LifeCell Life::FindCenter()
|
|
{
|
|
double sx, sy;
|
|
int n;
|
|
sx = 0.0;
|
|
sy = 0.0;
|
|
n = 0;
|
|
|
|
LifeCellBox *c;
|
|
for (c = m_head; c; c = c->m_next)
|
|
if (!c->m_dead)
|
|
{
|
|
sx += c->m_x;
|
|
sy += c->m_y;
|
|
n++;
|
|
}
|
|
|
|
if (n > 0)
|
|
{
|
|
sx = (sx / n) + CELLBOX / 2;
|
|
sy = (sy / n) + CELLBOX / 2;
|
|
}
|
|
|
|
LifeCell cell;
|
|
cell.i = (wxInt32) sx;
|
|
cell.j = (wxInt32) sy;
|
|
return cell;
|
|
}
|
|
|
|
LifeCell Life::FindNorth()
|
|
{
|
|
wxInt32 x = 0, y = 0;
|
|
bool first = true;
|
|
|
|
LifeCellBox *c;
|
|
for (c = m_head; c; c = c->m_next)
|
|
if (!c->m_dead && ((first) || (c->m_y < y)))
|
|
{
|
|
x = c->m_x;
|
|
y = c->m_y;
|
|
first = false;
|
|
}
|
|
|
|
LifeCell cell;
|
|
cell.i = first? 0 : x + CELLBOX / 2;
|
|
cell.j = first? 0 : y + CELLBOX / 2;
|
|
return cell;
|
|
}
|
|
|
|
LifeCell Life::FindSouth()
|
|
{
|
|
wxInt32 x = 0, y = 0;
|
|
bool first = true;
|
|
|
|
LifeCellBox *c;
|
|
for (c = m_head; c; c = c->m_next)
|
|
if (!c->m_dead && ((first) || (c->m_y > y)))
|
|
{
|
|
x = c->m_x;
|
|
y = c->m_y;
|
|
first = false;
|
|
}
|
|
|
|
LifeCell cell;
|
|
cell.i = first? 0 : x + CELLBOX / 2;
|
|
cell.j = first? 0 : y + CELLBOX / 2;
|
|
return cell;
|
|
}
|
|
|
|
LifeCell Life::FindWest()
|
|
{
|
|
wxInt32 x = 0, y = 0;
|
|
bool first = true;
|
|
|
|
LifeCellBox *c;
|
|
for (c = m_head; c; c = c->m_next)
|
|
if (!c->m_dead && ((first) || (c->m_x < x)))
|
|
{
|
|
x = c->m_x;
|
|
y = c->m_y;
|
|
first = false;
|
|
}
|
|
|
|
LifeCell cell;
|
|
cell.i = first? 0 : x + CELLBOX / 2;
|
|
cell.j = first? 0 : y + CELLBOX / 2;
|
|
return cell;
|
|
}
|
|
|
|
LifeCell Life::FindEast()
|
|
{
|
|
wxInt32 x = 0, y = 0;
|
|
bool first = true;
|
|
|
|
LifeCellBox *c;
|
|
for (c = m_head; c; c = c->m_next)
|
|
if (!c->m_dead && ((first) || (c->m_x > x)))
|
|
{
|
|
x = c->m_x;
|
|
y = c->m_y;
|
|
first = false;
|
|
}
|
|
|
|
LifeCell cell;
|
|
cell.i = first? 0 : x + CELLBOX / 2;
|
|
cell.j = first? 0 : y + CELLBOX / 2;
|
|
return cell;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// FindMore & co.
|
|
// --------------------------------------------------------------------------
|
|
|
|
// DoLine:
|
|
// Post eight cells to the cell arrays - leave out the fourth
|
|
// argument (or pass 0, the default value) to post alive cells
|
|
// only, else it will post cells which have changed.
|
|
//
|
|
void Life::DoLine(wxInt32 x, wxInt32 y, wxUint32 live, wxUint32 old)
|
|
{
|
|
wxUint32 diff = (live ^ old) & 0xff;
|
|
|
|
if (!diff) return;
|
|
|
|
for (wxInt32 k = 8; k; k--, x++)
|
|
{
|
|
if (diff & 0x01)
|
|
{
|
|
m_cells[m_ncells].i = x;
|
|
m_cells[m_ncells].j = y;
|
|
m_ncells++;
|
|
}
|
|
diff >>= 1;
|
|
}
|
|
}
|
|
|
|
void Life::BeginFind(wxInt32 x0, wxInt32 y0, wxInt32 x1, wxInt32 y1, bool changed)
|
|
{
|
|
// TODO: optimize for the case where the maximum number of
|
|
// cellboxes that fit in the specified viewport is smaller
|
|
// than the current total of boxes; iterating over the list
|
|
// should then be faster than searching in the hash table.
|
|
|
|
m_x0 = m_x = x0 & 0xfffffff8;
|
|
m_y0 = m_y = y0 & 0xfffffff8;
|
|
m_x1 = (x1 + 7) & 0xfffffff8;
|
|
m_y1 = (y1 + 7) & 0xfffffff8;
|
|
|
|
m_findmore = true;
|
|
m_changed = changed;
|
|
}
|
|
|
|
bool Life::FindMore(LifeCell *cells[], size_t *ncells)
|
|
{
|
|
LifeCellBox *c;
|
|
*cells = m_cells;
|
|
m_ncells = 0;
|
|
|
|
if (m_changed)
|
|
{
|
|
for ( ; m_y <= m_y1; m_y += 8, m_x = m_x0)
|
|
for ( ; m_x <= m_x1; m_x += 8)
|
|
{
|
|
if ((c = LinkBox(m_x, m_y, false)) == NULL)
|
|
continue;
|
|
|
|
// check whether there is enough space left in the array
|
|
if (m_ncells > (CELLSARRAYSIZE - 64))
|
|
{
|
|
*ncells = m_ncells;
|
|
return false;
|
|
}
|
|
|
|
DoLine(m_x, m_y , c->m_live1, c->m_old1 );
|
|
DoLine(m_x, m_y + 1, c->m_live1 >> 8, c->m_old1 >> 8 );
|
|
DoLine(m_x, m_y + 2, c->m_live1 >> 16, c->m_old1 >> 16);
|
|
DoLine(m_x, m_y + 3, c->m_live1 >> 24, c->m_old1 >> 24);
|
|
DoLine(m_x, m_y + 4, c->m_live2, c->m_old2 );
|
|
DoLine(m_x, m_y + 5, c->m_live2 >> 8, c->m_old2 >> 8 );
|
|
DoLine(m_x, m_y + 6, c->m_live2 >> 16, c->m_old2 >> 16);
|
|
DoLine(m_x, m_y + 7, c->m_live2 >> 24, c->m_old2 >> 24);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( ; m_y <= m_y1; m_y += 8, m_x = m_x0)
|
|
for ( ; m_x <= m_x1; m_x += 8)
|
|
{
|
|
if ((c = LinkBox(m_x, m_y, false)) == NULL)
|
|
continue;
|
|
|
|
// check whether there is enough space left in the array
|
|
if (m_ncells > (CELLSARRAYSIZE - 64))
|
|
{
|
|
*ncells = m_ncells;
|
|
return false;
|
|
}
|
|
|
|
DoLine(m_x, m_y , c->m_live1 );
|
|
DoLine(m_x, m_y + 1, c->m_live1 >> 8 );
|
|
DoLine(m_x, m_y + 2, c->m_live1 >> 16);
|
|
DoLine(m_x, m_y + 3, c->m_live1 >> 24);
|
|
DoLine(m_x, m_y + 4, c->m_live2 );
|
|
DoLine(m_x, m_y + 5, c->m_live2 >> 8 );
|
|
DoLine(m_x, m_y + 6, c->m_live2 >> 16);
|
|
DoLine(m_x, m_y + 7, c->m_live2 >> 24);
|
|
}
|
|
}
|
|
|
|
*ncells = m_ncells;
|
|
m_findmore = false;
|
|
return true;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Evolution engine
|
|
// --------------------------------------------------------------------------
|
|
|
|
extern unsigned char *g_tab;
|
|
extern int g_tab1[];
|
|
extern int g_tab2[];
|
|
|
|
// NextTic:
|
|
// Advance one step in evolution :-)
|
|
//
|
|
bool Life::NextTic()
|
|
{
|
|
LifeCellBox *c, *up, *dn, *lf, *rt;
|
|
wxUint32 t1, t2, t3, t4;
|
|
bool changed = false;
|
|
|
|
m_numcells = 0;
|
|
|
|
// Stage 1:
|
|
// Compute neighbours of each cell
|
|
//
|
|
// WARNING: unrolled loops and lengthy code follows!
|
|
//
|
|
c = m_head;
|
|
|
|
while (c)
|
|
{
|
|
if (! (c->m_live1 || c->m_live2))
|
|
{
|
|
c = c->m_next;
|
|
continue;
|
|
}
|
|
up = c->m_up;
|
|
dn = c->m_dn;
|
|
lf = c->m_lf;
|
|
rt = c->m_rt;
|
|
|
|
// up
|
|
t1 = c->m_live1 & 0x000000ff;
|
|
if (t1)
|
|
{
|
|
if (!up)
|
|
{
|
|
up = LinkBox(c->m_x, c->m_y - 8);
|
|
up->m_dn = c;
|
|
}
|
|
t2 = g_tab1[t1];
|
|
up->m_on[7] += t2;
|
|
c->m_on[1] += t2;
|
|
c->m_on[0] += g_tab2[t1];
|
|
}
|
|
|
|
// down
|
|
t1 = (c->m_live2 & 0xff000000) >> 24;
|
|
if (t1)
|
|
{
|
|
if (!dn)
|
|
{
|
|
dn = LinkBox(c->m_x, c->m_y + 8);
|
|
dn->m_up = c;
|
|
}
|
|
t2 = g_tab1[t1];
|
|
dn->m_on[0] += t2;
|
|
c->m_on[6] += t2;
|
|
c->m_on[7] += g_tab2[t1];
|
|
}
|
|
|
|
t1 = c->m_live1;
|
|
t2 = c->m_live2;
|
|
|
|
// left
|
|
if (t1 & 0x01010101)
|
|
{
|
|
if (!lf)
|
|
{
|
|
lf = LinkBox(c->m_x - 8, c->m_y);
|
|
lf->m_rt = c;
|
|
}
|
|
if (t1 & 0x00000001)
|
|
{
|
|
if (!lf->m_up)
|
|
{
|
|
lf->m_up = LinkBox(c->m_x - 8, c->m_y - 8);
|
|
lf->m_up->m_dn = lf;
|
|
}
|
|
lf->m_up->m_on[7] += 0x10000000;
|
|
lf->m_on[0] += 0x10000000;
|
|
lf->m_on[1] += 0x10000000;
|
|
}
|
|
if (t1 & 0x00000100)
|
|
{
|
|
lf->m_on[0] += 0x10000000;
|
|
lf->m_on[1] += 0x10000000;
|
|
lf->m_on[2] += 0x10000000;
|
|
}
|
|
if (t1 & 0x00010000)
|
|
{
|
|
lf->m_on[1] += 0x10000000;
|
|
lf->m_on[2] += 0x10000000;
|
|
lf->m_on[3] += 0x10000000;
|
|
}
|
|
if (t1 & 0x01000000)
|
|
{
|
|
lf->m_on[2] += 0x10000000;
|
|
lf->m_on[3] += 0x10000000;
|
|
lf->m_on[4] += 0x10000000;
|
|
}
|
|
}
|
|
if (t2 & 0x01010101)
|
|
{
|
|
if (!lf)
|
|
{
|
|
lf = LinkBox(c->m_x - 8, c->m_y);
|
|
lf->m_rt = c;
|
|
}
|
|
if (t2 & 0x00000001)
|
|
{
|
|
lf->m_on[3] += 0x10000000;
|
|
lf->m_on[4] += 0x10000000;
|
|
lf->m_on[5] += 0x10000000;
|
|
}
|
|
if (t2 & 0x00000100)
|
|
{
|
|
lf->m_on[4] += 0x10000000;
|
|
lf->m_on[5] += 0x10000000;
|
|
lf->m_on[6] += 0x10000000;
|
|
}
|
|
if (t2 & 0x00010000)
|
|
{
|
|
lf->m_on[5] += 0x10000000;
|
|
lf->m_on[6] += 0x10000000;
|
|
lf->m_on[7] += 0x10000000;
|
|
}
|
|
if (t2 & 0x01000000)
|
|
{
|
|
if (!lf->m_dn)
|
|
{
|
|
lf->m_dn = LinkBox(c->m_x - 8, c->m_y + 8);
|
|
lf->m_dn->m_up = lf;
|
|
}
|
|
lf->m_on[6] += 0x10000000;
|
|
lf->m_on[7] += 0x10000000;
|
|
lf->m_dn->m_on[0] += 0x10000000;
|
|
}
|
|
}
|
|
|
|
// right
|
|
if (t1 & 0x80808080)
|
|
{
|
|
if (!rt)
|
|
{
|
|
rt = LinkBox(c->m_x + 8, c->m_y);
|
|
rt->m_lf = c;
|
|
}
|
|
if (t1 & 0x00000080)
|
|
{
|
|
if (!rt->m_up)
|
|
{
|
|
rt->m_up = LinkBox(c->m_x + 8, c->m_y - 8);
|
|
rt->m_up->m_dn = rt;
|
|
}
|
|
rt->m_up->m_on[7] += 0x00000001;
|
|
rt->m_on[0] += 0x00000001;
|
|
rt->m_on[1] += 0x00000001;
|
|
}
|
|
if (t1 & 0x00008000)
|
|
{
|
|
rt->m_on[0] += 0x00000001;
|
|
rt->m_on[1] += 0x00000001;
|
|
rt->m_on[2] += 0x00000001;
|
|
}
|
|
if (t1 & 0x00800000)
|
|
{
|
|
rt->m_on[1] += 0x00000001;
|
|
rt->m_on[2] += 0x00000001;
|
|
rt->m_on[3] += 0x00000001;
|
|
}
|
|
if (t1 & 0x80000000)
|
|
{
|
|
rt->m_on[2] += 0x00000001;
|
|
rt->m_on[3] += 0x00000001;
|
|
rt->m_on[4] += 0x00000001;
|
|
}
|
|
}
|
|
if (t2 & 0x80808080)
|
|
{
|
|
if (!rt)
|
|
{
|
|
rt = LinkBox(c->m_x + 8, c->m_y);
|
|
rt->m_lf = c;
|
|
}
|
|
if (t2 & 0x00000080)
|
|
{
|
|
rt->m_on[3] += 0x00000001;
|
|
rt->m_on[4] += 0x00000001;
|
|
rt->m_on[5] += 0x00000001;
|
|
}
|
|
if (t2 & 0x00008000)
|
|
{
|
|
rt->m_on[4] += 0x00000001;
|
|
rt->m_on[5] += 0x00000001;
|
|
rt->m_on[6] += 0x00000001;
|
|
}
|
|
if (t2 & 0x00800000)
|
|
{
|
|
rt->m_on[5] += 0x00000001;
|
|
rt->m_on[6] += 0x00000001;
|
|
rt->m_on[7] += 0x00000001;
|
|
}
|
|
if (t2 & 0x80000000)
|
|
{
|
|
if (!rt->m_dn)
|
|
{
|
|
rt->m_dn = LinkBox(c->m_x + 8, c->m_y + 8);
|
|
rt->m_dn->m_up = rt;
|
|
}
|
|
rt->m_on[6] += 0x00000001;
|
|
rt->m_on[7] += 0x00000001;
|
|
rt->m_dn->m_on[0] += 0x00000001;
|
|
}
|
|
}
|
|
|
|
// inner cells
|
|
int i;
|
|
for (i = 1; i <= 3; i++)
|
|
{
|
|
t1 = ((c->m_live1) >> (i * 8)) & 0x000000ff;
|
|
if (t1)
|
|
{
|
|
c->m_on[i - 1] += g_tab1[t1];
|
|
c->m_on[i ] += g_tab2[t1];
|
|
c->m_on[i + 1] += g_tab1[t1];
|
|
}
|
|
}
|
|
for (i = 0; i <= 2; i++)
|
|
{
|
|
t1 = ((c->m_live2) >> (i * 8)) & 0x000000ff;
|
|
if (t1)
|
|
{
|
|
c->m_on[i + 3] += g_tab1[t1];
|
|
c->m_on[i + 4] += g_tab2[t1];
|
|
c->m_on[i + 5] += g_tab1[t1];
|
|
}
|
|
}
|
|
|
|
c->m_up = up;
|
|
c->m_dn = dn;
|
|
c->m_lf = lf;
|
|
c->m_rt = rt;
|
|
c = c->m_next;
|
|
}
|
|
|
|
// Stage 2:
|
|
// Stabilize
|
|
//
|
|
c = m_head;
|
|
|
|
while (c)
|
|
{
|
|
t1 = 0;
|
|
t2 = 0;
|
|
|
|
t3 = c->m_live1;
|
|
c->m_old1 = t3;
|
|
|
|
t4 = c->m_on[0];
|
|
t1 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 ) & 0xf) ];
|
|
t1 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 4 ) & 0xf) ] << 4;
|
|
t4 = c->m_on[1];
|
|
t1 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 8 ) & 0xf) ] << 8;
|
|
t1 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 12) & 0xf) ] << 12;
|
|
t4 = c->m_on[2];
|
|
t1 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 16) & 0xf) ] << 16;
|
|
t1 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 20) & 0xf) ] << 20;
|
|
t4 = c->m_on[3];
|
|
t1 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 24) & 0xf) ] << 24;
|
|
t1 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 28) & 0xf) ] << 28;
|
|
|
|
t3 = c->m_live2;
|
|
c->m_old2 = t3;
|
|
|
|
t4 = c->m_on[4];
|
|
t2 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 ) & 0xf) ];
|
|
t2 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 4 ) & 0xf) ] << 4;
|
|
t4 = c->m_on[5];
|
|
t2 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 8 ) & 0xf) ] << 8;
|
|
t2 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 12) & 0xf) ] << 12;
|
|
t4 = c->m_on[6];
|
|
t2 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 16) & 0xf) ] << 16;
|
|
t2 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 20) & 0xf) ] << 20;
|
|
t4 = c->m_on[7];
|
|
t2 |= g_tab[ ((t4 & 0x0000ffff) << 4 ) + ((t3 >> 24) & 0xf) ] << 24;
|
|
t2 |= g_tab[ ((t4 & 0xffff0000) >> 12) + ((t3 >> 28) & 0xf) ] << 28;
|
|
|
|
c->m_on[0] = c->m_on[1] = c->m_on[2] = c->m_on[3] =
|
|
c->m_on[4] = c->m_on[5] = c->m_on[6] = c->m_on[7] = 0;
|
|
c->m_live1 = t1;
|
|
c->m_live2 = t2;
|
|
|
|
// count alive cells
|
|
#if 1
|
|
wxUint32 t1_, t2_;
|
|
|
|
t1_ = (t1 & 0x55555555) + (t1 >> 1 & 0x55555555);
|
|
t1_ = (t1_ & 0x33333333) + (t1_ >> 2 & 0x33333333);
|
|
|
|
t2_ = (t2 & 0x55555555) + (t2 >> 1 & 0x55555555);
|
|
t2_ = (t2_ & 0x33333333) + (t2_ >> 2 & 0x33333333) + t1_;
|
|
t2_ = (t2_ & 0x0F0F0F0F) + (t2_ >> 4 & 0x0F0F0F0F);
|
|
t2_ = (t2_ & 0x00FF00FF) + (t2_ >> 8 & 0x00FF00FF);
|
|
|
|
m_numcells += (t2_ & 0xFF) + (t2_ >> 16 & 0xFF);
|
|
#else
|
|
// Original, slower code
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
if (t1 & (1 << i)) m_numcells++;
|
|
if (t2 & (1 << i)) m_numcells++;
|
|
}
|
|
#endif
|
|
|
|
changed |= ((t1 ^ c->m_old1) || (t2 ^ c->m_old2));
|
|
|
|
// mark, and discard if necessary, dead boxes
|
|
if (t1 || t2)
|
|
{
|
|
c->m_dead = 0;
|
|
c = c->m_next;
|
|
}
|
|
else
|
|
{
|
|
LifeCellBox *aux = c->m_next;
|
|
if (c->m_dead++ > MAXDEAD)
|
|
KillBox(c);
|
|
|
|
c = aux;
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
// ==========================================================================
|
|
// LifeModule
|
|
// ==========================================================================
|
|
|
|
// A module to pregenerate lookup tables without having to do it
|
|
// from the application.
|
|
|
|
class LifeModule: public wxModule
|
|
{
|
|
DECLARE_DYNAMIC_CLASS(LifeModule)
|
|
|
|
public:
|
|
LifeModule() {};
|
|
bool OnInit();
|
|
void OnExit();
|
|
};
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(LifeModule, wxModule)
|
|
|
|
bool LifeModule::OnInit()
|
|
{
|
|
// see below
|
|
g_tab = new unsigned char [0xfffff];
|
|
|
|
if (!g_tab) return false;
|
|
|
|
for (wxUint32 i = 0; i < 0xfffff; i++)
|
|
{
|
|
wxUint32 val = i >> 4;
|
|
wxUint32 old = i & 0x0000f;
|
|
wxUint32 live = 0;
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
live >>= 1;
|
|
|
|
if (((val & 0xf) == 3) || (((val & 0xf) == 2) && (old & 0x1)))
|
|
live |= 0x8;
|
|
|
|
old >>= 1;
|
|
val >>= 4;
|
|
}
|
|
|
|
g_tab[i] = (unsigned char) live;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void LifeModule::OnExit()
|
|
{
|
|
delete [] g_tab;
|
|
}
|
|
|
|
|
|
// This table converts from number of neighbors (like in on[]) to
|
|
// bits, for a set of four cells. It takes as index a five-digit
|
|
// hexadecimal value (0xNNNNB) where Ns hold number of neighbors
|
|
// for each cell and B holds their previous state.
|
|
//
|
|
unsigned char *g_tab;
|
|
|
|
// This table converts from bits (like in live1, live2) to number
|
|
// of neighbors for each cell in the upper or lower row.
|
|
//
|
|
int g_tab1[]=
|
|
{
|
|
0x00000000,
|
|
0x00000011,
|
|
0x00000111,
|
|
0x00000122,
|
|
0x00001110,
|
|
0x00001121,
|
|
0x00001221,
|
|
0x00001232,
|
|
0x00011100,
|
|
0x00011111,
|
|
0x00011211,
|
|
0x00011222,
|
|
0x00012210,
|
|
0x00012221,
|
|
0x00012321,
|
|
0x00012332,
|
|
0x00111000,
|
|
0x00111011,
|
|
0x00111111,
|
|
0x00111122,
|
|
0x00112110,
|
|
0x00112121,
|
|
0x00112221,
|
|
0x00112232,
|
|
0x00122100,
|
|
0x00122111,
|
|
0x00122211,
|
|
0x00122222,
|
|
0x00123210,
|
|
0x00123221,
|
|
0x00123321,
|
|
0x00123332,
|
|
0x01110000,
|
|
0x01110011,
|
|
0x01110111,
|
|
0x01110122,
|
|
0x01111110,
|
|
0x01111121,
|
|
0x01111221,
|
|
0x01111232,
|
|
0x01121100,
|
|
0x01121111,
|
|
0x01121211,
|
|
0x01121222,
|
|
0x01122210,
|
|
0x01122221,
|
|
0x01122321,
|
|
0x01122332,
|
|
0x01221000,
|
|
0x01221011,
|
|
0x01221111,
|
|
0x01221122,
|
|
0x01222110,
|
|
0x01222121,
|
|
0x01222221,
|
|
0x01222232,
|
|
0x01232100,
|
|
0x01232111,
|
|
0x01232211,
|
|
0x01232222,
|
|
0x01233210,
|
|
0x01233221,
|
|
0x01233321,
|
|
0x01233332,
|
|
0x11100000,
|
|
0x11100011,
|
|
0x11100111,
|
|
0x11100122,
|
|
0x11101110,
|
|
0x11101121,
|
|
0x11101221,
|
|
0x11101232,
|
|
0x11111100,
|
|
0x11111111,
|
|
0x11111211,
|
|
0x11111222,
|
|
0x11112210,
|
|
0x11112221,
|
|
0x11112321,
|
|
0x11112332,
|
|
0x11211000,
|
|
0x11211011,
|
|
0x11211111,
|
|
0x11211122,
|
|
0x11212110,
|
|
0x11212121,
|
|
0x11212221,
|
|
0x11212232,
|
|
0x11222100,
|
|
0x11222111,
|
|
0x11222211,
|
|
0x11222222,
|
|
0x11223210,
|
|
0x11223221,
|
|
0x11223321,
|
|
0x11223332,
|
|
0x12210000,
|
|
0x12210011,
|
|
0x12210111,
|
|
0x12210122,
|
|
0x12211110,
|
|
0x12211121,
|
|
0x12211221,
|
|
0x12211232,
|
|
0x12221100,
|
|
0x12221111,
|
|
0x12221211,
|
|
0x12221222,
|
|
0x12222210,
|
|
0x12222221,
|
|
0x12222321,
|
|
0x12222332,
|
|
0x12321000,
|
|
0x12321011,
|
|
0x12321111,
|
|
0x12321122,
|
|
0x12322110,
|
|
0x12322121,
|
|
0x12322221,
|
|
0x12322232,
|
|
0x12332100,
|
|
0x12332111,
|
|
0x12332211,
|
|
0x12332222,
|
|
0x12333210,
|
|
0x12333221,
|
|
0x12333321,
|
|
0x12333332,
|
|
0x11000000,
|
|
0x11000011,
|
|
0x11000111,
|
|
0x11000122,
|
|
0x11001110,
|
|
0x11001121,
|
|
0x11001221,
|
|
0x11001232,
|
|
0x11011100,
|
|
0x11011111,
|
|
0x11011211,
|
|
0x11011222,
|
|
0x11012210,
|
|
0x11012221,
|
|
0x11012321,
|
|
0x11012332,
|
|
0x11111000,
|
|
0x11111011,
|
|
0x11111111,
|
|
0x11111122,
|
|
0x11112110,
|
|
0x11112121,
|
|
0x11112221,
|
|
0x11112232,
|
|
0x11122100,
|
|
0x11122111,
|
|
0x11122211,
|
|
0x11122222,
|
|
0x11123210,
|
|
0x11123221,
|
|
0x11123321,
|
|
0x11123332,
|
|
0x12110000,
|
|
0x12110011,
|
|
0x12110111,
|
|
0x12110122,
|
|
0x12111110,
|
|
0x12111121,
|
|
0x12111221,
|
|
0x12111232,
|
|
0x12121100,
|
|
0x12121111,
|
|
0x12121211,
|
|
0x12121222,
|
|
0x12122210,
|
|
0x12122221,
|
|
0x12122321,
|
|
0x12122332,
|
|
0x12221000,
|
|
0x12221011,
|
|
0x12221111,
|
|
0x12221122,
|
|
0x12222110,
|
|
0x12222121,
|
|
0x12222221,
|
|
0x12222232,
|
|
0x12232100,
|
|
0x12232111,
|
|
0x12232211,
|
|
0x12232222,
|
|
0x12233210,
|
|
0x12233221,
|
|
0x12233321,
|
|
0x12233332,
|
|
0x22100000,
|
|
0x22100011,
|
|
0x22100111,
|
|
0x22100122,
|
|
0x22101110,
|
|
0x22101121,
|
|
0x22101221,
|
|
0x22101232,
|
|
0x22111100,
|
|
0x22111111,
|
|
0x22111211,
|
|
0x22111222,
|
|
0x22112210,
|
|
0x22112221,
|
|
0x22112321,
|
|
0x22112332,
|
|
0x22211000,
|
|
0x22211011,
|
|
0x22211111,
|
|
0x22211122,
|
|
0x22212110,
|
|
0x22212121,
|
|
0x22212221,
|
|
0x22212232,
|
|
0x22222100,
|
|
0x22222111,
|
|
0x22222211,
|
|
0x22222222,
|
|
0x22223210,
|
|
0x22223221,
|
|
0x22223321,
|
|
0x22223332,
|
|
0x23210000,
|
|
0x23210011,
|
|
0x23210111,
|
|
0x23210122,
|
|
0x23211110,
|
|
0x23211121,
|
|
0x23211221,
|
|
0x23211232,
|
|
0x23221100,
|
|
0x23221111,
|
|
0x23221211,
|
|
0x23221222,
|
|
0x23222210,
|
|
0x23222221,
|
|
0x23222321,
|
|
0x23222332,
|
|
0x23321000,
|
|
0x23321011,
|
|
0x23321111,
|
|
0x23321122,
|
|
0x23322110,
|
|
0x23322121,
|
|
0x23322221,
|
|
0x23322232,
|
|
0x23332100,
|
|
0x23332111,
|
|
0x23332211,
|
|
0x23332222,
|
|
0x23333210,
|
|
0x23333221,
|
|
0x23333321,
|
|
0x23333332
|
|
};
|
|
|
|
// This table converts from bits (like in live1, live2) to number
|
|
// of neighbors for each cell in the same row (excluding ourselves)
|
|
//
|
|
int g_tab2[]=
|
|
{
|
|
0x00000000,
|
|
0x00000010,
|
|
0x00000101,
|
|
0x00000111,
|
|
0x00001010,
|
|
0x00001020,
|
|
0x00001111,
|
|
0x00001121,
|
|
0x00010100,
|
|
0x00010110,
|
|
0x00010201,
|
|
0x00010211,
|
|
0x00011110,
|
|
0x00011120,
|
|
0x00011211,
|
|
0x00011221,
|
|
0x00101000,
|
|
0x00101010,
|
|
0x00101101,
|
|
0x00101111,
|
|
0x00102010,
|
|
0x00102020,
|
|
0x00102111,
|
|
0x00102121,
|
|
0x00111100,
|
|
0x00111110,
|
|
0x00111201,
|
|
0x00111211,
|
|
0x00112110,
|
|
0x00112120,
|
|
0x00112211,
|
|
0x00112221,
|
|
0x01010000,
|
|
0x01010010,
|
|
0x01010101,
|
|
0x01010111,
|
|
0x01011010,
|
|
0x01011020,
|
|
0x01011111,
|
|
0x01011121,
|
|
0x01020100,
|
|
0x01020110,
|
|
0x01020201,
|
|
0x01020211,
|
|
0x01021110,
|
|
0x01021120,
|
|
0x01021211,
|
|
0x01021221,
|
|
0x01111000,
|
|
0x01111010,
|
|
0x01111101,
|
|
0x01111111,
|
|
0x01112010,
|
|
0x01112020,
|
|
0x01112111,
|
|
0x01112121,
|
|
0x01121100,
|
|
0x01121110,
|
|
0x01121201,
|
|
0x01121211,
|
|
0x01122110,
|
|
0x01122120,
|
|
0x01122211,
|
|
0x01122221,
|
|
0x10100000,
|
|
0x10100010,
|
|
0x10100101,
|
|
0x10100111,
|
|
0x10101010,
|
|
0x10101020,
|
|
0x10101111,
|
|
0x10101121,
|
|
0x10110100,
|
|
0x10110110,
|
|
0x10110201,
|
|
0x10110211,
|
|
0x10111110,
|
|
0x10111120,
|
|
0x10111211,
|
|
0x10111221,
|
|
0x10201000,
|
|
0x10201010,
|
|
0x10201101,
|
|
0x10201111,
|
|
0x10202010,
|
|
0x10202020,
|
|
0x10202111,
|
|
0x10202121,
|
|
0x10211100,
|
|
0x10211110,
|
|
0x10211201,
|
|
0x10211211,
|
|
0x10212110,
|
|
0x10212120,
|
|
0x10212211,
|
|
0x10212221,
|
|
0x11110000,
|
|
0x11110010,
|
|
0x11110101,
|
|
0x11110111,
|
|
0x11111010,
|
|
0x11111020,
|
|
0x11111111,
|
|
0x11111121,
|
|
0x11120100,
|
|
0x11120110,
|
|
0x11120201,
|
|
0x11120211,
|
|
0x11121110,
|
|
0x11121120,
|
|
0x11121211,
|
|
0x11121221,
|
|
0x11211000,
|
|
0x11211010,
|
|
0x11211101,
|
|
0x11211111,
|
|
0x11212010,
|
|
0x11212020,
|
|
0x11212111,
|
|
0x11212121,
|
|
0x11221100,
|
|
0x11221110,
|
|
0x11221201,
|
|
0x11221211,
|
|
0x11222110,
|
|
0x11222120,
|
|
0x11222211,
|
|
0x11222221,
|
|
0x01000000,
|
|
0x01000010,
|
|
0x01000101,
|
|
0x01000111,
|
|
0x01001010,
|
|
0x01001020,
|
|
0x01001111,
|
|
0x01001121,
|
|
0x01010100,
|
|
0x01010110,
|
|
0x01010201,
|
|
0x01010211,
|
|
0x01011110,
|
|
0x01011120,
|
|
0x01011211,
|
|
0x01011221,
|
|
0x01101000,
|
|
0x01101010,
|
|
0x01101101,
|
|
0x01101111,
|
|
0x01102010,
|
|
0x01102020,
|
|
0x01102111,
|
|
0x01102121,
|
|
0x01111100,
|
|
0x01111110,
|
|
0x01111201,
|
|
0x01111211,
|
|
0x01112110,
|
|
0x01112120,
|
|
0x01112211,
|
|
0x01112221,
|
|
0x02010000,
|
|
0x02010010,
|
|
0x02010101,
|
|
0x02010111,
|
|
0x02011010,
|
|
0x02011020,
|
|
0x02011111,
|
|
0x02011121,
|
|
0x02020100,
|
|
0x02020110,
|
|
0x02020201,
|
|
0x02020211,
|
|
0x02021110,
|
|
0x02021120,
|
|
0x02021211,
|
|
0x02021221,
|
|
0x02111000,
|
|
0x02111010,
|
|
0x02111101,
|
|
0x02111111,
|
|
0x02112010,
|
|
0x02112020,
|
|
0x02112111,
|
|
0x02112121,
|
|
0x02121100,
|
|
0x02121110,
|
|
0x02121201,
|
|
0x02121211,
|
|
0x02122110,
|
|
0x02122120,
|
|
0x02122211,
|
|
0x02122221,
|
|
0x11100000,
|
|
0x11100010,
|
|
0x11100101,
|
|
0x11100111,
|
|
0x11101010,
|
|
0x11101020,
|
|
0x11101111,
|
|
0x11101121,
|
|
0x11110100,
|
|
0x11110110,
|
|
0x11110201,
|
|
0x11110211,
|
|
0x11111110,
|
|
0x11111120,
|
|
0x11111211,
|
|
0x11111221,
|
|
0x11201000,
|
|
0x11201010,
|
|
0x11201101,
|
|
0x11201111,
|
|
0x11202010,
|
|
0x11202020,
|
|
0x11202111,
|
|
0x11202121,
|
|
0x11211100,
|
|
0x11211110,
|
|
0x11211201,
|
|
0x11211211,
|
|
0x11212110,
|
|
0x11212120,
|
|
0x11212211,
|
|
0x11212221,
|
|
0x12110000,
|
|
0x12110010,
|
|
0x12110101,
|
|
0x12110111,
|
|
0x12111010,
|
|
0x12111020,
|
|
0x12111111,
|
|
0x12111121,
|
|
0x12120100,
|
|
0x12120110,
|
|
0x12120201,
|
|
0x12120211,
|
|
0x12121110,
|
|
0x12121120,
|
|
0x12121211,
|
|
0x12121221,
|
|
0x12211000,
|
|
0x12211010,
|
|
0x12211101,
|
|
0x12211111,
|
|
0x12212010,
|
|
0x12212020,
|
|
0x12212111,
|
|
0x12212121,
|
|
0x12221100,
|
|
0x12221110,
|
|
0x12221201,
|
|
0x12221211,
|
|
0x12222110,
|
|
0x12222120,
|
|
0x12222211,
|
|
0x12222221
|
|
};
|