| 1 |
module living_space; |
|---|
| 2 |
|
|---|
| 3 |
// von Neumann == TLRB, Moore == 12346789, Serial=Left, Right, Wraparound +1/-1 |
|---|
| 4 |
typedef ubyte SpaceType; |
|---|
| 5 |
const SpaceType Neumann=0, Moore=1; |
|---|
| 6 |
|
|---|
| 7 |
void dumpESP() { void* res = void; asm { mov res, ESP; } writefln(res); } |
|---|
| 8 |
|
|---|
| 9 |
import tools.mersenne, tools.array2d, tools.threads, qd, std.stdio, tools.base; |
|---|
| 10 |
class Space(SpaceType H, string EVAL="") { |
|---|
| 11 |
int boxsize, border; |
|---|
| 12 |
bool wrap; |
|---|
| 13 |
array2d!(ubyte) state, state2; |
|---|
| 14 |
array2d!(bool) changed, changed2; |
|---|
| 15 |
const ubyte xsize=2, xshift=1, ysize=2, yshift=1; |
|---|
| 16 |
rgb[] cols; |
|---|
| 17 |
void stamp(int[][] what, int xpos=0, int ypos=0) { |
|---|
| 18 |
auto h=what.length; |
|---|
| 19 |
auto w=0; foreach (wh; what) if (wh.length>w) w=wh.length; |
|---|
| 20 |
|
|---|
| 21 |
if (h>state.height) throw new Exception("Pattern too high to stamp: "~.toString(h)~"!"); |
|---|
| 22 |
if (w>state.width) throw new Exception("Pattern too wide to stamp: "~.toString(w)~"!"); |
|---|
| 23 |
foreach (iy, row; what) { |
|---|
| 24 |
foreach (ix, cell; row) { |
|---|
| 25 |
auto x=ix+(state.width-w)/2+(w+4)*xpos, y=iy+(state.height-h)/2+(h+4)*ypos; |
|---|
| 26 |
switch (cell) { |
|---|
| 27 |
case -1: break; |
|---|
| 28 |
case -2: state[x, y]=[cast(ubyte) 1, 4, 7][rand()%3]; break; |
|---|
| 29 |
default: state[x, y]=cast(ubyte) cell; |
|---|
| 30 |
} |
|---|
| 31 |
} |
|---|
| 32 |
} |
|---|
| 33 |
} |
|---|
| 34 |
this(int b, int o, bool w, int[][] init) { |
|---|
| 35 |
boxsize=b; border=o; wrap=w; |
|---|
| 36 |
state = typeof(state) (screen.width/boxsize, screen.height/boxsize); |
|---|
| 37 |
|
|---|
| 38 |
changed = array2d!(bool)(state.width>>xshift, state.height>>yshift); |
|---|
| 39 |
changed2 = changed.dup; |
|---|
| 40 |
|
|---|
| 41 |
assert((state.width%xsize)==0, "Width must be multiple of changesize!"); |
|---|
| 42 |
assert((state.height%ysize)==0, "Height must be multiple of changesize!"); |
|---|
| 43 |
|
|---|
| 44 |
changed = true; |
|---|
| 45 |
|
|---|
| 46 |
if (init) stamp(init); |
|---|
| 47 |
state2 = state.dup; |
|---|
| 48 |
// 0 1 2 3 4 5 6 7 8 9 10 |
|---|
| 49 |
cols=[Black, Blue, Red, Red~Blue, Green, Red~White, Green~Blue, White, Red~Black, Yellow, Blue~Black]; |
|---|
| 50 |
} |
|---|
| 51 |
void render() { |
|---|
| 52 |
auto active_cols = new rgb[cols.length], inactive_cols = active_cols.dup; |
|---|
| 53 |
foreach (i, col; cols) { active_cols[i] = col~Green~col~col; inactive_cols[i] = col~Red~col~col; } |
|---|
| 54 |
foreach (x, y, value; state) { |
|---|
| 55 |
typeof(cols[0]) c; |
|---|
| 56 |
if (changed[x>>xshift, y>>yshift]) |
|---|
| 57 |
c=active_cols[value]; |
|---|
| 58 |
else |
|---|
| 59 |
c=inactive_cols[value]; |
|---|
| 60 |
if (boxsize==1) { |
|---|
| 61 |
pset(x, y, c); |
|---|
| 62 |
} else { |
|---|
| 63 |
line(x*boxsize, y*boxsize, (x+1)*boxsize-border, (y+1)*boxsize-border, Fill=c); |
|---|
| 64 |
if (border) line(x*boxsize-1, y*boxsize-1, (x+1)*boxsize-1, (y+1)*boxsize-1, Box=White~Black~Black~Black~Black); |
|---|
| 65 |
} |
|---|
| 66 |
} |
|---|
| 67 |
} |
|---|
| 68 |
static if (EVAL.length) mixin(EVAL); |
|---|
| 69 |
else { |
|---|
| 70 |
static if (H==Neumann) abstract ubyte eval(ubyte me, ubyte up, ubyte right, ubyte down, ubyte left); |
|---|
| 71 |
static if (H==Moore) abstract ubyte eval(ubyte, ubyte, ubyte, ubyte, ubyte, ubyte, ubyte, ubyte, ubyte); |
|---|
| 72 |
} |
|---|
| 73 |
uint calcLine(int y) { |
|---|
| 74 |
uint res; |
|---|
| 75 |
auto width = state.width; |
|---|
| 76 |
const size_t ymask=ysize-1; |
|---|
| 77 |
auto yd=y>>yshift, ym=y&ymask; |
|---|
| 78 |
|
|---|
| 79 |
auto |
|---|
| 80 |
changed_cur=changed2.h_iter(yd), |
|---|
| 81 |
changed_above=changed2.h_iter(yd-1), |
|---|
| 82 |
changed_below=changed2.h_iter(yd+1), |
|---|
| 83 |
changed_is=changed.h_iter(yd); |
|---|
| 84 |
|
|---|
| 85 |
auto resline = state2.h_iter(y); |
|---|
| 86 |
auto myline = state.h_iter(y), above = state.h_iter(y-1), below = state.h_iter(y+1); |
|---|
| 87 |
|
|---|
| 88 |
static if (H==Moore) ubyte a=void, b=void, c=void, d=void, e=void, f=void, g=void, h=void, i=void; |
|---|
| 89 |
else ubyte prev=void, cur=void, next=void; |
|---|
| 90 |
|
|---|
| 91 |
size_t x=0; |
|---|
| 92 |
void reset() { |
|---|
| 93 |
resline.pos=x; myline.pos=x; above.pos=x; below.pos=x; |
|---|
| 94 |
static if (H==Moore) { |
|---|
| 95 |
a=above.prev; b=above(); c=above.next; |
|---|
| 96 |
d=myline.prev; e=myline(); f=myline.next; |
|---|
| 97 |
g=below.prev; h=below(); i=below.next; |
|---|
| 98 |
} else { prev=myline.prev(); cur=myline(); next=myline.next(); } |
|---|
| 99 |
} |
|---|
| 100 |
void changed() { |
|---|
| 101 |
auto xs = x >> xshift; |
|---|
| 102 |
changed_above.pos = changed_cur.pos = changed_below.pos = xs; |
|---|
| 103 |
auto xm = x & (xsize-1); |
|---|
| 104 |
void x_changed(typeof(changed_cur) ch) { |
|---|
| 105 |
if (!xm) ch.prev = true; |
|---|
| 106 |
ch = true; |
|---|
| 107 |
if (xm == xsize-1) ch.next = true; |
|---|
| 108 |
} |
|---|
| 109 |
if (!ym) x_changed(changed_above); |
|---|
| 110 |
x_changed(changed_cur); |
|---|
| 111 |
if (ym == ysize-1) x_changed(changed_below); |
|---|
| 112 |
} |
|---|
| 113 |
bool skipped=true; |
|---|
| 114 |
while (x<width) { |
|---|
| 115 |
changed_is.pos=x >> xshift; |
|---|
| 116 |
if (!changed_is() && !changed_is.done) { |
|---|
| 117 |
skipped = true; |
|---|
| 118 |
do changed_is ++; |
|---|
| 119 |
while (!changed_is() && !changed_is.done); |
|---|
| 120 |
} |
|---|
| 121 |
if (changed_is.done && !changed_is()) break; |
|---|
| 122 |
if (skipped) { x = changed_is.pos << xshift; reset(); skipped=false; } |
|---|
| 123 |
else { |
|---|
| 124 |
static if (H != Moore) { prev=cur; cur=next; next=myline.next(); } |
|---|
| 125 |
} |
|---|
| 126 |
static if (H==Moore) { |
|---|
| 127 |
if (x && x < width-3) { |
|---|
| 128 |
myline += 3; above += 3; below += 3; res += 3; |
|---|
| 129 |
// we know that x is nowhere near the border .. use nowrap versions |
|---|
| 130 |
if ((resline=eval(a, b, c, d, e, f, g, h, i))!=e) changed(); |
|---|
| 131 |
a = above.prev_nowrap; d = myline.prev_nowrap; g = below.prev_nowrap; resline ++; x ++; |
|---|
| 132 |
if ((resline=eval(b, c, a, e, f, d, h, i, g))!=f) changed(); |
|---|
| 133 |
b = above(); e = myline(); h = below(); resline ++; x ++; |
|---|
| 134 |
if ((resline=eval(c, a, b, f, d, e, i, g, h))!=d) changed(); |
|---|
| 135 |
c = above.next_nowrap; f = myline.next_nowrap; i = below.next_nowrap; resline ++; x ++; |
|---|
| 136 |
} else { |
|---|
| 137 |
if ((resline=eval(a, b, c, d, e, f, g, h, i))!=e) changed(); |
|---|
| 138 |
if (x<width-1) { |
|---|
| 139 |
resline++; myline++; above++; below++; |
|---|
| 140 |
a = b; b = c; c = above.next(); |
|---|
| 141 |
d = e; e = f; f = myline.next(); |
|---|
| 142 |
g = h; h = i; i = below.next(); |
|---|
| 143 |
} |
|---|
| 144 |
x++; res++; |
|---|
| 145 |
} |
|---|
| 146 |
} else { |
|---|
| 147 |
auto ncur=eval(cur, myline.aboveValue, next, myline.belowValue, prev); |
|---|
| 148 |
resline=ncur; |
|---|
| 149 |
if (ncur!=cur) changed(); |
|---|
| 150 |
resline++; |
|---|
| 151 |
myline++; |
|---|
| 152 |
res++; |
|---|
| 153 |
x++; |
|---|
| 154 |
} |
|---|
| 155 |
} |
|---|
| 156 |
return res; |
|---|
| 157 |
} |
|---|
| 158 |
void step() { |
|---|
| 159 |
auto height = state.height; |
|---|
| 160 |
changed2 = false; |
|---|
| 161 |
for (int y = 0; y < height; y++) { |
|---|
| 162 |
calcLine(y); |
|---|
| 163 |
} |
|---|
| 164 |
swap(changed, changed2); |
|---|
| 165 |
swap(state, state2); |
|---|
| 166 |
} |
|---|
| 167 |
} |
|---|