root/06/libkombilo-branches/hash_center/search.cpp

Revision 249, 197.4 kB (checked in by ug, 1 year ago)

Merge -r 246:248 from libkombilo main branch.

Line 
1 // File: search.cpp
2 // part of libkombilo, http://www.u-go.net/kombilo/
3
4 // Copyright (c) 2006-7 Ulrich Goertz <u@g0ertz.de>
5
6 // Permission is hereby granted, free of charge, to any person obtaining a copy of
7 // this software and associated documentation files (the "Software"), to deal in
8 // the Software without restriction, including without limitation the rights to
9 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10 // of the Software, and to permit persons to whom the Software is furnished to do
11 // so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in all
14 // copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 // SOFTWARE.
23
24 #include "sgfparser.h"
25 #include "abstractboard.h"
26 #include "search.h"
27 #include <stdio.h>
28 #include <string>
29 #include <cstring>
30
31 using std::min;
32 using std::max;
33 using std::string;
34 using std::vector;
35 using std::map;
36 using std::pair;
37 using std::make_pair;
38 using std::stack;
39 using std::set;
40
41 #if defined(_MSC_VER)
42 #include <algorithm>
43 #else
44 using std::sort;
45 #endif
46
47 SnapshotVector::SnapshotVector() : vector<unsigned char>() {
48   current = begin();
49 }
50
51 SnapshotVector::SnapshotVector(char* c, int size) : vector<unsigned char>() {
52   for(int i=0; i<size; i++) push_back(c[i]);
53   current = begin();
54 }
55
56 void SnapshotVector::pb_int(int d) {
57   for(int i = 0; i < 4; i++) {
58     push_back((unsigned char)(d % 256));
59     d = d >> 8;
60   }
61 }
62
63 void SnapshotVector::pb_charp(char* c, int size) {
64   pb_int(size);
65   for(int i=0; i<size; i++) push_back(c[i]);
66 }
67
68 void SnapshotVector::pb_intp(int* p, int size) {
69   pb_int(size);
70   for(int i=0; i<size; i++) pb_int(p[i]);
71 }
72
73 void SnapshotVector::pb_string(string s) {
74   pb_int(s.size()+1);
75   for(unsigned int i=0; i<s.size(); i++) push_back(s[i]);
76   push_back(0);
77 }
78
79 void SnapshotVector::pb_char(char c) {
80   push_back(c);
81 }
82
83 int SnapshotVector::retrieve_int() {
84   int result = 0;
85   for(int i=0; i<4; i++) {
86     result += *current << (i*8);
87     current++;
88   }
89   return result;
90 }
91
92 int* SnapshotVector::retrieve_intp() {
93   int sz = retrieve_int();
94   int* result = new int[sz];
95   for(int i=0; i<sz; i++)
96     result[i] = retrieve_int();
97   return result;
98 }
99
100 char SnapshotVector::retrieve_char() {
101   char c = *current;
102   current++;
103   return c;
104 }
105
106 char* SnapshotVector::retrieve_charp() {
107   int sz = retrieve_int();
108   char* result = new char[sz];
109   for(int i=0; i<sz; i++) {
110     result[i] = *current;
111     current++;
112   }
113   return result;
114 }
115
116 string SnapshotVector::retrieve_string() {
117   char* cp = retrieve_charp();
118   string s(cp);
119   delete [] cp;
120   return s;
121 }
122
123 char* SnapshotVector::to_charp() {
124   char* result = new char[size()];
125   int counter = 0;
126   for(SnapshotVector::iterator it = begin(); it != end(); it++) result[counter++] = *it;
127   return result;
128 }
129
130
131 PatternError::PatternError() {}
132
133 Continuation::Continuation() {
134   B  = 0;
135   W  = 0;
136   tB = 0;
137   tW = 0;
138   wB = 0;
139   lB = 0;
140   wW = 0;
141   lW = 0;
142 }
143
144 void Continuation::from_snv(SnapshotVector& snv) {
145   B = snv.retrieve_int();
146   W = snv.retrieve_int();
147   tB = snv.retrieve_int();
148   tW = snv.retrieve_int();
149   wB = snv.retrieve_int();
150   lB = snv.retrieve_int();
151   wW = snv.retrieve_int();
152   lW = snv.retrieve_int();
153 }
154
155 void Continuation::to_snv(SnapshotVector& snv) {
156   snv.pb_int(B);
157   snv.pb_int(W);
158   snv.pb_int(tB);
159   snv.pb_int(tW);
160   snv.pb_int(wB);
161   snv.pb_int(lB);
162   snv.pb_int(wW);
163   snv.pb_int(lW);
164 }
165
166 Symmetries::Symmetries(char sX, char sY) {
167   sizeX = sX;
168   sizeY = sY;
169   dataX = new char[sizeX*sizeY];
170   dataY = new char[sizeX*sizeY];
171   dataCS = new char[sizeX*sizeY];
172   for(int i=0; i<sizeX*sizeY; i++) {
173     dataX[i] = -1;
174     dataY[i] = -1;
175     dataCS[i] = -1;
176   }
177 }
178
179 Symmetries::~Symmetries() {
180   delete [] dataX;
181   delete [] dataY;
182   delete [] dataCS;
183 }
184
185 Symmetries::Symmetries(const Symmetries& s) {
186   sizeX = s.sizeX;
187   sizeY = s.sizeY;
188   dataX = new char[sizeX*sizeY];
189   dataY = new char[sizeX*sizeY];
190   dataCS = new char[sizeX*sizeY];
191   for(int i=0; i<sizeX*sizeY; i++) {
192     dataX[i] = s.dataX[i];
193     dataY[i] = s.dataY[i];
194     dataCS[i] = s.dataCS[i];
195   }
196 }
197
198 Symmetries& Symmetries::operator=(const Symmetries& s) {
199   if (&s != this) {
200     sizeX = s.sizeX;
201     sizeY = s.sizeY;
202     delete [] dataX;
203     delete [] dataY;
204     delete [] dataCS;
205     dataX = new char[sizeX*sizeY];
206     dataY = new char[sizeX*sizeY];
207     dataCS = new char[sizeX*sizeY];
208     for(int i=0; i<sizeX*sizeY; i++) {
209       dataX[i] = s.dataX[i];
210       dataY[i] = s.dataY[i];
211       dataCS[i] = s.dataCS[i];
212     }
213   }
214   return *this;
215 }
216
217 void Symmetries::set(char i, char j, char k, char l, char cs) throw(PatternError) {
218   if (0 <= i && i < sizeX && 0 <= j && j < sizeY) {
219     dataX[i + j*sizeX] = k;
220     dataY[i + j*sizeX] = l;
221     dataCS[i + j*sizeX] = cs;
222   }
223   else throw PatternError();
224 }
225
226 char Symmetries::getX(char i, char j) throw(PatternError) {
227   if (0 <= i && i < sizeX && 0 <= j && j < sizeY) return dataX[i + j*sizeX];
228   else throw PatternError();
229   return -1;
230 }
231
232 char Symmetries::getY(char i, char j) throw(PatternError) {
233   if (0 <= i && i < sizeX && 0 <= j && j < sizeY) return dataY[i + j*sizeX];
234   else throw PatternError();
235   return -1;
236 }
237
238 char Symmetries::getCS(char i, char j) throw(PatternError) {
239   if (0 <= i && i < sizeX && 0 <= j && j < sizeY) return dataCS[i + j*sizeX];
240   else throw PatternError();
241   return -1;
242 }
243
244 char Symmetries::has_key(char i, char j) throw(PatternError) {
245   if (0 <= i && i < sizeX && 0 <= j && j < sizeY) {
246     if (dataX[i + j*sizeX] == -1) return 0;
247     else return 1;
248   }
249   else throw PatternError();
250   return 0;
251 }
252
253
254 // ----------- class Pattern -----------------------------------------------
255
256 char invertColor(char co) {
257   if (co == 'X') return 'O';
258   if (co == 'x') return 'o';
259
260   if (co == 'O') return 'X';
261   if (co == 'o') return 'x';
262
263   return co;
264 }
265
266 int Pattern::operator==(const Pattern& p) {
267   if (boardsize != p.boardsize) return 0;
268   if (sizeX != p.sizeX || sizeY != p.sizeY) return 0;
269   if (left != p.left || right != p.right || top != p.top || bottom != p.bottom) return 0;
270   for(int i=0; i < sizeX*sizeY; i++)
271     if (initialPos[i] != p.initialPos[i]) return 0;
272   if (contList != p.contList) return 0;
273   return 1;
274 }
275
276 char Pattern::BW2XO(char c) {
277   if (c == 'B') return 'X';
278   if (c == 'W') return 'O';
279   return c;
280 }
281
282 char Pattern::getInitial(int i, int j) {
283   return initialPos[i + sizeX*j];
284 }
285  
286 char Pattern::getFinal(int i, int j) {
287   return finalPos[i + sizeX*j];
288 }
289  
290 Pattern::Pattern() {
291   initialPos = 0;
292   finalPos = 0;
293   flip = 0;
294   colorSwitch = 0;
295   sizeX = 0;
296   sizeY = 0;
297   boardsize = 0;
298   contLabels = 0;
299 }
300
301 Pattern::Pattern(int type, int BOARDSIZE, int sX, int sY, char* iPos, char* CONTLABELS) {
302   flip = 0;
303   colorSwitch = 0;
304   sizeX = sX;
305   sizeY = sY;
306   boardsize = BOARDSIZE;
307   if (CONTLABELS) {
308     contLabels = new char[sizeX * sizeY];
309     for(int i=0; i<sizeX*sizeY; i++) contLabels[i] = CONTLABELS[i];
310   } else contLabels = 0;
311
312   if (type == CORNER_NW_PATTERN || type == FULLBOARD_PATTERN) {
313     left = right = top = bottom = 0;
314   } else if (type == CORNER_NE_PATTERN) {
315     top = bottom = 0;
316     left = right = boardsize - sizeX;
317   } else if (type == CORNER_SE_PATTERN) {
318     top = bottom = boardsize - sizeY;
319     left = right = boardsize - sizeX;
320   } else if (type == CORNER_SW_PATTERN) {
321     top = bottom = boardsize - sizeY;
322     left = right = 0;
323   } else if (type == SIDE_N_PATTERN) {
324     top = bottom = 0;
325     left = 1;
326     right = boardsize -1 - sizeX;
327   } else if (type == SIDE_E_PATTERN) {
328     left = right = boardsize - sizeX;
329     top = 1;
330     bottom = boardsize -1 - sizeY;
331   } else if (type == SIDE_W_PATTERN) {
332     left = right = 0;
333     top = 1;
334     bottom = boardsize -1 - sizeY;
335   } else if (type == SIDE_S_PATTERN) {
336     top = bottom = boardsize - sizeY;
337     left = 1;
338     right = boardsize -1 - sizeX;
339   } else if (type == CENTER_PATTERN) {
340     left = top = 1;
341     right = boardsize -1 - sizeX;
342     bottom = boardsize -1 - sizeY;
343   }
344
345   initialPos = new char[sizeX * sizeY];
346   finalPos = new char[sizeX*sizeY];
347   for(int i=0; i<sizeX*sizeY; i++) {
348     initialPos[i] = iPos[i];
349     finalPos[i] = iPos[i];
350   }
351 }
352
353 Pattern::Pattern(int type, int BOARDSIZE, int sX, int sY, char* iPos, vector<MoveNC> CONTLIST, char* CONTLABELS) {
354   flip = 0;
355   colorSwitch = 0;
356   sizeX = sX;
357   sizeY = sY;
358   boardsize = BOARDSIZE;
359   if (CONTLABELS) {
360     contLabels = new char[sizeX * sizeY];
361     for(int i=0; i<sizeX*sizeY; i++) contLabels[i] = CONTLABELS[i];
362   } else contLabels = 0;
363
364   if (type == CORNER_NW_PATTERN || type == FULLBOARD_PATTERN) {
365     left = right = top = bottom = 0;
366   } else if (type == CORNER_NE_PATTERN) {
367     top = bottom = 0;
368     left = right = boardsize - sizeX;
369   } else if (type == CORNER_SE_PATTERN) {
370     top = bottom = boardsize - sizeY;
371     left = right = boardsize - sizeX;
372   } else if (type == CORNER_SW_PATTERN) {
373     top = bottom = boardsize - sizeY;
374     left = right = 0;
375   } else if (type == SIDE_N_PATTERN) {
376     top = bottom = 0;
377     left = 1;
378     right = boardsize -1 - sizeX;
379   } else if (type == SIDE_E_PATTERN) {
380     left = right = boardsize - sizeX;
381     top = 1;
382     bottom = boardsize -1 - sizeY;
383   } else if (type == SIDE_W_PATTERN) {
384     left = right = 0;
385     top = 1;
386     bottom = boardsize -1 - sizeY;
387   } else if (type == SIDE_S_PATTERN) {
388     top = bottom = boardsize - sizeY;
389     left = 1;
390     right = boardsize -1 - sizeX;
391   } else if (type == CENTER_PATTERN) {
392     left = top = 1;
393     right = boardsize -1 - sizeX;
394     bottom = boardsize -1 - sizeY;
395   }
396
397   initialPos = new char[sizeX * sizeY];
398   finalPos = new char[sizeX*sizeY];
399   for(int i=0; i<sizeX*sizeY; i++) {
400     initialPos[i] = iPos[i];
401     finalPos[i] = iPos[i];
402   }
403
404   contList = CONTLIST;
405 }
406
407 Pattern::Pattern(int le, int ri, int to, int bo, int BOARDSIZE, int sX, int sY, char* iPos, const vector<MoveNC>& CONTLIST, char* CONTLABELS) throw(PatternError) {
408   // check whether anchor rectangle is valid
409   if ((le < 0) || ri+sX > BOARDSIZE || to < 0 || bo+sY > BOARDSIZE || ri < le || bo < to)
410     throw PatternError();
411
412   flip = 0;
413   colorSwitch = 0;
414
415   left = le;
416   right = ri;
417   top = to;
418   bottom = bo;
419   boardsize = BOARDSIZE;
420
421   sizeX = sX;
422   sizeY = sY;
423   if (CONTLABELS) {
424     contLabels = new char[sizeX * sizeY];
425     for(int i=0; i<sizeX*sizeY; i++) contLabels[i] = CONTLABELS[i];
426   } else contLabels = 0;
427
428   initialPos = new char[sizeX * sizeY];
429   finalPos = new char[sizeX*sizeY];
430   for(int i=0; i<sizeX*sizeY; i++) {
431     initialPos[i] = iPos[i];
432     finalPos[i] = iPos[i];
433   }
434
435   contList = CONTLIST;
436 }
437
438 Pattern::Pattern(SnapshotVector& snv) {
439   flip = snv.retrieve_int();
440   colorSwitch = snv.retrieve_int();
441   left = snv.retrieve_int();
442   right = snv.retrieve_int();
443   top = snv.retrieve_int();
444   bottom = snv.retrieve_int();
445   boardsize = snv.retrieve_int();
446   sizeX = snv.retrieve_int();
447   sizeY = snv.retrieve_int();
448   if (snv.retrieve_char()) { // contLabels?
449     contLabels = snv.retrieve_charp();
450   } else contLabels = 0;
451   initialPos = snv.retrieve_charp();
452   finalPos = snv.retrieve_charp();
453
454   int size = snv.retrieve_int();
455   for(int i=0; i<size; i++)
456     contList.push_back(MoveNC(snv.retrieve_char(), snv.retrieve_char(), snv.retrieve_char())); // x, y, color
457 }
458
459 void Pattern::to_snv(SnapshotVector& snv) {
460   snv.pb_int(flip);
461   snv.pb_int(colorSwitch);
462   snv.pb_int(left);
463   snv.pb_int(right);
464   snv.pb_int(top);
465   snv.pb_int(bottom);
466   snv.pb_int(boardsize);
467   snv.pb_int(sizeX);
468   snv.pb_int(sizeY);
469   if (contLabels) {
470     snv.pb_char(1);
471     snv.pb_charp(contLabels, sizeX*sizeY);
472   } else snv.pb_char(0);
473   snv.pb_charp(initialPos, sizeX*sizeY);
474   snv.pb_charp(finalPos, sizeX*sizeY);
475   snv.pb_int(contList.size());
476   for(vector<MoveNC>::iterator it = contList.begin(); it != contList.end(); it++) {
477     snv.pb_char(it->x);
478     snv.pb_char(it->y);
479     snv.pb_char(it->color);
480   }
481 }
482
483 Pattern::~Pattern() {
484   if (initialPos) delete [] initialPos;
485   if (finalPos) delete [] finalPos;
486   if (contLabels) delete [] contLabels;
487 }
488
489 Pattern::Pattern(const Pattern& p) {
490   left = p.left;
491   right = p.right;
492   top = p.top;
493   bottom = p.bottom;
494   boardsize = p.boardsize;
495   sizeX = p.sizeX;
496   sizeY = p.sizeY;
497   flip = p.flip;
498   colorSwitch = p.colorSwitch;
499
500   initialPos = new char[sizeX*sizeY];
501   finalPos = new char[sizeX*sizeY];
502   if (p.contLabels) contLabels = new char[sizeX*sizeY];
503   else contLabels = 0;
504   for(int i=0; i<sizeX*sizeY; i++) {
505     initialPos[i] = p.initialPos[i];
506     finalPos[i] = p.finalPos[i];
507     if (p.contLabels) contLabels[i] = p.contLabels[i];
508   }
509   contList = p.contList;
510 }
511
512 Pattern& Pattern::operator=(const Pattern& p) {
513   if (&p != this) {
514     left = p.left;
515     right = p.right;
516     top = p.top;
517     bottom = p.bottom;
518     boardsize = p.boardsize;
519     sizeX = p.sizeX;
520     sizeY = p.sizeY;
521     flip = p.flip;
522     colorSwitch = p.colorSwitch;
523
524     if (initialPos) delete [] initialPos;
525     if (finalPos) delete [] finalPos;
526     if (contLabels) delete [] contLabels;
527
528     initialPos = new char[sizeX*sizeY];
529     finalPos = new char[sizeX*sizeY];
530     if (p.contLabels) contLabels = new char[sizeX*sizeY];
531     else contLabels = 0;
532     for(int i=0; i<sizeX*sizeY; i++) {
533       initialPos[i] = p.initialPos[i];
534       finalPos[i] = p.finalPos[i];
535       if (p.contLabels) contLabels[i] = p.contLabels[i];
536     }
537     contList = p.contList;
538   }
539   return *this;
540 }
541
542 Pattern& Pattern::copy(const Pattern& p) {
543   if (&p != this) {
544     left = p.left;
545     right = p.right;
546     top = p.top;
547     bottom = p.bottom;
548     boardsize = p.boardsize;
549     sizeX = p.sizeX;
550     sizeY = p.sizeY;
551     flip = p.flip;
552     colorSwitch = p.colorSwitch;
553
554     if (initialPos) delete [] initialPos;
555     if (finalPos) delete [] finalPos;
556
557     initialPos = new char[sizeX*sizeY];
558     finalPos = new char[sizeX*sizeY];
559     if (p.contLabels) contLabels = new char[sizeX*sizeY];
560     else contLabels = 0;
561     for(int i=0; i<sizeX*sizeY; i++) {
562       initialPos[i] = p.initialPos[i];
563       finalPos[i] = p.finalPos[i];
564       if (p.contLabels) contLabels[i] = p.contLabels[i];
565     }
566     contList = p.contList;
567   }
568   return *this;
569 }
570
571 Pattern Pattern::apply_flip(int f, bool CS) {
572   int newSizeX = max(Pattern::flipsX(f,0,0,sizeX,sizeY),
573       Pattern::flipsX(f,sizeX,sizeY,sizeX,sizeY));
574   int newSizeY = max(Pattern::flipsY(f,0,0,sizeX,sizeY),
575       Pattern::flipsY(f,sizeX,sizeY,sizeX,sizeY));
576
577   int newLeft = min(Pattern::flipsX(f,left,top,boardsize-1,boardsize-1),
578       Pattern::flipsX(f,right+sizeX-1,bottom+sizeY-1,
579         boardsize-1,boardsize-1));
580   int newRight = max(Pattern::flipsX(f,left,top,boardsize-1,boardsize-1),
581       Pattern::flipsX(f,right+sizeX-1,bottom+sizeY-1,
582         boardsize-1,boardsize-1)) - (newSizeX-1);
583   int newTop = min(Pattern::flipsY(f,left,top,boardsize-1,boardsize-1),
584       Pattern::flipsY(f,right+sizeX-1,bottom+sizeY-1,
585         boardsize-1,boardsize-1));
586   int newBottom = max(Pattern::flipsY(f,left,top,boardsize-1,boardsize-1),
587       Pattern::flipsY(f,right+sizeX-1,bottom+sizeY-1,
588         boardsize-1,boardsize-1)) - (newSizeY - 1);
589
590   // printf("%d, %d, %d, %d, %d, %d, %d\n", f, newSizeX, newSizeY, newLeft, newRight, newTop, newBottom);
591   char* newInitialPos = new char[sizeX*sizeY];
592   int i=0;
593   for(i=0; i<sizeX; i++) {
594     for(int j=0; j<sizeY; j++) {
595       if (!CS)
596         newInitialPos[Pattern::flipsX(f,i,j,sizeX-1,sizeY-1) + \
597           newSizeX*Pattern::flipsY(f,i,j,sizeX-1,sizeY-1)] = getInitial(i, j);
598       else
599         newInitialPos[Pattern::flipsX(f,i,j,sizeX-1,sizeY-1) + \
600           newSizeX*Pattern::flipsY(f,i,j,sizeX-1,sizeY-1)] =
601           invertColor(getInitial(i, j));
602     }
603   }
604
605   vector<MoveNC> newContList;
606   for(i=0; (unsigned int)i<contList.size(); i++) {
607     if (!CS)
608       newContList.push_back(MoveNC(Pattern::flipsX(f, contList[i].x, contList[i].y,
609               sizeX-1,sizeY-1),
610             Pattern::flipsY(f, contList[i].x, contList[i].y,
611               sizeX-1,sizeY-1),
612             contList[i].color));
613     else
614       newContList.push_back(MoveNC(Pattern::flipsX(f, contList[i].x, contList[i].y,
615               sizeX-1,sizeY-1),
616             Pattern::flipsY(f, contList[i].x, contList[i].y,
617               sizeX-1,sizeY-1),
618             invertColor(contList[i].color)));
619   }
620
621   Pattern pNew(newLeft, newRight, newTop, newBottom, boardsize,
622                newSizeX, newSizeY, newInitialPos, newContList);
623
624   pNew.flip = f;
625   if (CS) pNew.colorSwitch = 1;
626   else pNew.colorSwitch = 0;
627   delete [] newInitialPos;
628   return pNew;
629 }
630
631 Pattern& Pattern::subpattern(int offsetX, int offsetY, int SIZEX, int SIZEY) {
632   int newLeft = left + offsetX;
633   int newRight = right + offsetX;
634   int newTop = top + offsetY;
635   int newBottom = bottom + offsetY;
636
637   char* newInitialPos = new char[SIZEX*SIZEY];
638   int i=0;
639   for(i=0; i<SIZEX; i++) {
640     for(int j=0; j<SIZEY; j++) {
641       newInitialPos[i + SIZEX*j] = getInitial(i+offsetX, j+offsetY);
642     }
643   }
644
645   vector<MoveNC> newContList;
646   for(i=0; (unsigned int)i<contList.size(); i++) {
647     newContList.push_back(MoveNC(contList[i].x-offsetX, contList[i].y-offsetY, contList[i].color));
648   }
649
650   Pattern* pNew =new Pattern(newLeft, newRight, newTop, newBottom, boardsize, SIZEX, SIZEY,
651       newInitialPos, newContList);
652
653   pNew->flip = flip;
654   pNew->colorSwitch = colorSwitch;
655   delete [] newInitialPos;
656   return *pNew;
657 }
658
659 string Pattern::printPattern() {
660   string result;
661   char buf[100];
662   sprintf(buf, "boardsize: %d, area: %d, %d, %d, %d\nsize: %d, %d\n", boardsize, left, right, top, bottom, sizeX, sizeY);
663   result += buf;
664   for(int i=0; i<sizeY; i++) {
665     for(int j=0; j<sizeX; j++) {
666       if (initialPos[i*sizeX + j] == 'X' || initialPos[i*sizeX + j] == 'O' || initialPos[i*sizeX + j] == 'x' || initialPos[i*sizeX + j] == 'x' || initialPos[i*sizeX+j] == '*') result += initialPos[i*sizeX+j];
667       else result += '.';
668     }
669     result += "\n";
670   }
671   result += "\n";
672   return result;
673 }
674
675 int Pattern::flipsX(int i, int x, int y, int XX, int YY) {
676   if (i==0) return x;         // id
677   if (i==1) return XX-x;      // mirror vertically
678   if (i==2) return x;         // mirror horizontally
679   if (i==3) return XX-x;      // rotate by 180 deg
680   if (i==4) return y;         // mirror wrt main diagonal (\)
681   if (i==5) return YY-y;      // rotate by -90 deg
682   if (i==6) return y;         // rotate by 90 deg
683   if (i==7) return YY-y;      // mirror wrt second diagonal (/)
684   return -1;
685 }
686
687 int Pattern::flipsY(int i, int x, int y, int XX, int YY) {
688   if (i==0) return y;
689   if (i==1) return y;
690   if (i==2) return YY-y;
691   if (i==3) return YY-y;
692   if (i==4) return x;
693   if (i==5) return x;
694   if (i==6) return XX-x;
695   if (i==7) return XX-x;
696   return -1;
697 }
698
699 int Pattern::PatternInvFlip(int i) {
700   if (i == 5) return 6;
701   if (i == 6) return 5;
702   return i;
703 }
704
705 const int composition_table[] = {
706   0, 1, 2, 3, 4, 5, 6, 7,
707   1, 0, 3, 2, 5, 4, 7, 6,
708   2, 3, 0, 1, 6, 7, 4, 5,
709   3, 2, 1, 0, 7, 6, 5, 4,
710   4, 6, 5, 7, 0, 2, 1, 3,
711   5, 7, 4, 6, 1, 3, 0, 2,
712   6, 4, 7, 5, 2, 0, 3, 1,
713   7, 5, 6, 4, 3, 1, 2, 0 };
714
715 int Pattern::compose_flips(int i, int j) {
716   return composition_table[j+8*i];
717 }
718
719
720 PatternList::PatternList(Pattern& p, int fColor, int nMove) throw(PatternError) {
721   pattern = p;
722   fixedColor = fColor;
723   nextMove = nMove;
724   special = -1;
725   flipTable = new int[16];
726   for(int i=0; i<16; i++) flipTable[i] = -1; // (patternList() relies on this)
727
728   patternList();
729   continuations = new Continuation[pattern.sizeX * pattern.sizeY];
730 }
731
732 PatternList::~PatternList() {
733   delete [] continuations;
734   delete [] flipTable;
735 }
736
737 void PatternList::patternList() {
738   vector<Pattern> lCS;
739   vector<pair<int,int> > sy;
740
741   for(int f = 0; f < 8; f++) {
742     Pattern pNew = pattern.apply_flip(f);
743
744     vector<Pattern>::iterator it;
745     bool foundNewPattern = true;
746     for(it = data.begin(); it != data.end(); it++) {
747       if (pNew == *it) {
748         foundNewPattern = false;
749         flipTable[f] = flipTable[it->flip];
750         break;
751       }
752     }
753     if (foundNewPattern) {
754 //       printf("new p: %s\n", pNew.printPattern().c_str());
755       flipTable[f] = data.size();
756       data.push_back(pNew);
757     }
758
759     if (pNew == pattern) sy.push_back(pair<int,int>(f,0));
760
761     if (nextMove || !fixedColor) { // need to consider CS'ed patterns
762       Pattern pNew1 = pattern.apply_flip(f, true);
763
764       if (!fixedColor) {
765         // need to add CS'ed pattern to patternList
766         // (if fixedColor==1 (but also nextMove!=0), we only need the CS'ed patterns to deal with
767         // continuations/the "symmetries" data
768         bool foundNewPattern = true;
769         int lCS_ctr = 0;
770         for(vector<Pattern>::iterator it = lCS.begin(); it != lCS.end(); it++) {
771           if (pNew1 == *it) {
772             foundNewPattern = false;
773             flipTable[f+8] = lCS_ctr;
774             break;
775           }
776           lCS_ctr++;
777         }
778         if (foundNewPattern) {
779           lCS.push_back(pNew1);
780         }
781       }
782
783       if (pNew1 == pattern) {
784         if (!fixedColor) sy.push_back(pair<int,int>(f,1));
785         if (nextMove) special = Pattern::PatternInvFlip(f);
786       }
787     }
788   }
789
790   // add the new CS'ed patterns to data, and update flipTable
791   int lCS_ctr = 0;
792   for(vector<Pattern>::iterator it = lCS.begin(); it != lCS.end(); it++) {
793     bool contained_in_l = false;
794     for(vector<Pattern>::iterator it_l = data.begin(); it_l != data.end(); it_l++)
795       if (*it == *it_l) {
796         contained_in_l = true;
797         flipTable[8+it->flip] = flipTable[it_l->flip];
798         break;
799       }
800     if (!contained_in_l) {
801       flipTable[8+it->flip] = data.size();
802       data.push_back(*it);
803     }
804     for(int ii=it->flip+1; ii<8; ii++)
805       if (flipTable[8+ii] == lCS_ctr) flipTable[8+ii] = flipTable[8+it->flip];
806     lCS_ctr++;
807   }
808
809   // compute the "symmetries"
810   Symmetries symm(pattern.sizeX, pattern.sizeY);
811   for(int i=0; i<symm.sizeX; i++)
812     for(int j=0; j<symm.sizeY; j++)
813       symm.set(i,j, i,j,0);
814
815   for(vector<pair<int,int> >::iterator it_s=sy.begin(); it_s!=sy.end(); it_s++) {
816     int s = it_s->first;
817     int newSizeX = max(Pattern::flipsX(s,0,0,pattern.sizeX,pattern.sizeY),
818                        Pattern::flipsX(s,pattern.sizeX,pattern.sizeY,pattern.sizeX,pattern.sizeY));
819     int newSizeY = max(Pattern::flipsY(s,0,0,pattern.sizeX,pattern.sizeY),
820                        Pattern::flipsY(s,pattern.sizeX,pattern.sizeY,pattern.sizeX,pattern.sizeY));
821     int c = it_s->second;
822     Symmetries symm1(newSizeX, newSizeY);
823
824     for(int i=0; i < pattern.sizeX; i++) {
825       for(int j=0; j < pattern.sizeY; j++) {
826         int fX = Pattern::flipsX(s, i, j, pattern.sizeX-1, pattern.sizeY-1);
827         int fY = Pattern::flipsY(s, i, j, pattern.sizeX-1, pattern.sizeY-1);
828         if ((i != fX || j != fY) && !symm1.has_key(fX, fY))
829           symm1.set(i,j, fX, fY, c);
830       }
831     }
832
833     {
834       int cs;
835       for(int i=0; i<symm.sizeX; i++)
836         for(int j=0; j<symm.sizeY; j++)
837           if (symm1.has_key(symm.getX(i,j), symm.getY(i,j))) {
838             if ((symm1.getCS(symm.getX(i,j),symm.getY(i,j)) || symm.getCS(i,j)) &&
839                 !(symm1.getCS(symm.getX(i,j),symm.getY(i,j)) && symm.getCS(i,j)))
840               cs = 1;
841             else cs = 0;
842             symm.set(i,j,symm1.getX(symm.getX(i,j),symm.getY(i,j)),
843                 symm1.getY(symm.getX(i,j),symm.getY(i,j)), cs);
844           }
845     }
846   }
847
848   symmetries.push_back(symm);
849   {
850     vector<Pattern>::iterator it = data.begin();
851     it++;
852     for(; it != data.end(); it++) {
853       // printf("ne %d, %d\n", it->sizeX, it->sizeY);
854       int f = it->flip;
855       Symmetries s(it->sizeX, it->sizeY);
856       for(int i=0; i<pattern.sizeX; i++) {
857         for(int j=0; j<pattern.sizeY; j++) {
858           if (!it->colorSwitch) {
859             s.set(Pattern::flipsX(f,i,j,pattern.sizeX-1,pattern.sizeY-1),
860                 Pattern::flipsY(f,i,j,pattern.sizeX-1,pattern.sizeY-1),
861                 symm.getX(i,j), symm.getY(i,j), symm.getCS(i,j));
862           } else {
863             s.set(Pattern::flipsX(f,i,j,pattern.sizeX-1,pattern.sizeY-1),
864                 Pattern::flipsY(f,i,j,pattern.sizeX-1,pattern.sizeY-1),
865                 symm.getX(i,j), symm.getY(i,j), 1-symm.getCS(i,j));
866           }
867         }
868       }
869       symmetries.push_back(s);
870     }
871   }
872 }
873
874 Pattern PatternList::get(int i) {
875   return data[i];
876 }
877
878 int PatternList::size() {
879   return data.size();
880 }
881
882 char* PatternList::updateContinuations(int index, int x, int y, char co, bool tenuki, char winner) {
883   char xx;
884   char yy;
885   char cSymm;
886   char cc;
887   xx = symmetries[index].getX(x,y);
888   yy = symmetries[index].getY(x,y);
889   cSymm = symmetries[index].getCS(x,y);
890   if (co == 'X' || co == 'B') {
891     if (cSymm) cc = 'W'; else cc = 'B';
892   } else {
893     if (cSymm) cc = 'B'; else cc = 'W';
894   }
895
896   if ((nextMove == 1 && cc == 'W') || (nextMove == 2 && cc == 'B')) {
897     if (special != -1) {
898       char xx1 = xx;
899       // printf("s1 xx %d, yy %d sp %d\n", xx, yy, special);
900       xx = Pattern::flipsX(special, xx, yy, pattern.sizeX-1, pattern.sizeY-1);
901       yy = Pattern::flipsY(special, xx1, yy, pattern.sizeX-1, pattern.sizeY-1);
902       // printf("s2 xx %d, yy %d\n", xx, yy);
903       if (cc == 'B') cc = 'W';
904       else cc = 'B';
905       cSymm = 1-cSymm;
906     } else {
907       return 0;
908     }
909   }
910
911   if (cc == 'B') {
912     continuations[xx + pattern.sizeX*yy].B++;
913     if (tenuki) continuations[xx + pattern.sizeX*yy].tB++;
914     if ((winner == 'B' && !cSymm) || (winner == 'W' && cSymm)) continuations[xx + pattern.sizeX*yy].wB++;
915     else if ((winner == 'W' && !cSymm) || (winner == 'B' && cSymm)) continuations[xx + pattern.sizeX*yy].lB++;
916   } else {
917     // printf("xx %d, yy %d\n", xx, yy);
918     continuations[xx + pattern.sizeX*yy].W++;
919     if (tenuki) continuations[xx + pattern.sizeX*yy].tW++;
920     if ((winner == 'B' && !cSymm) || (winner == 'W' && cSymm)) continuations[xx + pattern.sizeX*yy].wW++;
921     else if ((winner == 'W' && !cSymm) || (winner ='B' && cSymm)) continuations[xx + pattern.sizeX*yy].lW++;
922   }
923   char* result = new char[3];
924   result[0] = xx;
925   result[1] = yy;
926   result[2] = cSymm;
927   return result;
928 }
929
930 char* PatternList::sortContinuations() {
931   char* labels = new char[pattern.sizeX*pattern.sizeY+1];
932   labels[pattern.sizeX * pattern.sizeY] = 0; // so we can just printf the labels as a string
933   for(int i=0; i<pattern.sizeX*pattern.sizeY; i++) {
934     if (continuations[i].B || continuations[i].W) labels[i] = '?'; // need to assign label
935     else labels[i] = '.';
936   }
937   string labelList = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
938   unsigned int labelIndex = 0;
939
940   // assign labels which are in the contLabels array passed to the original pattern
941   // (these will usually be labels "already present in the SGF file")
942  
943   if (pattern.contLabels) {
944     for(int i=0; i<pattern.sizeX*pattern.sizeY; i++) {
945       if (pattern.contLabels[i] != '.') {
946         labels[i] = pattern.contLabels[i];
947         unsigned int j = labelList.find(pattern.contLabels[i]);
948         if (j != string::npos) labelList.erase(j,1);
949       }
950     }
951   }
952
953   // now give labels to the remaining points, starting with the one with
954   // most hits
955  
956   int max_hits = 0;
957   int max_hits_index = 0;
958   while (max_hits != -1 && labelIndex < labelList.size()) {