| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
#include <Python.h> |
|---|
| 24 |
|
|---|
| 25 |
void invert(char *s) { |
|---|
| 26 |
int c,i,j; |
|---|
| 27 |
for (i=0,j=strlen(s)-1;i<j;i++,j--) { |
|---|
| 28 |
c=s[i]; |
|---|
| 29 |
s[i]=s[j]; |
|---|
| 30 |
s[j]=c; |
|---|
| 31 |
} |
|---|
| 32 |
} |
|---|
| 33 |
|
|---|
| 34 |
char* itoa(int n) { |
|---|
| 35 |
char *s = new char[15]; |
|---|
| 36 |
int i; |
|---|
| 37 |
|
|---|
| 38 |
i=0; |
|---|
| 39 |
do { s[i++] = n%10+'0'; |
|---|
| 40 |
} while ((n/=10)>0); |
|---|
| 41 |
|
|---|
| 42 |
s[i]='\0'; |
|---|
| 43 |
invert(s); |
|---|
| 44 |
return s; |
|---|
| 45 |
} |
|---|
| 46 |
|
|---|
| 47 |
|
|---|
| 48 |
bool greater(long* a, unsigned long i, unsigned long j) { |
|---|
| 49 |
if (a[2*i]>a[2*j] || (a[2*i]==a[2*j] && a[2*i+1]>a[2*j+1])) return true; |
|---|
| 50 |
return false; |
|---|
| 51 |
} |
|---|
| 52 |
|
|---|
| 53 |
void swap(long* a, unsigned long i, unsigned long j) { |
|---|
| 54 |
long help1, help2; |
|---|
| 55 |
|
|---|
| 56 |
help1 = a[2*i]; |
|---|
| 57 |
help2 = a[2*i+1]; |
|---|
| 58 |
a[2*i] = a[2*j]; |
|---|
| 59 |
a[2*i+1] = a[2*j+1]; |
|---|
| 60 |
a[2*j] = help1; |
|---|
| 61 |
a[2*j+1] = help2; |
|---|
| 62 |
} |
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 |
void sortCArray(long* a, long l, long r) { |
|---|
| 66 |
|
|---|
| 67 |
long left, right, li11; |
|---|
| 68 |
|
|---|
| 69 |
long stack[250]; |
|---|
| 70 |
stack[0] = l; |
|---|
| 71 |
stack[1] = r; |
|---|
| 72 |
unsigned char stackIndex = 1; |
|---|
| 73 |
|
|---|
| 74 |
long help1, help2; |
|---|
| 75 |
|
|---|
| 76 |
while (stackIndex) { |
|---|
| 77 |
if (r > l) { |
|---|
| 78 |
if (r-l == 1) { |
|---|
| 79 |
if (greater(a, l, r)) swap(a, l, r); |
|---|
| 80 |
|
|---|
| 81 |
stackIndex--; |
|---|
| 82 |
l = stack[2*stackIndex]; |
|---|
| 83 |
r = stack[2*stackIndex+1]; |
|---|
| 84 |
|
|---|
| 85 |
} else { |
|---|
| 86 |
|
|---|
| 87 |
if (greater(a, (r+l)/2, l)) { |
|---|
| 88 |
if (greater(a, l, r)) li11 = l; |
|---|
| 89 |
else { |
|---|
| 90 |
if (greater(a, r, (r+l)/2)) li11 = (r+l)/2; |
|---|
| 91 |
else li11 = r; |
|---|
| 92 |
} |
|---|
| 93 |
} else { |
|---|
| 94 |
if (greater(a, (r+l)/2, r)) li11 = (r+l)/2; |
|---|
| 95 |
else { |
|---|
| 96 |
if (greater(a, r, l)) li11 = l; |
|---|
| 97 |
else li11 = r; |
|---|
| 98 |
} |
|---|
| 99 |
} |
|---|
| 100 |
|
|---|
| 101 |
swap(a, li11, r); |
|---|
| 102 |
help1 = a[2*r]; |
|---|
| 103 |
help2 = a[2*r+1]; |
|---|
| 104 |
|
|---|
| 105 |
left = l; |
|---|
| 106 |
right = r-1; |
|---|
| 107 |
|
|---|
| 108 |
while (1) { |
|---|
| 109 |
while (a[2*left] < help1 || (a[2*left]==help1 && a[2*left+1]<help2)) left++; |
|---|
| 110 |
while (a[2*right] > help1 || (a[2*right]==help1 && a[2*right+1]>help2)) right--; |
|---|
| 111 |
|
|---|
| 112 |
if (right <= left) break; |
|---|
| 113 |
|
|---|
| 114 |
swap(a, left, right); |
|---|
| 115 |
|
|---|
| 116 |
left++; |
|---|
| 117 |
right--; |
|---|
| 118 |
} |
|---|
| 119 |
|
|---|
| 120 |
swap(a, left, r); |
|---|
| 121 |
|
|---|
| 122 |
if (left-l > r-left) { |
|---|
| 123 |
stack[2*stackIndex] = l; |
|---|
| 124 |
stack[2*stackIndex+1] = left-1; |
|---|
| 125 |
stackIndex++; |
|---|
| 126 |
l = left+1; |
|---|
| 127 |
} else { |
|---|
| 128 |
stack[2*stackIndex] = left+1; |
|---|
| 129 |
stack[2*stackIndex+1] = r; |
|---|
| 130 |
stackIndex++; |
|---|
| 131 |
r = left-1; |
|---|
| 132 |
} |
|---|
| 133 |
} |
|---|
| 134 |
} else { |
|---|
| 135 |
stackIndex--; |
|---|
| 136 |
l = stack[2*stackIndex]; |
|---|
| 137 |
r = stack[2*stackIndex+1]; |
|---|
| 138 |
} |
|---|
| 139 |
} |
|---|
| 140 |
} |
|---|
| 141 |
|
|---|
| 142 |
static const int COLORSWITCH = 1024; |
|---|
| 143 |
|
|---|
| 144 |
static char flipX(char flipNO, char x, char y) { |
|---|
| 145 |
if (flipNO==0) return x; |
|---|
| 146 |
if (flipNO==1) return 18-x; |
|---|
| 147 |
if (flipNO==2) return x; |
|---|
| 148 |
if (flipNO==3) return 18-x; |
|---|
| 149 |
if (flipNO==4) return y; |
|---|
| 150 |
if (flipNO==5) return 18-y; |
|---|
| 151 |
if (flipNO==6) return y; |
|---|
| 152 |
if (flipNO==7) return 18-y; |
|---|
| 153 |
return 0; |
|---|
| 154 |
} |
|---|
| 155 |
|
|---|
| 156 |
static char flipY(char flipNO, char x, char y) { |
|---|
| 157 |
if (flipNO==0) return y; |
|---|
| 158 |
if (flipNO==1) return y; |
|---|
| 159 |
if (flipNO==2) return 18-y; |
|---|
| 160 |
if (flipNO==3) return 18-y; |
|---|
| 161 |
if (flipNO==4) return x; |
|---|
| 162 |
if (flipNO==5) return x; |
|---|
| 163 |
if (flipNO==6) return 18-x; |
|---|
| 164 |
if (flipNO==7) return 18-x; |
|---|
| 165 |
return 0; |
|---|
| 166 |
} |
|---|
| 167 |
|
|---|
| 168 |
static PyObject* match(PyObject* self, PyObject* args) { |
|---|
| 169 |
int noPatterns; |
|---|
| 170 |
char *Patterns; |
|---|
| 171 |
char *PSize; |
|---|
| 172 |
char *PInvFlips; |
|---|
| 173 |
char *PColorSwitch; |
|---|
| 174 |
char *PAnchors; |
|---|
| 175 |
unsigned long *PBitsTable; |
|---|
| 176 |
unsigned char *PBits; |
|---|
| 177 |
unsigned char *fp; |
|---|
| 178 |
unsigned char *mainlist; |
|---|
| 179 |
unsigned long *posTable; |
|---|
| 180 |
|
|---|
| 181 |
unsigned long *hashIndices; |
|---|
| 182 |
unsigned char *hash; |
|---|
| 183 |
|
|---|
| 184 |
char* contLabels; |
|---|
| 185 |
|
|---|
| 186 |
int PCSlength, PAlength, PBTlength, PBlength, fplength, MLlength, PTlength, HLlength, |
|---|
| 187 |
hashIlength, hashlength, contLabelsLength, contLabelsIndex, |
|---|
| 188 |
showColorSwitch, nextMoveVar, fixedColorVar; |
|---|
| 189 |
int moveLimit; |
|---|
| 190 |
unsigned long* helplist; |
|---|
| 191 |
|
|---|
| 192 |
PyObject *progBarUpdate; |
|---|
| 193 |
PyObject *continuations; |
|---|
| 194 |
PyObject *symmetries; |
|---|
| 195 |
PyObject *dbData; |
|---|
| 196 |
float pB_start, pB_end; |
|---|
| 197 |
|
|---|
| 198 |
if (!PyArg_ParseTuple(args, "sss#s#s#s#s#is#s#s#s#s#s#Offs#iOOOiii", &Patterns, &PSize, |
|---|
| 199 |
&PInvFlips, &noPatterns, &PColorSwitch, &PCSlength, |
|---|
| 200 |
&PAnchors, &PAlength, &PBitsTable, &PBTlength, &PBits, &PBlength, &moveLimit, |
|---|
| 201 |
&helplist, &HLlength, &fp, &fplength, |
|---|
| 202 |
&mainlist, &MLlength, &posTable, &PTlength, |
|---|
| 203 |
&hashIndices, &hashIlength, &hash, &hashlength, |
|---|
| 204 |
&progBarUpdate, &pB_start, &pB_end, |
|---|
| 205 |
&contLabels, &contLabelsLength, &contLabelsIndex, |
|---|
| 206 |
&continuations, &symmetries, &dbData, |
|---|
| 207 |
&showColorSwitch, &nextMoveVar, &fixedColorVar)) |
|---|
| 208 |
return NULL; |
|---|
| 209 |
|
|---|
| 210 |
HLlength /= sizeof(unsigned long); |
|---|
| 211 |
|
|---|
| 212 |
int foundgamesSize = 5000; |
|---|
| 213 |
int unsigned long *foundgames = PyMem_New(unsigned long, foundgamesSize); |
|---|
| 214 |
int foundgamesIndex=0; |
|---|
| 215 |
|
|---|
| 216 |
PyObject *result = PyList_New(0); |
|---|
| 217 |
|
|---|
| 218 |
int Bwins = 0; |
|---|
| 219 |
int Wwins = 0; |
|---|
| 220 |
int noSwitched = 0; |
|---|
| 221 |
int noMatchesFinal = 0; |
|---|
| 222 |
|
|---|
| 223 |
int patternSize = PSize[0] * PSize[1]; |
|---|
| 224 |
|
|---|
| 225 |
unsigned long* hashInd = new unsigned long[noPatterns]; |
|---|
| 226 |
if (hashIlength) { |
|---|
| 227 |
for(int i=0; i<noPatterns; i++) hashInd[i] = hashIndices[2*i]; |
|---|
| 228 |
} |
|---|
| 229 |
|
|---|
| 230 |
for(int game=0; game < HLlength; game++) { |
|---|
| 231 |
|
|---|
| 232 |
if (game % 600 == 0) { |
|---|
| 233 |
float percent = game * (pB_end - pB_start) / HLlength + pB_start; |
|---|
| 234 |
PyObject* arglist = Py_BuildValue("(f)", percent); |
|---|
| 235 |
PyEval_CallObject(progBarUpdate, arglist); |
|---|
| 236 |
Py_DECREF(arglist); |
|---|
| 237 |
} |
|---|
| 238 |
|
|---|
| 239 |
unsigned long index = helplist[game]; |
|---|
| 240 |
|
|---|
| 241 |
char matchlist[13000]; |
|---|
| 242 |
int matchlistIndex = 0; |
|---|
| 243 |
|
|---|
| 244 |
for(char N=0; N<noPatterns; N++) { |
|---|
| 245 |
|
|---|
| 246 |
if (hashIlength) { |
|---|
| 247 |
while ((hashInd[N]+1<hashIndices[2*N+1]) && (index > 256*hash[hashInd[N]] + hash[hashInd[N]+1])) hashInd[N]+=2; |
|---|
| 248 |
if (index < 256*hash[hashInd[N]] + hash[hashInd[N]+1]) continue; |
|---|
| 249 |
if (index == 256*hash[hashInd[N]] + hash[hashInd[N]+1]) { |
|---|
| 250 |
hashInd[N] += 2; |
|---|
| 251 |
matchlist[matchlistIndex++] = N; |
|---|
| 252 |
matchlist[matchlistIndex++] = PAnchors[4*N]; |
|---|
| 253 |
matchlist[matchlistIndex++] = PAnchors[4*N+1]; |
|---|
| 254 |
} |
|---|
| 255 |
} |
|---|
| 256 |
else { |
|---|
| 257 |
|
|---|
| 258 |
char a00 = PAnchors[4*N]; |
|---|
| 259 |
char a01 = PAnchors[4*N+1]; |
|---|
| 260 |
char a10 = PAnchors[4*N+2]; |
|---|
| 261 |
char a11 = PAnchors[4*N+3]; |
|---|
| 262 |
|
|---|
| 263 |
for(char a0=a00; a0 <= a10; a0++) |
|---|
| 264 |
for(char a1=a01; a1 <= a11; a1++) { |
|---|
| 265 |
|
|---|
| 266 |
int matches = 1; |
|---|
| 267 |
|
|---|
| 268 |
int pIndex = 2*(a1%2) + (a0%2); |
|---|
| 269 |
int patternBits = PBitsTable[N*4 + pIndex]; |
|---|
| 270 |
|
|---|
| 271 |
int pbIndex = 0; |
|---|
| 272 |
int fpIndex = index*150 + a1/2 + (a0/2)*10; |
|---|
| 273 |
|
|---|
| 274 |
for(int x=0; x < PBits[patternBits]; x++) { |
|---|
| 275 |
|
|---|
| 276 |
int start = PBits[patternBits + ++pbIndex]; |
|---|
| 277 |
int length = PBits[patternBits + ++pbIndex]; |
|---|
| 278 |
fpIndex += start; |
|---|
| 279 |
|
|---|
| 280 |
for(int y=0; y<length; y++) { |
|---|
| 281 |
pbIndex++; |
|---|
| 282 |
|
|---|
| 283 |
if (PBits[patternBits+pbIndex] & fp[fpIndex]) { |
|---|
| 284 |
matches = 0; |
|---|
| 285 |
break; |
|---|
| 286 |
} |
|---|
| 287 |
|
|---|
| 288 |
fpIndex++; |
|---|
| 289 |
} |
|---|
| 290 |
if (!matches) break; |
|---|
| 291 |
fpIndex += 10 - start - length; |
|---|
| 292 |
|
|---|
| 293 |
} |
|---|
| 294 |
|
|---|
| 295 |
if (matches) { |
|---|
| 296 |
matchlist[matchlistIndex++] = N; |
|---|
| 297 |
matchlist[matchlistIndex++] = a0; |
|---|
| 298 |
matchlist[matchlistIndex++] = a1; |
|---|
| 299 |
} |
|---|
| 300 |
|
|---|
| 301 |
} |
|---|
| 302 |
} |
|---|
| 303 |
} |
|---|
| 304 |
|
|---|
| 305 |
if (matchlistIndex) { |
|---|
| 306 |
|
|---|
| 307 |
int noMatches = matchlistIndex/3; |
|---|
| 308 |
int toBeFound = noMatches; |
|---|
| 309 |
long noCurrentResults = 0; |
|---|
| 310 |
long *currentResults = new long[noMatches*2]; |
|---|
| 311 |
|
|---|
| 312 |
char *dicts = new char[noMatches * patternSize]; |
|---|
| 313 |
int *dictsNO = new int[noMatches]; |
|---|
| 314 |
|
|---|
| 315 |
int *found = new int[noMatches]; |
|---|
| 316 |
|
|---|
| 317 |
char *Xinterv = new char[2*noMatches]; |
|---|
| 318 |
char *Yinterv = new char[2*noMatches]; |
|---|
| 319 |
|
|---|
| 320 |
for(int m=0; m<noMatches; m++) { |
|---|
| 321 |
|
|---|
| 322 |
found[m] = -1; |
|---|
| 323 |
dictsNO[m] = 0; |
|---|
| 324 |
|
|---|
| 325 |
int sizeX = PSize[2*matchlist[3*m]]; |
|---|
| 326 |
int sizeY = PSize[2*matchlist[3*m]+1]; |
|---|
| 327 |
int Poffset = matchlist[3*m] * patternSize; |
|---|
| 328 |
|
|---|
| 329 |
for(int i=0; i < sizeX; i++) { |
|---|
| 330 |
for(int j=0; j < sizeY; j++) { |
|---|
| 331 |
if (Patterns[Poffset + sizeY*i + j] == '.') |
|---|
| 332 |
dicts[m*patternSize+i*sizeY+j] = ' '; |
|---|
| 333 |
else { |
|---|
| 334 |
dicts[m*patternSize+i*sizeY+j] = Patterns[Poffset + sizeY*i + j]; |
|---|
| 335 |
if (Patterns[Poffset + sizeY*i + j] != '*') dictsNO[m]++; |
|---|
| 336 |
} |
|---|
| 337 |
} |
|---|
| 338 |
} |
|---|
| 339 |
|
|---|
| 340 |
Xinterv[2*m] = matchlist[3*m+1]; |
|---|
| 341 |
Xinterv[2*m+1] = matchlist[3*m+1] + PSize[2*matchlist[3*m]]; |
|---|
| 342 |
Yinterv[2*m] = matchlist[3*m+2]; |
|---|
| 343 |
Yinterv[2*m+1] = matchlist[3*m+2] + PSize[2*matchlist[3*m]+1]; |
|---|
| 344 |
} |
|---|
| 345 |
|
|---|
| 346 |
int movelistIndex = posTable[index]+2; |
|---|
| 347 |
|
|---|
| 348 |
int caplistIndex = movelistIndex; |
|---|
| 349 |
while (mainlist[caplistIndex] != 'z') caplistIndex++; |
|---|
| 350 |
int mlLength = caplistIndex; |
|---|
| 351 |
|
|---|
| 352 |
if (mainlist[caplistIndex+2] == 'z') caplistIndex +=2; |
|---|
| 353 |
else caplistIndex += 3; |
|---|
| 354 |
|
|---|
| 355 |
|
|---|
| 356 |
|
|---|
| 357 |
if (mainlist[movelistIndex] == 25 && mainlist[movelistIndex+1] == 3) { |
|---|
| 358 |
movelistIndex += 2; |
|---|
| 359 |
while (mainlist[movelistIndex] != 25) { |
|---|
| 360 |
char x = mainlist[movelistIndex++]; |
|---|
| 361 |
char y = mainlist[movelistIndex++]; |
|---|
| 362 |
|
|---|
| 363 |
for (int m=0; m<noMatches; m++) { |
|---|
| 364 |
if (found[m] != -2) { |
|---|
| 365 |
if (Xinterv[2*m] <= x && x < Xinterv[2*m+1] && |
|---|
| 366 |
Yinterv[2*m] <= y && y < Yinterv[2*m+1]) { |
|---|
| 367 |
|
|---|
| 368 |
if (dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1]+y-matchlist[3*m+2]]==' ') { |
|---|
| 369 |
|
|---|
| 370 |
if (!(fp[index*150 + 100 + y/4 + 5*(x/2)] & (1 << (x%2 + 2*(y%4))))) { |
|---|
| 371 |
|
|---|
| 372 |
found[m] = -2; |
|---|
| 373 |
toBeFound--; |
|---|
| 374 |
continue; |
|---|
| 375 |
} |
|---|
| 376 |
else { |
|---|
| 377 |
dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1]+y-matchlist[3*m+2]] = '.'; |
|---|
| 378 |
dictsNO[m]++; |
|---|
| 379 |
} |
|---|
| 380 |
} |
|---|
| 381 |
else if (dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1] |
|---|
| 382 |
+y-matchlist[3*m+2]] == 'X') { |
|---|
| 383 |
dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1]+y-matchlist[3*m+2]]=' '; |
|---|
| 384 |
dictsNO[m]--; |
|---|
| 385 |
} |
|---|
| 386 |
} |
|---|
| 387 |
} |
|---|
| 388 |
} |
|---|
| 389 |
} |
|---|
| 390 |
} |
|---|
| 391 |
|
|---|
| 392 |
|
|---|
| 393 |
|
|---|
| 394 |
if (mainlist[movelistIndex] == 25 && mainlist[movelistIndex+1] == 4) { |
|---|
| 395 |
movelistIndex += 2; |
|---|
| 396 |
while (mainlist[movelistIndex] != 25) { |
|---|
| 397 |
char x = mainlist[movelistIndex]; |
|---|
| 398 |
char y = mainlist[movelistIndex+1]; |
|---|
| 399 |
movelistIndex += 2; |
|---|
| 400 |
|
|---|
| 401 |
int m; |
|---|
| 402 |
for (m=0; m<noMatches; m++) { |
|---|
| 403 |
if (found[m]!= -2) { |
|---|
| 404 |
if (Xinterv[2*m] <= x && x < Xinterv[2*m+1] && |
|---|
| 405 |
Yinterv[2*m] <= y && y < Yinterv[2*m+1]) { |
|---|
| 406 |
if (dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1]+y-matchlist[3*m+2]]==' ') { |
|---|
| 407 |
if (!(fp[index*150 + 100 + y/4 + 5*(x/2)] & (1 << (x%2 + 2*(y%4))))) { |
|---|
| 408 |
|
|---|
| 409 |
found[m] = -2; |
|---|
| 410 |
toBeFound--; |
|---|
| 411 |
continue; |
|---|
| 412 |
} |
|---|
| 413 |
else { |
|---|
| 414 |
dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1]+y-matchlist[3*m+2]] = '.'; |
|---|
| 415 |
dictsNO[m]++; |
|---|
| 416 |
} |
|---|
| 417 |
} |
|---|
| 418 |
else if (dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1] |
|---|
| 419 |
+y-matchlist[3*m+2]] == 'O') { |
|---|
| 420 |
dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1]+y-matchlist[3*m+2]]=' '; |
|---|
| 421 |
dictsNO[m]--; |
|---|
| 422 |
} |
|---|
| 423 |
} |
|---|
| 424 |
} |
|---|
| 425 |
} |
|---|
| 426 |
} |
|---|
| 427 |
} |
|---|
| 428 |
|
|---|
| 429 |
for(int m=0; m<noMatches; m++) |
|---|
| 430 |
if (found[m]==-1 && !dictsNO[m]) found[m] = 0; |
|---|
| 431 |
|
|---|
| 432 |
|
|---|
| 433 |
|
|---|
| 434 |
char co = 'B'; |
|---|
| 435 |
|
|---|
| 436 |
if (mainlist[movelistIndex+1] == 1) co = 'B'; |
|---|
| 437 |
if (mainlist[movelistIndex+1] == 2) co = 'W'; |
|---|
| 438 |
|
|---|
| 439 |
int mLimit; |
|---|
| 440 |
|
|---|
| 441 |
if (moveLimit == 250) mLimit = 1500 + movelistIndex; |
|---|
| 442 |
else mLimit = 2*moveLimit + movelistIndex; |
|---|
| 443 |
|
|---|
| 444 |
int counter = -1; |
|---|
| 445 |
char c; |
|---|
| 446 |
char cinv; |
|---|
| 447 |
|
|---|
| 448 |
while (movelistIndex < mlLength-2 && movelistIndex < mLimit) { |
|---|
| 449 |
|
|---|
| 450 |
movelistIndex += 2; |
|---|
| 451 |
counter++; |
|---|
| 452 |
|
|---|
| 453 |
if (co == 'B') { |
|---|
| 454 |
co = 'W'; |
|---|
| 455 |
c = 'X'; |
|---|
| 456 |
cinv = 'O'; |
|---|
| 457 |
} else { |
|---|
| 458 |
co = 'B'; |
|---|
| 459 |
c = 'O'; |
|---|
| 460 |
cinv = 'X'; |
|---|
| 461 |
} |
|---|
| 462 |
|
|---|
| 463 |
char x = mainlist[movelistIndex]; |
|---|
| 464 |
char y = mainlist[movelistIndex+1]; |
|---|
| 465 |
|
|---|
| 466 |
int clI = 0; |
|---|
| 467 |
int clIend = 0; |
|---|
| 468 |
|
|---|
| 469 |
if (mainlist[caplistIndex] != 'z' && counter == 256*mainlist[caplistIndex] + mainlist[caplistIndex+1]) { |
|---|
| 470 |
caplistIndex += 2; |
|---|
| 471 |
clI = caplistIndex; |
|---|
| 472 |
while (mainlist[caplistIndex] != 'z' && mainlist[caplistIndex] != 'y') caplistIndex++; |
|---|
| 473 |
clIend = caplistIndex-1; |
|---|
| 474 |
caplistIndex++; |
|---|
| 475 |
} |
|---|
| 476 |
|
|---|
| 477 |
for(int m=0; m<noMatches; m++) { |
|---|
| 478 |
|
|---|
| 479 |
if (found[m] != -2) { |
|---|
| 480 |
|
|---|
| 481 |
if (Xinterv[2*m] <= x && x < Xinterv[2*m+1] && |
|---|
| 482 |
Yinterv[2*m] <= y && y < Yinterv[2*m+1]) { |
|---|
| 483 |
|
|---|
| 484 |
if (found[m] > -1) { |
|---|
| 485 |
int colorSwitch = 0; |
|---|
| 486 |
|
|---|
| 487 |
int f = PInvFlips[matchlist[3*m]]; |
|---|
| 488 |
char xx = flipX(f, x, y); |
|---|
| 489 |
char yy = flipY(f, x, y); |
|---|
| 490 |
|
|---|
| 491 |
char XX1 = flipX(f, Xinterv[2*m], Yinterv[2*m]); |
|---|
| 492 |
char YY1 = flipY(f, Xinterv[2*m], Yinterv[2*m]); |
|---|
| 493 |
|
|---|
| 494 |
char XX2 = flipX(f, Xinterv[2*m+1]-1, Yinterv[2*m+1]-1); |
|---|
| 495 |
char YY2 = flipY(f, Xinterv[2*m+1]-1, Yinterv[2*m+1]-1); |
|---|
| 496 |
|
|---|
| 497 |
char XX = XX1 < XX2 ? XX1 : XX2; |
|---|
| 498 |
char YY = YY1 < YY2 ? YY1 : YY2; |
|---|
| 499 |
|
|---|
| 500 |
xx -= XX; |
|---|
| 501 |
yy -= YY; |
|---|
| 502 |
|
|---|
| 503 |
char *cc, *wcc, *lcc, *tcc; |
|---|
| 504 |
if ((PColorSwitch[matchlist[3*m]] && co == 'B') || |
|---|
| 505 |
(!PColorSwitch[matchlist[3*m]] && co == 'W')) |
|---|
| 506 |
cc = "B"; |
|---|
| 507 |
else cc = "W"; |
|---|
| 508 |
|
|---|
| 509 |
PyObject *key = Py_BuildValue("ii", xx, yy); |
|---|
| 510 |
PyObject *t = PyDict_GetItem(symmetries, key); |
|---|
| 511 |
Py_DECREF(key); |
|---|
| 512 |
|
|---|
| 513 |
PyObject *xxyy = PyTuple_GetItem(t, 0); |
|---|
| 514 |
Py_INCREF(xxyy); |
|---|
| 515 |
|
|---|
| 516 |
xx = PyInt_AsLong(PyTuple_GetItem(xxyy, 0)); |
|---|
| 517 |
yy = PyInt_AsLong(PyTuple_GetItem(xxyy, 1)); |
|---|
| 518 |
long cSymm = PyInt_AsLong(PyTuple_GetItem(t, 1)); |
|---|
| 519 |
|
|---|
| 520 |
if ((strcmp(cc, "W")==0 && !cSymm) || (strcmp(cc, "B")==0 && cSymm)) { |
|---|
| 521 |
cc = "W"; |
|---|
| 522 |
wcc = "wW"; |
|---|
| 523 |
lcc = "lW"; |
|---|
| 524 |
tcc = "tW"; |
|---|
| 525 |
} |
|---|
| 526 |
else { |
|---|
| 527 |
cc = "B"; |
|---|
| 528 |
wcc = "wB"; |
|---|
| 529 |
lcc = "lB"; |
|---|
| 530 |
tcc = "tB"; |
|---|
| 531 |
} |
|---|
| 532 |
|
|---|
| 533 |
if (nextMoveVar) { |
|---|
| 534 |
if ((nextMoveVar==2 && cc=="B") || (nextMoveVar==1 && cc=="W")) { |
|---|
| 535 |
PyObject *key1 = PyInt_FromLong(-1); |
|---|
| 536 |
PyObject *t1 = PyDict_GetItem(symmetries, key1); |
|---|
| 537 |
Py_DECREF(key1); |
|---|
| 538 |
|
|---|
| 539 |
long ssymm = PyInt_AsLong(t1); |
|---|
| 540 |
if (ssymm != -1 && !fixedColorVar) { |
|---|
| 541 |
|
|---|
| 542 |
if (cc == "B") { |
|---|
| 543 |
cc = "W"; |
|---|
| 544 |
wcc = "wW"; |
|---|
| 545 |
lcc = "lW"; |
|---|
| 546 |
tcc = "tW"; |
|---|
| 547 |
} |
|---|
| 548 |
else { |
|---|
| 549 |
cc = "B"; |
|---|
| 550 |
wcc = "wB"; |
|---|
| 551 |
lcc = "lB"; |
|---|
| 552 |
tcc = "tB"; |
|---|
| 553 |
} |
|---|
| 554 |
|
|---|
| 555 |
|
|---|
| 556 |
xx += XX; |
|---|
| 557 |
yy += YY; |
|---|
| 558 |
|
|---|
| 559 |
int xx_n = flipX(ssymm, xx, yy); |
|---|
| 560 |
int yy_n = flipY(ssymm, xx, yy); |
|---|
| 561 |
int XX1_n = flipX(ssymm, XX1, YY1); |
|---|
| 562 |
int YY1_n = flipY(ssymm, XX1, YY1); |
|---|
| 563 |
int XX2_n = flipX(ssymm, XX2, YY2); |
|---|
| 564 |
int YY2_n = flipY(ssymm, XX2, YY2); |
|---|
| 565 |
|
|---|
| 566 |
XX = XX1_n < XX2_n ? XX1_n : XX2_n; |
|---|
| 567 |
YY = YY1_n < YY2_n ? YY1_n : YY2_n; |
|---|
| 568 |
|
|---|
| 569 |
xx = xx_n - XX; |
|---|
| 570 |
yy = yy_n - YY; |
|---|
| 571 |
|
|---|
| 572 |
PyObject *key2 = Py_BuildValue("ii", xx, yy); |
|---|
| 573 |
PyObject *t2 = PyDict_GetItem(symmetries, key); |
|---|
| 574 |
|
|---|
| 575 |
PyObject *xxyy2 = PyTuple_GetItem(t2, 0); |
|---|
| 576 |
long cSymm1 = PyInt_AsLong(PyTuple_GetItem(t2, 1)); |
|---|
| 577 |
|
|---|
| 578 |
if (!cSymm1) { |
|---|
| 579 |
Py_DECREF(xxyy); |
|---|
| 580 |
xxyy = xxyy2; |
|---|
| 581 |
Py_DECREF(key2); |
|---|
| 582 |
Py_INCREF(xxyy); |
|---|
| 583 |
} |
|---|
| 584 |
else { |
|---|
| 585 |
Py_DECREF(xxyy); |
|---|
| 586 |
xxyy = key2; |
|---|
| 587 |
} |
|---|
| 588 |
|
|---|
| 589 |
colorSwitch = 1-cSymm; |
|---|
| 590 |
if (colorSwitch) noSwitched++; |
|---|
| 591 |
} |
|---|
| 592 |
else { |
|---|
| 593 |
found[m] = -2; |
|---|
| 594 |
toBeFound--; |
|---|
| 595 |
continue; |
|---|
| 596 |
} |
|---|
| 597 |
} |
|---|
| 598 |
else { |
|---|
| 599 |
colorSwitch = cSymm; |
|---|
| 600 |
if (colorSwitch) noSwitched++; |
|---|
| 601 |
} |
|---|
| 602 |
} |
|---|
| 603 |
else colorSwitch = cSymm; |
|---|
| 604 |
|
|---|
| 605 |
char text; |
|---|
| 606 |
PyObject* scxy; |
|---|
| 607 |
|
|---|
| 608 |
if ((scxy = PyDict_GetItem(continuations, xxyy))) { |
|---|
| 609 |
PyObject *temp = PyInt_FromLong(PyInt_AsLong(PyDict_GetItemString(scxy, cc))+1); |
|---|
| 610 |
PyDict_SetItemString(scxy, cc, temp); |
|---|
| 611 |
Py_DECREF(temp); |
|---|
| 612 |
text = PyString_AsString(PyDict_GetItemString(scxy, "N"))[0]; |
|---|
| 613 |
} |
|---|
| 614 |
else { |
|---|
| 615 |
if (contLabelsIndex >= contLabelsLength) text = '?'; |
|---|
| 616 |
else text = contLabels[contLabelsIndex++]; |
|---|
| 617 |
|
|---|
| 618 |
if (strcmp(cc, "B")==0) { |
|---|
| 619 |
scxy = PyDict_New(); |
|---|
| 620 |
PyObject* Py0 = PyInt_FromLong(0); |
|---|
| 621 |
PyObject *Py1 = PyInt_FromLong(1); |
|---|
| 622 |
PyDict_SetItemString(scxy, "B", Py1); |
|---|
| 623 |
PyDict_SetItemString(scxy, "W", Py0); |
|---|
| 624 |
PyDict_SetItemString(scxy, "tB", Py0); |
|---|
| 625 |
PyDict_SetItemString(scxy, "tW", Py0); |
|---|
| 626 |
PyDict_SetItemString(scxy, "wB", Py0); |
|---|
| 627 |
PyDict_SetItemString(scxy, "lB", Py0); |
|---|
| 628 |
PyDict_SetItemString(scxy, "wW", Py0); |
|---|
| 629 |
PyDict_SetItemString(scxy, "lW", Py0); |
|---|
| 630 |
PyDict_SetItemString(scxy, "N", PyString_FromStringAndSize(&text, 1)); |
|---|
| 631 |
Py_DECREF(Py0); |
|---|
| 632 |
Py_DECREF(Py1); |
|---|
| 633 |
PyDict_SetItem(continuations, xxyy, scxy); |
|---|
| 634 |
Py_DECREF(scxy); |
|---|
| 635 |
} |
|---|
| 636 |
else { |
|---|
| 637 |
scxy = PyDict_New(); |
|---|
| 638 |
PyObject *Py0 = PyInt_FromLong(0); |
|---|
| 639 |
PyObject *Py1 = PyInt_FromLong(1); |
|---|
| 640 |
PyDict_SetItemString(scxy, "B", Py0); |
|---|
| 641 |
PyDict_SetItemString(scxy, "W", Py1); |
|---|
| 642 |
PyDict_SetItemString(scxy, "tB", Py0); |
|---|
| 643 |
PyDict_SetItemString(scxy, "tW", Py0); |
|---|
| 644 |
PyDict_SetItemString(scxy, "wB", Py0); |
|---|
| 645 |
PyDict_SetItemString(scxy, "lB", Py0); |
|---|
| 646 |
PyDict_SetItemString(scxy, "wW", Py0); |
|---|
| 647 |
PyDict_SetItemString(scxy, "lW", Py0); |
|---|
| 648 |
PyDict_SetItemString(scxy, "N", PyString_FromStringAndSize(&text, 1)); |
|---|
| 649 |
Py_DECREF(Py0); |
|---|
| 650 |
Py_DECREF(Py1); |
|---|
| 651 |
PyDict_SetItem(continuations, xxyy, scxy); |
|---|
| 652 |
Py_DECREF(scxy); |
|---|
| 653 |
} |
|---|
| 654 |
} |
|---|
| 655 |
|
|---|
| 656 |
Py_DECREF(xxyy); |
|---|
| 657 |
|
|---|
| 658 |
PyObject *d1 = PyList_GetItem(dbData, index); |
|---|
| 659 |
|
|---|
| 660 |
if (!PyTuple_Check(d1)) return NULL; |
|---|
| 661 |
|
|---|
| 662 |
PyObject *d2 = PyTuple_GetItem(d1, 4); |
|---|
| 663 |
if (!PyString_Check(d2)) return NULL; |
|---|
| 664 |
|
|---|
| 665 |
char* winner = PyString_AsString(d2); |
|---|
| 666 |
|
|---|
| 667 |
if (winner[0] == 'B') |
|---|
| 668 |
if (!(PColorSwitch[matchlist[3*m]] || colorSwitch)) { |
|---|
| 669 |
PyObject *temp = PyInt_FromLong(PyInt_AsLong(PyDict_GetItemString(scxy, wcc))+1); |
|---|
| 670 |
PyDict_SetItemString(scxy, wcc, temp); |
|---|
| 671 |
Py_DECREF(temp); |
|---|
| 672 |
Bwins++; |
|---|
| 673 |
} |
|---|
| 674 |
else { |
|---|
| 675 |
PyObject *temp = PyInt_FromLong(PyInt_AsLong(PyDict_GetItemString(scxy, lcc))+1); |
|---|
| 676 |
PyDict_SetItemString(scxy, lcc, temp); |
|---|
| 677 |
Py_DECREF(temp); |
|---|
| 678 |
Wwins++; |
|---|
| 679 |
} |
|---|
| 680 |
if (winner[0] == 'W') |
|---|
| 681 |
if (!(PColorSwitch[matchlist[3*m]] || colorSwitch)) { |
|---|
| 682 |
PyObject *temp = PyInt_FromLong(PyInt_AsLong(PyDict_GetItemString(scxy, lcc))+1); |
|---|
| 683 |
PyDict_SetItemString(scxy, lcc, temp); |
|---|
| 684 |
Py_DECREF(temp); |
|---|
| 685 |
Wwins++; |
|---|
| 686 |
} |
|---|
| 687 |
else { |
|---|
| 688 |
PyObject *temp = PyInt_FromLong(PyInt_AsLong(PyDict_GetItemString(scxy, wcc))+1); |
|---|
| 689 |
PyDict_SetItemString(scxy, wcc, temp); |
|---|
| 690 |
Py_DECREF(temp); |
|---|
| 691 |
Bwins++; |
|---|
| 692 |
} |
|---|
| 693 |
|
|---|
| 694 |
if (!(found[m]==counter || found[m]==counter+1)) { |
|---|
| 695 |
PyObject *temp = PyInt_FromLong(PyInt_AsLong(PyDict_GetItemString(scxy, tcc))+1); |
|---|
| 696 |
PyDict_SetItemString(scxy, tcc, temp); |
|---|
| 697 |
Py_DECREF(temp); |
|---|
| 698 |
} |
|---|
| 699 |
|
|---|
| 700 |
noSwitched += PColorSwitch[matchlist[3*m]]; |
|---|
| 701 |
|
|---|
| 702 |
currentResults[2*noCurrentResults] = found[m]; |
|---|
| 703 |
currentResults[2*noCurrentResults+1] = (PColorSwitch[matchlist[3*m]]|colorSwitch) * COLORSWITCH + text; |
|---|
| 704 |
noCurrentResults++; |
|---|
| 705 |
|
|---|
| 706 |
found[m] = -2; |
|---|
| 707 |
toBeFound--; |
|---|
| 708 |
|
|---|
| 709 |
continue; |
|---|
| 710 |
} |
|---|
| 711 |
|
|---|
| 712 |
if (dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1] |
|---|
| 713 |
+y-matchlist[3*m+2]] == ' ') { |
|---|
| 714 |
|
|---|
| 715 |
if (!(fp[index*150 + 100 + y/4 + 5*(x/2)] & (1 << (x%2 + 2*(y%4))))) { |
|---|
| 716 |
found[m] = -2; |
|---|
| 717 |
toBeFound--; |
|---|
| 718 |
continue; |
|---|
| 719 |
} |
|---|
| 720 |
else { |
|---|
| 721 |
dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1]+y-matchlist[3*m+2]] = '.'; |
|---|
| 722 |
dictsNO[m]++; |
|---|
| 723 |
} |
|---|
| 724 |
|
|---|
| 725 |
} |
|---|
| 726 |
else if (dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1] |
|---|
| 727 |
+y-matchlist[3*m+2]] == c) { |
|---|
| 728 |
dicts[m*patternSize+(x-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1]+y-matchlist[3*m+2]] = ' '; |
|---|
| 729 |
dictsNO[m]--; |
|---|
| 730 |
} |
|---|
| 731 |
} |
|---|
| 732 |
|
|---|
| 733 |
if (found[m] == -1) { |
|---|
| 734 |
|
|---|
| 735 |
if (clI) { |
|---|
| 736 |
|
|---|
| 737 |
for(int i=clI; i<clIend; i+=2) { |
|---|
| 738 |
char xx = mainlist[i]-1; |
|---|
| 739 |
char yy = mainlist[i+1]-1; |
|---|
| 740 |
|
|---|
| 741 |
if (Xinterv[2*m] <= xx && xx < Xinterv[2*m+1] && |
|---|
| 742 |
Yinterv[2*m] <= yy && yy < Yinterv[2*m+1]) { |
|---|
| 743 |
if (dicts[m*patternSize+(xx-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1] |
|---|
| 744 |
+yy-matchlist[3*m+2]] == ' ') { |
|---|
| 745 |
dicts[m*patternSize+(xx-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1] |
|---|
| 746 |
+yy-matchlist[3*m+2]] = cinv; |
|---|
| 747 |
dictsNO[m]++; |
|---|
| 748 |
} |
|---|
| 749 |
else if (dicts[m*patternSize+(xx-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1] |
|---|
| 750 |
+yy-matchlist[3*m+2]] == '.') { |
|---|
| 751 |
dicts[m*patternSize+(xx-matchlist[3*m+1])*PSize[2*matchlist[3*m]+1] |
|---|
| 752 |
+yy-matchlist[3*m+2]] = ' '; |
|---|
| 753 |
dictsNO[m]--; |
|---|
| 754 |
} |
|---|
| 755 |
} |
|---|
| 756 |
|
|---|
| 757 |
} |
|---|
| 758 |
} |
|---|
| 759 |
if (!dictsNO[m]) found[m] = counter + 1; |
|---|
| 760 |
} |
|---|
| 761 |
|
|---|
| 762 |
} |
|---|
| 763 |
} |
|---|
| 764 |
|
|---|
| 765 |
if (!toBeFound) break; |
|---|
| 766 |
} |
|---|
| 767 |
|
|---|
| 768 |
|
|---|
| 769 |
if (!nextMoveVar) { |
|---|
| 770 |
for(int m=0; m<noMatches; m++) |
|---|
| 771 |
if (found[m] > -1) { |
|---|
| 772 |
|
|---|
| 773 |
noSwitched += PColorSwitch[matchlist[3*m]]; |
|---|
| 774 |
|
|---|
| 775 |
currentResults[2*noCurrentResults] = found[m]; |
|---|
| 776 |
currentResults[2*noCurrentResults+1] = PColorSwitch[matchlist[3*m]] * COLORSWITCH; |
|---|
| 777 |
noCurrentResults++; |
|---|
| 778 |
|
|---|
| 779 |
char winner = PyString_AsString(PyTuple_GetItem(PyList_GetItem(dbData, index), 4))[0]; |
|---|
| 780 |
|
|---|
| 781 |
if (winner == 'B') |
|---|
| 782 |
if (!PColorSwitch[matchlist[3*m]]) Bwins++; |
|---|
| 783 |
else Wwins++; |
|---|
| 784 |
if (winner == 'W') |
|---|
| 785 |
if (!PColorSwitch[matchlist[3*m]]) Wwins++; |
|---|
| 786 |
else Bwins++; |
|---|
| 787 |
} |
|---|
| 788 |
} |
|---|
| 789 |
|
|---|
| 790 |
delete dicts; |
|---|
| 791 |
delete dictsNO; |
|---|
| 792 |
delete found; |
|---|
| 793 |
delete Xinterv; |
|---|
| 794 |
delete Yinterv; |
|---|
| 795 |
|
|---|
| 796 |
if (noCurrentResults) { |
|---|
| 797 |
|
|---|
| 798 |
if (foundgamesIndex > foundgamesSize - 2) { |
|---|
| 799 |
foundgamesSize += 2000; |
|---|
| 800 |
foundgames = PyMem_Resize(foundgames, unsigned long, foundgamesSize); |
|---|
| 801 |
} |
|---|
| 802 |
|
|---|
| 803 |
foundgames[foundgamesIndex++] = index; |
|---|
| 804 |
noMatchesFinal += noCurrentResults; |
|---|
| 805 |
|
|---|
| 806 |
sortCArray(currentResults, 0, noCurrentResults-1); |
|---|
| 807 |
|
|---|
| 808 |
char *resultStr = new char[7*noCurrentResults]; |
|---|
| 809 |
int resultStrIndex = 0; |
|---|
| 810 |
|
|---|
| 811 |
for(int i=0; i<noCurrentResults; i++) { |
|---|
| 812 |
char *s = itoa(currentResults[2*i]); |
|---|
| 813 |
for(int j=0; j<strlen(s); j++) resultStr[resultStrIndex++] = s[j]; |
|---|
| 814 |
delete s; |
|---|
| 815 |
if (currentResults[2*i+1] % 256) resultStr[resultStrIndex++] = currentResults[2*i+1] % 256; |
|---|
| 816 |
if (showColorSwitch && (currentResults[2*i+1]&COLORSWITCH)) resultStr[resultStrIndex++] = '-'; |
|---|
| 817 |
resultStr[resultStrIndex++] = ','; |
|---|
| 818 |
resultStr[resultStrIndex++] = ' '; |
|---|
| 819 |
} |
|---|
| 820 |
resultStrIndex -= 2; |
|---|
| 821 |
|
|---|
| 822 |
PyObject *temp = PyString_FromStringAndSize(resultStr, resultStrIndex); |
|---|
| 823 |
if (PyList_Append(result, temp)) return NULL; |
|---|
| 824 |
Py_DECREF(temp); |
|---|
| 825 |
|
|---|
| 826 |
delete resultStr; |
|---|
| 827 |
|
|---|
| 828 |
} |
|---|
| 829 |
delete currentResults; |
|---|
| 830 |
} |
|---|
| 831 |
} |
|---|
| 832 |
|
|---|
| 833 |
PyObject *returnValue = Py_BuildValue("s#Oiiiii", foundgames, foundgamesIndex*sizeof(unsigned long), result, |
|---|
| 834 |
noSwitched, contLabelsIndex, Wwins, Bwins, noMatchesFinal); |
|---|
| 835 |
|
|---|
| 836 |
Py_DECREF(result); |
|---|
| 837 |
delete hashInd; |
|---|
| 838 |
PyMem_Free(foundgames); |
|---|
| 839 |
|
|---|
| 840 |
return returnValue; |
|---|
| 841 |
} |
|---|
| 842 |
|
|---|
| 843 |
|
|---|
| 844 |
static PyObject* sortArray(PyObject* self, PyObject* args) { |
|---|
| 845 |
|
|---|
| 846 |
long* a; |
|---|
| 847 |
|
|---|
| 848 |
unsigned long adr; |
|---|
| 849 |
long l, r; |
|---|
| 850 |
|
|---|
| 851 |
if (!PyArg_ParseTuple(args, "lii", &adr, &l, &r)) |
|---|
| 852 |
return NULL; |
|---|
| 853 |
|
|---|
|
|---|