root/trunk/qd/gone.d

Revision 517, 7.4 kB (checked in by FeepingCreature, 3 years ago)
  • Seed by time, not hot
  • tools ini/ser update
  • QD stuff
Line 
1 import qd;
2 import std.stdio, std.math, std.stdio: format;
3 import tools.base;
4
5 bool even(int i) { return (i%2)==0; }
6 bool odd(int i) { return (i%2)!=0; }
7
8 bool has(T)(T[] array, T what) {
9   foreach (elem; array) if (elem==what) return true;
10   return false;
11 }
12
13 size_t count(T)(T[] array, T what) {
14   size_t res; foreach (elem; array) if (elem==what) res++;
15   return res;
16 }
17
18 void swap(T)(ref T a, ref T b) { T c=a; a=b; b=c; }
19
20 void merge(T)(ref T[] a, T[] b) { foreach (elem; b) if (!a.has(elem)) a~=elem; }
21
22 template Tuple(T...) { alias T Tuple; }
23
24 void swipe(T)(ref T target, T replacement, void delegate() dg) {
25   auto backup=target;
26   target=replacement;
27   scope(exit) target=backup;
28   dg();
29 }
30
31 class SuperGoBoard(C, C free) {
32   private C[] fields;
33   C turn;
34   this(C start) { turn=start; }
35   struct connects {
36     int[2] fields;
37     bool opIn_r(int id) {
38       foreach (field; fields) if (field==id) return true;
39       return false;
40     }
41     static connects opCall(int a, int b) { connects res=void; res.fields[]=[a, b]; return res; }
42   }
43   private connects[] conns;
44   private {
45     bool connected(int id1, int id2) {
46       foreach (conn; conns) if ((id1 in conn) && (id2 in conn)) return true;
47       return false;
48     }
49     void checkRange(int id) {
50       if (id<0 || id!<fields.length) throw new Exception("ID out of range");
51     }
52   }
53   SuperGoBoard deepdup() {
54     auto res=new SuperGoBoard(turn);
55     foreach (id, value; this.tupleof)
56       static if (is(typeof(value.dup))) res.tupleof[id]=value.dup;
57       else res.tupleof[id]=value;
58     res.conns=conns.dup;
59     return res;
60   }
61   C opIndex(int id) {
62     checkRange(id);
63     return fields[id];
64   }
65   void opIndexAssign(C col, int id) {
66     checkRange(id);
67     fields[id]=col;
68   }
69   int[] adj(int id) {
70     int[] res; for (int i=0; i<fields.length; ++i) if ((i!=id) && connected(i, id)) res~=i;
71     return res;
72   }
73   private void tryRemove(C exempt=free) {
74     auto processed=new bool[fields.length];
75     size_t current=0;
76     while (current<fields.length) {
77       while (current<fields.length && (processed[current]||fields[current]==free||fields[current]==exempt)) current++;
78       if (current==fields.length) break;
79       auto curGrp=group(current); scope(exit) foreach (entry; curGrp) processed[entry]=true;
80       if (!freedoms(curGrp)) foreach (entry; curGrp) fields[entry]=free;
81     }
82   }
83   void rule() {
84     tryRemove(turn);
85     tryRemove;
86   }
87   int[] adj(int[] ids) {
88     int[] res;
89     foreach (id; ids) res.merge(adj(id));
90     return res;
91   }
92   void connect(int a, int b) {
93     if (connected(a, b)) throw new Exception(format("Can't connect (", a, ", ", b, ") twice!"));
94     conns~=connects(a, b);
95   }
96   int[] group(int id) {
97     int[] res;
98     auto col=fields[id];
99     void recurse(int id) {
100       res~=id;
101       foreach (next; adj(id)) if ((fields[next]==col) && !res.has(next)) recurse(next);
102     }
103     recurse(id);
104     return res;
105   }
106   int freedoms(int[] ids) {
107     int res;
108     foreach (id; adj(ids)) if (fields[id]==free) res++;
109     return res;
110   }
111   bool canSet(int id, C col) {
112     checkRange(id);
113     if (fields[id]!=free) return false;
114     foreach (ac; adj(id)) if (fields[ac]==free) return true;
115     auto test=deepdup();
116     test.fields[id]=col;
117     test.rule;
118     return test.fields[id]==col;
119   }
120   int opCatAssign(C c) { fields~=c; return fields.length-1; }
121 }
122
123 enum Color { None, Black, White }
124
125 struct AnonStruct(string s) {
126   mixin(s);
127   static AnonStruct opCall(typeof(AnonStruct.tupleof) t) {
128     AnonStruct res=void;
129     foreach (id, value; t) res.tupleof[id]=value;
130     return res;
131   }
132 }
133
134 void drawDigit(int px, int py, ubyte digit) {
135   void draw(bool a, bool b, bool c, bool d, bool e, bool f, bool g) {
136     if (a) line(px-2, py-5, px+2, py-5);
137     if (b) line(px-2, py-5, px-2, py);
138     if (c) line(px+2, py-5, px+2, py);
139     if (d) line(px-2, py, px+2, py);
140     if (e) line(px-2, py, px-2, py+5);
141     if (f) line(px+2, py, px+2, py+5);
142     if (g) line(px+2, py+5, px-2, py+5);
143   }
144   const y=true;
145   const n=false;
146   switch (digit) {
147     case 0: draw(y, y, y, n, y, y, y); break;
148     case 1: draw(n, n, y, n, n, y, n); break;
149     case 2: draw(y, n, y, y, y, n, y); break;
150     case 3: draw(y, n, y, y, n, y, y); break;
151     case 4: draw(n, y, y, y, n, y, n); break;
152     case 5: draw(y, y, n, y, n, y, y); break;
153     case 6: draw(y, y, n, y, y, y, y); break;
154     case 7: draw(y, y, y, n, n, y, n); break;
155     case 8: draw(y, y, y, y, y, y, y); break;
156     case 9: draw(y, y, y, y, n, y, y); break;
157     default: break;
158   }
159 }
160
161 void drawNumber(int x, int y, int num) {
162   const width=7;
163   ubyte[] digits; do { digits~=num%10; num/=10; } while(num);
164   foreach (id, digit; digits) drawDigit(-id*width+x+(digits.length-1)*width/2, y, digit);
165 }
166
167 void main() {
168   int size=3;
169   screen(640, 480);
170   flip=false;
171   alias AnonStruct!("int x, y; ") vec2;
172   vec2[int] position;
173   auto board=new SuperGoBoard!(Color, Color.None)(Color.White);
174   int[int][int] columns;
175   const offs=0.5;
176   int width=cast(int)(screen.width/(size*2+1+offs));
177   int height=cast(int)(screen.height/(size*4+3));
178   for (int i=0; i<=size; i++) {
179     for (int dir=-1; dir<=1; dir+=2) {
180       auto cid=dir*(i+1);
181       writefln(even(i)?1:0);
182       for (int j=-size*2-1+i; j<=size*2+1-i; ++j) {
183         writefln("j = ", j);
184         //int offset=(screen.width/8)/(size+1);
185         int offset=cast(int)((width*offs)/4);
186         if (even(i) != even(j)) offset=-offset;
187         //if (odd(i)) offset=-offset;
188         auto newPos=board~=Color.None;
189         columns[cid][j]=newPos;
190         bool function(int) cond;
191         if (even(i)) cond=&odd;
192         else cond=&even;
193         if (i) {
194           if (cond(j)) board.connect(newPos, columns[dir*i][j]);
195           if (cond(j) && (j + 2) in columns[dir*i])
196             board.connect(newPos, columns[dir*i][j+2]);
197           // connect outsides
198           /*if (j==i-size-1) board.connect(newPos, columns[dir*i][j-1]);
199           if (j==size-i+1) board.connect(newPos, columns[dir*i][j+1]);*/
200         }
201         position[newPos]=vec2(screen.width/2+dir*(width/2+width*i+offset), screen.height/2+j*height);
202       }
203       writefln(columns[cid]);
204       foreach (id, entry; columns[cid]) if (id+1 in columns[cid]) board.connect(entry, columns[cid][id+1]);
205     }
206   }
207   bool function(int) cond;
208   foreach (id, entry; columns[1]) if (odd(id)) board.connect(entry, columns[-1][id]);
209   while(true) {
210     void delegate() click=null;
211     circle(20, 20, 10, Fill=(board.turn==Color.White)?White:Black, Red);
212     foreach (id, conn; board.conns) {
213       auto p1=position[conn.fields[0]];
214       auto p2=position[conn.fields[1]];
215       line(p1.x, p1.y, p2.x, p2.y);
216     }
217     foreach (id, color; board.fields) with (position[id]) {
218       auto fill=([Color.None: Blue, Color.Black: Black, Color.White: White][color]);
219       auto overlay=fill;
220       if (distance(x, y, mouse.x, mouse.y)<10) {
221         if (!board.canSet(id, board.turn)) overlay=Red;
222         else {
223           overlay=(board.turn==Color.Black?Black:White);
224           click=stuple(id, board) /apply/ (int id, typeof(board) board) {
225             with (board) if (canSet(id, turn)) {
226               board[id]=turn;
227               rule;
228               turn=(turn==Color.White)?Color.Black:Color.White;
229             }
230           };
231         }
232       }
233       fill=fill~(fill~overlay);
234       circle(x, y, 10, Red, Fill=fill);
235       if (board[id]) drawNumber(x, y, board.freedoms(board.group(id)));
236       // drawNumber(x, y, id);
237     }
238    
239     flip; events;
240     if (key.pressed(27)) return;
241     if (mouse.clicked(Button.Left) && click) click();
242   }
243 }
Note: See TracBrowser for help on using the browser.