root/trunk/qd/cellular.d

Revision 548, 11.7 kB (checked in by FeepingCreature, 3 years ago)
  • Fixed cellular
Line 
1 module cellular;
2 import qd, std.stdio, std.string, tools.base;
3
4 const real K=1024, M=1024*K, G=1024*M, T=1024*G;
5
6 string fc(real what, string label) {
7   if (what>T) return format(1.0*what/T, "Tc", label);
8   if (what>G) return format(1.0*what/G, "Gc", label);
9   if (what>M) return format(1.0*what/M, "Mc", label);
10   if (what>K) return format(1.0*what/K, "Kc", label);
11   return format(what, "c", label);
12 }
13
14 import tools.array2d;
15
16 void swap(T)(ref T a, ref T b) { T x=a; a=b; b=x; }
17
18 size_t newline(string s) { size_t count; while (count<s.length && s[count]!='\n') ++count; return count;  }
19
20 /**
21  * transform a list of rules (CTRBLI, sorted) into a tree of if statements
22  * AT COMPILE TIME ... DUN DUN DUN
23  * NOTE:
24  *   gdc already optimizes the if tree.
25  *   no need to calculate the symmetries manually.
26 **/
27 string rules_transform(string _file) {
28   string res;
29   for (int symmetry=0; symmetry<4; ++symmetry) {
30     string sup, sright, sdown, sleft;
31     switch (symmetry) {
32       case 0: sup="up"; sright="right"; sdown="down"; sleft="left"; break;
33       case 1: sup="right"; sright="down"; sdown="left"; sleft="up"; break;
34       case 2: sup="down"; sright="left"; sdown="up"; sleft="right"; break;
35       case 3: sup="left"; sright="up"; sdown="right"; sleft="down"; break;
36       default: assert(false);
37     }
38     auto file=_file;
39     int cur_me=-1, cur_up, cur_right, cur_down, cur_left;
40     while (file.length) {
41       auto line=file[0..newline(file)];
42       file=file[newline(file)+1..$];
43       if (line[0]=='#') continue;
44       auto me=line[0]-'0', up=line[1]-'0', right=line[2]-'0',
45         down=line[3]-'0', left=line[4]-'0', to=line[5]-'0';
46       if (cur_me!=me) {
47         if (cur_me!=-1) res~="} } } } }";
48         cur_me=me; cur_up=up; cur_right=right; cur_down=down; cur_left=left;
49         res~="if (me=="~ctToString(me)~") {
50           if ("~sup~"=="~ctToString(up)~") {
51             if ("~sright~"=="~ctToString(right)~") {
52               if ("~sdown~"=="~ctToString(down)~") {
53                 if ("~sleft~"=="~ctToString(left)~") {
54                   return "~ctToString(to)~"; ";
55       } else {
56         if (cur_up!=up) {
57           cur_up=up; cur_right=right; cur_down=down; cur_left=left;
58           res~="} } } } if ("~sup~"=="~ctToString(up)~") {
59             if ("~sright~"=="~ctToString(right)~") {
60               if ("~sdown~"=="~ctToString(down)~") {
61                 if ("~sleft~"=="~ctToString(left)~") {
62                   return "~ctToString(to)~"; ";
63         } else {
64           if (cur_right!=right) {
65             cur_right=right; cur_down=down; cur_left=left;
66             res~="} } } if ("~sright~"=="~ctToString(right)~") {
67               if ("~sdown~"=="~ctToString(down)~") {
68                 if ("~sleft~"=="~ctToString(left)~") {
69                   return "~ctToString(to)~"; ";
70           } else {
71             if (cur_down!=down) {
72               cur_down=down; cur_left=left;
73               res~="} } if ("~sdown~"=="~ctToString(down)~") {
74                 if ("~sleft~"=="~ctToString(left)~") {
75                   return "~ctToString(to)~"; ";
76             } else {
77               if (cur_left!=left) {
78                 cur_left=left;
79                 res~="} if ("~sleft~"=="~ctToString(left)~") {
80                   return "~ctToString(to)~"; ";
81               } else assert(false, "Duplicate state");
82             }
83           }
84         }
85       }
86     }
87     res~="} } } } }";
88   }
89   return res;
90 }
91
92 import living_space;
93 final class ChouReggia : Space!(Neumann) {
94   this(int b, int o, bool w, int[][] s=null) { super(b, o, w, s); }
95   final ubyte eval(ubyte me, ubyte up, ubyte right, ubyte down, ubyte left) {
96     mixin(rules_transform(import("ChouReggia.r")));
97     return me;
98   }
99 }
100
101 final class Byl : Space!(Neumann) {
102   this(int b, int o, bool w, int[][] s=null) { super(b, o, w, s); }
103   final ubyte eval(ubyte me, ubyte up, ubyte right, ubyte down, ubyte left) {
104     mixin(rules_transform(import("byl.r")));
105     return me;
106   }
107 }
108
109 final class Evoloop : Space!(Neumann) {
110   this(int b, int o, bool w, int[][] s=null) { super(b, o, w, s); }
111   final ubyte eval(ubyte me, ubyte up, ubyte right, ubyte down, ubyte left) {
112     bool see(ubyte which) {
113       return (up == which || right == which || down == which || left == which);
114     }
115     mixin(rules_transform(import("evoloop.r")));
116     if (me==8) return 0;
117     if (see(8)) {
118       if ((me==0) || (me==1)) {
119         if (see(2) || see(3) || see(4) || see(5) || see(6) || see(7)) return 8;
120         else return me;
121       }
122       if ((me==2) || (me==3) || (me==5)) return 0;
123       if ((me==4) || (me==6) || (me==7)) return 1;
124     }
125     if (!me) return 0;
126     return 8;
127   }
128 }
129
130 ubyte urand(ubyte and=255) { return cast(ubyte)(rand()&and); }
131
132 import std.random;
133 final class Life : Space!(Moore) {
134   bool[] sustain, births;
135   this(int b, int o, bool w, int[] sust, int[] birth, int[][] s=null) {
136     sustain=new bool[9]; foreach (entry; sust) sustain[entry]=true;
137     births=new bool[9]; foreach (entry; birth) births[entry]=true;
138     super(b, o, w, s);
139     cols=[Black, White, Black~White~Black, White~Black~White];
140     if (!s) foreach (ref cell; state) cell=urand(1);
141   }
142   final ubyte eval(ubyte a, ubyte b, ubyte c, ubyte d, ubyte e, ubyte f, ubyte g, ubyte h, ubyte i) {
143     int sum=(a&1)+(b&1)+(c&1)
144            +(d&1)      +(f&1)
145            +(g&1)+(h&1)+(i&1);
146     if (e&1) {
147       if (sustain[sum]) return 3;
148       return 2;
149     } else {
150       if (births[sum]) return 1; // Any dead cell with exactly three live neighbours comes to life.
151       return 0;
152     }
153   }
154 }
155
156 template rule(int a, int b, int c, int d, int e, string WHUT) {
157   const string rule=Replace!("if (me==$a) {
158     if (
159       (($b==-1)?true:( up ==$b)) && (($c==-1)?true:( left ==$c)) && (($d==-1)?true:( down ==$d)) && (($e==-1)?true:( right ==$e)) ||
160       (($b==-1)?true:( left ==$b)) && (($c==-1)?true:( down ==$c)) && (($d==-1)?true:( right ==$d)) && (($e==-1)?true:( up ==$e)) ||
161       (($b==-1)?true:( down ==$b)) && (($c==-1)?true:( right ==$c)) && (($d==-1)?true:( up ==$d)) && (($e==-1)?true:( left ==$e)) ||
162       (($b==-1)?true:( right ==$b)) && (($c==-1)?true:( up ==$c)) && (($d==-1)?true:( left ==$d)) && (($e==-1)?true:( down ==$e))
163     ) $W;
164   }", "$a", ctToString(a), "$b", ctToString(b), "$c", ctToString(c), "$d", ctToString(d), "$e", ctToString(e), "$W", WHUT);
165 }
166
167 const string WireEval="
168   final ubyte eval(ubyte a, ubyte b, ubyte c, ubyte d, ubyte e, ubyte f, ubyte g, ubyte h, ubyte i) {
169     switch (e) {
170       case 0: return 0; break;
171       case 2: return 3; break;
172       case 3: return 1; break;
173       case 1:
174         ubyte heads;
175         if (a==2) ++heads; if (b==2) ++heads; if (c==2) ++heads;
176         if (d==2) ++heads;                    if (f==2) ++heads;
177         if (g==2) ++heads; if (h==2) ++heads; if (i==2) ++heads;
178         if ((heads==1) || (heads==2)) return 2;
179         return 1;
180         break;
181     }
182   }";
183 final class Wireworld : Space!(Moore, WireEval) {
184   this(int b, int o, int[][] s=null) { super(b, o, true, s); cols=[Black, Yellow, Blue~White~Blue, Red~White~Red]; }
185 }
186
187 import std.c.time, tools.functional;
188 static import std.file;
189
190 void main() {
191   screen(640, 960);
192   flip=false;
193   // cannot reproduce sexyloop
194   // ask authors?
195   auto g = new Evoloop(1, 0, true, (string text) {
196     auto lines = text.split("\n");
197     auto res = new int[][lines.length];
198     int maxlen;
199     foreach (line; lines) if (line.length > maxlen) maxlen = line.length;
200     foreach (i, line; lines) {
201       res[i] = new int[maxlen];
202       foreach (k, ch; line)
203         if (ch == ' ') res[i][k] = 0;
204         else res[i][k] = ch - '0';
205     }
206     return res;
207   }("
208      222222222222222
209     27017017017011115
210     21222222222222212
211     202           212
212     272           212
213     212           212
214     202           212
215     272           212
216     212           212
217     202           212
218     272           272
219     212           202    22222
220     202           212   2111112
221     272           272   2122212
222     21222222222222202   212 212
223     20710710710410412   212 272
224      222222222222222    2122202
225                         2111112
226                          22222
227      "));
228   /*auto g=new Life(2, 0, [2, 3], [3], [
229     [1,1,1,0,1],
230     [1,0,0,0,0],
231     [0,0,0,1,1],
232     [0,1,1,0,1],
233     [1,0,1,0,1]
234   ]);*/
235   /*auto g=new Life(4, 0, true, [2, 3], [3], [
236     "                        x           ",
237     "                      x x           ",
238     "            xx      xx            xx",
239     "           x   x    xx            x ",
240     "xx        x     x   xx              ",
241     "xx        x   x xx    x x           ",
242     "          x     x       x           ",
243     "           x   x                    ",
244     "            xx                      "
245   ] /map/ (string s) { return s /map/ ex!("f -> (f==' ')?0:1"); });*/
246   /*auto g=new Life(2, 0, true, [2, 3], [3], [
247     "  x ",
248     "   x",
249     " xxx"
250   ] /Map!("return $ /Map!(\"return ($==' ')?0:1\")"));*/
251   //auto g=new Life(2, 0, [2, 5], [3, 4]);
252   /*auto g=new Wireworld(4, 1, "
253    ->oooooooooooooooo                            oooooooo
254   o                  ooooooo                    oooooooo
255    ooooooooooooooo  o       o                  o
256                   o o       o             oo  o oooooooo
257    ooooooooooooooo  o       o            o  o o  oooooooo
258   o                 o       o            o ooo
259    ooooooooooooooooo       ooo           o  o
260                             o            ooo
261                            o oooooooooooo
262                            o o
263                           ooo
264                            o
265                            o
266    ->ooooo                 o
267   o       ooooooooooooooooo
268    ooooooo
269 ".split("\n") /Map!(" return $ /Map!(\"if (($=='>') || ($=='<')) return 2; if ($=='-') return 3; if ($=='o') return 1; return 0\")"));*/
270   /*auto wf=cast(char[])std.file.read("primes.wi");
271   //auto wf=cast(char[])std.file.read("test.wi");
272   screen(640, 960);
273   auto g=new Wireworld(1, 0, wf.split("\n") /map/ (string s) {
274     return s /map/ (char c) {
275       if (c=='~') return 3; else
276       if (c=='@') return 2; else
277       if (c=='#') return 1; else
278       return 0;
279     };
280   });*/
281   //auto g=new Byl(1, 0, true, [[0, 2, 2], [2, 3, 1, 2], [2, 3, 4, 2], [0, 2, 5]]);
282   //auto g=new Test(4, 1, true, [[1]]);
283   //auto g=new Life(5, 0, true, [0], [2], [[1, 1], [1, 1]]);
284   real sum=0; long secs, isum;
285   auto now=time(null); long ips;
286   bool fastmode=false, step=false, returnPressed=false;
287   int stepsize=1;
288   int delay=1;
289   bool mouseBtn[5];
290  
291   void changeStepsize(int n) { auto on=stepsize; stepsize=n; writefln("Stepsize: ", on, " -> ", n); }
292   void changeDelay(int n) { auto on=delay; delay=n; writefln("Delay: ", on, " -> ", n); }
293   void handleEvents() {
294     events((ushort key, bool pressed) {
295       if (!pressed) return;
296       switch (key) {
297         case 13: step=true; fastmode=false; break;
298         case ' ': fastmode=!fastmode; break;
299         case 93, 270: /*fastmode=true;*/ if (delay>1) changeDelay(delay/2); else changeStepsize(stepsize*2); break;
300         case 47, 269: /*fastmode=true;*/ if (stepsize>1) changeStepsize(stepsize/2); else changeDelay(delay*2); break;
301         default: break;
302       }
303     }, (int x, int y, ubyte button, int pressed) {
304       if (pressed==1) mouseBtn[button-1]=true;
305       if (pressed==-1) mouseBtn[button-1]=false;
306       if (mouseBtn[0]) {
307         x/=g.boxsize; y/=g.boxsize;
308         logln("State: ", g.state[x, y]);
309       }
310     });
311   }
312   ulong cps, iterations; bool worked;
313   while (true) {
314     if(now != time(null)) {
315       sum += cps;
316       if (worked) { worked = false; secs ++; }
317       isum += ips;
318       writefln(fc(cps, "ps"), ", avg ", fc(sum/secs, "ps"), "; ", iterations, " iterations done, ", ips, " iterations per second, ", 1f*isum / secs, " average");
319       now=time(null); ips=cps=0;
320     }
321     if (!(iterations&(stepsize-1))) {
322       g.render;
323       flip;
324       handleEvents;
325     }
326     if (fastmode || step) {
327       ++ips; ++iterations;
328       worked = true;
329       g.step;
330       cps ++;
331       step=false;
332     }
333     handleEvents;
334   }
335 }
Note: See TracBrowser for help on using the browser.