root/trunk/qd/living_space.d

Revision 548, 6.0 kB (checked in by FeepingCreature, 3 years ago)
  • Fixed cellular
Line 
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 }
Note: See TracBrowser for help on using the browser.