root/06/libkombilo/search.cpp

Revision 253, 178.0 kB (checked in by ug, 1 year ago)

Fixed bug in search with wildcards.

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