1 //------------------------------------------------------------------------------
2 // SilChessMachine.cpp
3 //
4 // Copyright (C) 2000-2005,2007-2009,2020 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <time.h>
26 #include <SilChess/SilChessMachine.h>
27
28
SilChessMachine()29 SilChessMachine::SilChessMachine()
30 {
31 SearchDepth=DEFAULT_SEARCH_DEPTH;
32 HumanSide=TF_White;
33 SearchStackTop=NULL;
34 SearchMachine=NULL;
35 CachedInfoValid=false;
36 StartNewGame();
37 }
38
39
SilChessMachine(const SilChessMachine & machine)40 SilChessMachine::SilChessMachine(const SilChessMachine & machine)
41 {
42 SearchDepth=DEFAULT_SEARCH_DEPTH;
43 HumanSide=TF_White;
44 SearchStackTop=NULL;
45 SearchMachine=NULL;
46 CachedInfoValid=false;
47 StartNewGame();
48 *this=machine;
49 }
50
51
~SilChessMachine()52 SilChessMachine::~SilChessMachine()
53 {
54 EndSearching();
55 }
56
57
operator =(const SilChessMachine & machine)58 SilChessMachine & SilChessMachine::operator = (const SilChessMachine & machine)
59 {
60 int i,j;
61
62 EndSearching();
63 CachedInfoValid=false;
64 SearchDepth=machine.SearchDepth;
65 HumanSide=machine.HumanSide;
66 memcpy(Pieces,machine.Pieces,sizeof(Pieces));
67 for (i=0; i<32; i++) for (j=0; j<16; j++) if (Pieces[i].N[j]) {
68 Pieces[i].N[j]=Pieces+(Pieces[i].N[j]-machine.Pieces);
69 }
70 for (i=0; i<64; i++) {
71 Board[i] = machine.Board[i] ? Pieces+(machine.Board[i]-machine.Pieces) : NULL;
72 }
73 Turn=machine.Turn;
74 memcpy(Moves,machine.Moves,sizeof(Moves));
75 MoveCount=machine.MoveCount;
76 TBClear();
77 memcpy(ValFac,machine.ValFac,sizeof(ValFac));
78 return *this;
79 }
80
81
ToString(char * str) const82 void SilChessMachine::Move::ToString(char * str) const
83 {
84 str[0]=(char)('a'+X1);
85 str[1]=(char)('8'-Y1);
86 str[2]=(char)('a'+X2);
87 str[3]=(char)('8'-Y2);
88 str[4]=0;
89 }
90
91
FromString(const char * str)92 bool SilChessMachine::Move::FromString(const char * str)
93 {
94 int i;
95
96 if (strlen(str)<4) return false;
97 if (str[0]>='A' && str[0]<='Z') X1=(signed char)(str[0]-'A');
98 else X1=(signed char)(str[0]-'a');
99 Y1=(signed char)('8'-str[1]);
100 if (str[2]>='A' && str[2]<='Z') X2=(signed char)(str[2]-'A');
101 else X2=(signed char)(str[2]-'a');
102 Y2=(signed char)('8'-str[3]);
103 if (X1<0 || Y1<0 || X2<0 || Y2<0 ||
104 X1>7 || Y1>7 || X2>7 || Y2>7) return false;
105 for (i=4; str[i]!=0; i++) if ((unsigned char)str[i]>32) return false;
106 return true;
107 }
108
109
operator ==(const Move & m) const110 bool SilChessMachine::Move::operator == (const Move & m) const
111 {
112 return X1==m.X1 && Y1==m.Y1 && X2==m.X2 && Y2==m.Y2;
113 }
114
115
StartNewGame()116 void SilChessMachine::StartNewGame()
117 {
118 int i;
119
120 EndSearching();
121 CachedInfoValid=false;
122
123 // The following factors have been optimized by a genetic algorithm.
124 ValFac[VFI_Piece ]= 116;
125 ValFac[VFI_PayingTurn ]= 90;
126 ValFac[VFI_PayingTurnOppo ]= 2;
127 ValFac[VFI_Threats ]= 12;
128 ValFac[VFI_Mobility ]= 6;
129 ValFac[VFI_Ties ]= 2;
130 ValFac[VFI_Center ]= 1;
131 ValFac[VFI_KingCover ]= 2;
132 ValFac[VFI_KingMobility ]= 6;
133 ValFac[VFI_KingNotCentered]= 2;
134 ValFac[VFI_KingCheck ]= 112;
135 ValFac[VFI_PawnBeside ]= 6;
136 ValFac[VFI_PawnOnward ]= 26;
137 ValFac[VFI_PawnHeaven ]= 120;
138
139 // The higher this value, the more random are the computer moves.
140 ValRangeForRandom=3;
141
142 TBClear();
143 memset(Pieces,0,sizeof(Pieces));
144 memset(Board,0,sizeof(Board));
145 Turn=TF_White;
146 MoveCount=0;
147 for (i=0; i<16; i++) {
148 if (i<8) {
149 Pieces[i].Type=TF_Pawn|TF_White;
150 Pieces[i].Value=PawnValue;
151 }
152 else if (i==8 || i==15) {
153 Pieces[i].Type=TF_Rook|TF_White;
154 Pieces[i].Value=RookValue;
155 Pieces[i].State=SF_CanCastle;
156 }
157 else if (i==9 || i==14) {
158 Pieces[i].Type=TF_Knight|TF_White;
159 Pieces[i].Value=KnightValue;
160 }
161 else if (i==10 || i==13) {
162 Pieces[i].Type=TF_Bishop|TF_White;
163 Pieces[i].Value=BishopValue;
164 }
165 else if (i==11) {
166 Pieces[i].Type=TF_Queen|TF_White;
167 Pieces[i].Value=QueenValue;
168 }
169 else {
170 Pieces[i].Type=TF_King|TF_White;
171 Pieces[i].Value=KingValue;
172 Pieces[i].State=SF_CanCastle;
173 }
174 Pieces[i].X=i&7;
175 Pieces[i].Y=6+(i>>3);
176 }
177 for (i=16; i<32; i++) {
178 Pieces[i]=Pieces[i-16];
179 Pieces[i].Type^=TF_White|TF_Black;
180 Pieces[i].Y=7-Pieces[i].Y;
181 }
182 for (i=0; i<32; i++) TBLinkPiece(Pieces[i]);
183 TBClear();
184 }
185
186
SetSearchDepth(int searchDepth)187 void SilChessMachine::SetSearchDepth(int searchDepth)
188 {
189 if (searchDepth<0) searchDepth=0;
190 if (searchDepth>MAX_SEARCH_DEPTH) searchDepth=MAX_SEARCH_DEPTH;
191 if (SearchDepth!=searchDepth) {
192 EndSearching();
193 SearchDepth=searchDepth;
194 }
195 }
196
197
GetField(int x,int y) const198 int SilChessMachine::GetField(int x, int y) const
199 {
200 Piece * p;
201 int t,r;
202
203 p=Board[y*8+x];
204 if (!p) return 0;
205 t=p->Type;
206 if (t&TF_Pawn ) r=1;
207 else if (t&TF_Knight) r=2;
208 else if (t&TF_Bishop) r=3;
209 else if (t&TF_Rook ) r=4;
210 else if (t&TF_Queen ) r=5;
211 else r=6;
212 if (t&TF_Black) r+=6;
213 return r;
214 }
215
216
IsLegalMove(const Move & m) const217 bool SilChessMachine::IsLegalMove(const Move & m) const
218 {
219 Move pm[512];
220 int pmc,i;
221 bool check;
222 SilChessMachine * machine;
223
224 pmc=EnumeratePossibleMoves(pm);
225 for (i=0; i<pmc; i++) {
226 if (pm[i]==m) {
227 machine=(SilChessMachine*)this;
228 machine->TBStart();
229 machine->TBDoMove(m);
230 check=machine->IsCheck(true);
231 machine->TakeBack();
232 return !check;
233 }
234 }
235 return false;
236 }
237
238
DoMove(const Move & m)239 void SilChessMachine::DoMove(const Move & m)
240 {
241 EndSearching();
242 TBDoMove(m);
243 TBClear();
244 }
245
246
UndoMove()247 void SilChessMachine::UndoMove()
248 {
249 Move m[MAX_MOVE_COUNT];
250 int mc,i;
251
252 if (MoveCount<=0) return;
253 EndSearching();
254 mc=MoveCount-1;
255 memcpy(m,Moves,sizeof(Move)*mc);
256 StartNewGame();
257 for (i=0; i<mc; i++) DoMove(m[i]);
258 }
259
260
SearchMove(Move * pResult)261 bool SilChessMachine::SearchMove(Move * pResult)
262 {
263 StartSearching(false);
264 while (!ContinueSearching()) {}
265 return EndSearching(pResult);
266 }
267
268
StartSearching(bool cloneEngine)269 void SilChessMachine::StartSearching(bool cloneEngine)
270 {
271 SearchStackEntry * top;
272 int i;
273
274 EndSearching();
275
276 top=SearchStack;
277 SearchStackTop=top;
278 top->Depth=SearchDepth;
279 top->Alpha=-INT_MAX;
280 top->Beta=INT_MAX;
281 top->Count=EnumeratePossibleMoves(top->Moves);
282 if (top->Depth>1) SortMoves(top->Moves,top->Count);
283 top->Index=0;
284 for (i=0; i<512; i++) FoundVals[i]=-INT_MAX;
285
286 if (cloneEngine) {
287 SearchMachine=new SilChessMachine(*this);
288 }
289 else {
290 SearchMachine=this;
291 }
292 }
293
294
ContinueSearching()295 bool SilChessMachine::ContinueSearching()
296 {
297 SearchStackEntry * top;
298 int v;
299
300 top=SearchStackTop;
301 if (!top) return false;
302 L_Next:
303 if (top->Index>=top->Count) {
304 if (top>SearchStack) goto L_Pop;
305 SearchStackTop=top;
306 return true;
307 }
308 SearchMachine->TBStart();
309 SearchMachine->TBDoMove(top->Moves[top->Index]);
310 if (!SearchMachine->IsCheck(true)) {
311 if (top->Depth>1) {
312 top[1].Depth=top->Depth-1;
313 top[1].Alpha=-top->Beta;
314 top[1].Beta=-top->Alpha;
315 top++;
316 top->Count=SearchMachine->EnumeratePossibleMoves(top->Moves);
317 if (top->Depth>1) SearchMachine->SortMoves(top->Moves,top->Count);
318 top->Index=0;
319 top->Found=0;
320 goto L_Next;
321 L_Pop:
322 if (top->Found>0) v=-top->Alpha;
323 else if (SearchMachine->IsCheck(false)) v=INT_MAX;
324 else v=0;
325 top--;
326 }
327 else if (top->Depth==1) {
328 v=-SearchMachine->Value();
329 }
330 else {
331 v=0;
332 }
333 if (top>SearchStack) {
334 top->Found++;
335 if (v>top->Alpha) {
336 top->Alpha=v;
337 if (v>=top->Beta) {
338 SearchMachine->TakeBack();
339 goto L_Pop;
340 }
341 }
342 }
343 else {
344 if (v==-INT_MAX) v=-INT_MAX+1;
345 FoundVals[top->Index]=v;
346 if (v<=-INT_MAX+2+ValRangeForRandom) v=-INT_MAX+1;
347 else v-=1+ValRangeForRandom;
348 if (v>top->Alpha) top->Alpha=v;
349 }
350 }
351 SearchMachine->TakeBack();
352 top->Index++;
353 if (top->Depth<3) goto L_Next;
354 SearchStackTop=top;
355 return false;
356 }
357
358
EndSearching(Move * pResult)359 bool SilChessMachine::EndSearching(Move * pResult)
360 {
361 SearchStackEntry * top;
362 int i,n,m,v;
363 bool res;
364
365 res=false;
366 top=SearchStackTop;
367 if (top) {
368 if (top==SearchStack && top->Index==top->Count) {
369 n=top->Count;
370 v=-INT_MAX;
371 for (i=0; i<n; i++) if (v<FoundVals[i]) v=FoundVals[i];
372 if (v>-INT_MAX) {
373 if (pResult) {
374 if (v<=-INT_MAX+1+ValRangeForRandom) v=-INT_MAX+1;
375 else v-=ValRangeForRandom;
376 for (i=0, m=0; i<n; i++) {
377 if (FoundVals[i]>=v) top->Moves[m++]=top->Moves[i];
378 }
379 *pResult=top->Moves[Random(0,m-1)];
380 // fprintf(stderr,"\nfound %d best moves\n",m);
381 }
382 res=true;
383 }
384 }
385 if (SearchMachine!=this) delete SearchMachine;
386 SearchMachine=NULL;
387 SearchStackTop=NULL;
388 }
389 return res;
390 }
391
392
IsCheck() const393 bool SilChessMachine::IsCheck() const
394 {
395 SilChessMachine * m;
396
397 m=(SilChessMachine*)this;
398 if (!m->CachedInfoValid) m->UpdateCachedInfo();
399 return m->CachedIsCheck;
400 }
401
402
IsMate() const403 bool SilChessMachine::IsMate() const
404 {
405 SilChessMachine * m;
406
407 m=(SilChessMachine*)this;
408 if (!m->CachedInfoValid) m->UpdateCachedInfo();
409 return m->CachedIsMate;
410 }
411
412
IsDraw() const413 bool SilChessMachine::IsDraw() const
414 {
415 SilChessMachine * m;
416
417 m=(SilChessMachine*)this;
418 if (!m->CachedInfoValid) m->UpdateCachedInfo();
419 return m->CachedIsDraw;
420 }
421
422
IsEndless() const423 bool SilChessMachine::IsEndless() const
424 {
425 return MoveCount>MAX_MOVE_COUNT-100;
426 }
427
428
GetValue() const429 int SilChessMachine::GetValue() const
430 {
431 SilChessMachine * m;
432
433 m=(SilChessMachine*)this;
434 if (!m->CachedInfoValid) m->UpdateCachedInfo();
435 return m->CachedValue;
436 }
437
438
Save(const char * filename) const439 bool SilChessMachine::Save(const char * filename) const
440 {
441 FILE * f;
442 char tmp[256];
443 int i;
444
445 if ((f=fopen(filename,"wb"))==NULL) return false;
446 fprintf(
447 f,
448 "_SilChess_\n"
449 "search depth: %d\n"
450 "human side: %s\n"
451 "moves:\n",
452 SearchDepth,
453 HumanSide==TF_White ? "white" : "black"
454 );
455 for (i=0; i<GetMoveCount(); i++) {
456 GetMove(i).ToString(tmp);
457 fprintf(f,"%s\n",tmp);
458 }
459 fflush(f);
460 if (ferror(f)) { fclose(f); return false; }
461 fclose(f);
462 return true;
463 }
464
465
Load(const char * filename)466 bool SilChessMachine::Load(const char * filename)
467 {
468 FILE * f;
469 char tmp[256];
470 int i;
471 Move m;
472
473 StartNewGame();
474 if ((f=fopen(filename,"rb"))==NULL) return false;
475 if (!fgets(tmp,256,f)) tmp[0]=0;
476 if (memcmp(tmp,"_SilChess_",10)!=0) goto L_FormatError;
477 if (!fgets(tmp,256,f)) tmp[0]=0;
478 if (memcmp(tmp,"search depth:",13)!=0) goto L_FormatError;
479 for (i=13; tmp[i]!=0 && (unsigned char)tmp[i]<=32; i++);
480 SearchDepth=atoi(tmp+i);
481 if (SearchDepth<0 || SearchDepth>MAX_SEARCH_DEPTH) goto L_FormatError;
482 if (!fgets(tmp,256,f)) tmp[0]=0;
483 if (memcmp(tmp,"human side:",11)!=0) goto L_FormatError;
484 for (i=11; tmp[i]!=0 && (unsigned char)tmp[i]<=32; i++);
485 if (memcmp(tmp+i,"white",5)==0) HumanSide=TF_White;
486 else if (memcmp(tmp+i,"black",5)==0) HumanSide=TF_Black;
487 else goto L_FormatError;
488 if (!fgets(tmp,256,f)) tmp[0]=0;
489 if (memcmp(tmp,"moves:",6)!=0) goto L_FormatError;
490 while (!feof(f)) {
491 tmp[0]=0;
492 if (!fgets(tmp,256,f)) tmp[0]=0;
493 for (i=0; tmp[i]!=0 && (unsigned char)tmp[i]<=32; i++);
494 if (tmp[i]!=0) {
495 if (!m.FromString(tmp+i)) goto L_FormatError;
496 if (!Board[m.Y1*8+m.X1]) goto L_FormatError;
497 DoMove(m);
498 }
499 }
500 if (ferror(f)) {
501 fclose(f);
502 return false;
503 }
504 fclose(f);
505 return true;
506 L_FormatError:
507 fclose(f);
508 return false;
509 }
510
511
Print(Charset charset,const char * lastMove) const512 void SilChessMachine::Print(Charset charset, const char * lastMove) const
513 {
514 switch (charset) {
515 case CS_ASCII : PrintASCII (!IsHumanWhite(),lastMove); break;
516 case CS_ASCII2: PrintASCII2(!IsHumanWhite(),lastMove); break;
517 case CS_ANSI : PrintANSI (!IsHumanWhite(),lastMove); break;
518 case CS_DOS : PrintDOS (!IsHumanWhite(),lastMove); break;
519 case CS_MINI : PrintMINI (!IsHumanWhite(),lastMove); break;
520 }
521 }
522
523
GeneticTraining()524 void SilChessMachine::GeneticTraining()
525 {
526 // This is a Genetic Algorithm for optimizing the valuation factors
527 // (ValFac[]). Computer players with different genes (=valuation
528 // factors) are playing against each other, the best survive and leave
529 // their genes to the next generation.
530 // Coming to the current factors was an interactive process: generate
531 // first factors, modify the code, improve the factors, modify the
532 // code, improve the factors and so on. Highly experimental...
533
534 #define CGT_PopCount 12 // >=4
535 #define CGT_PlayDepth 1
536 #define CGT_PlayMaxMoves 70
537 int Pop[VFI_Count][CGT_PopCount];
538 int PopTmp[VFI_Count][CGT_PopCount];
539 int Fitness[CGT_PopCount];
540 Move move;
541 int i,j,k,l,m;
542
543 StartNewGame();
544 for (j=0; j<CGT_PopCount; j++) for (i=0; i<VFI_Count; i++) {
545 m=ValFac[i];
546 if (Random(0,7)==0) {
547 if (m<=6) m+=Random(-4,4);
548 else m+=Random(-128,128)*m/128/5;
549 }
550 // m=Random(ValFac[i]/4,ValFac[i]*3);
551 // m+=Random(-8,8);
552 if (m>255) m=255; else if (m<0) m=0;
553 Pop[i][j]=m;
554 }
555
556 L_Loop:
557
558 StartNewGame();
559 for (i=0; i<VFI_Count; i++) {
560 Pop[i][CGT_PopCount-1]=ValFac[i];
561 }
562
563 // for (j=0; j<CGT_PopCount; j++) {
564 // Pop[0][j]=ValFac[0];
565 // Pop[1][j]=ValFac[1];
566 // }
567
568
569 printf("New Population:\n");
570 for (j=0; j<CGT_PopCount; j++) {
571 printf("%2d: ",j);
572 for (i=0; i<VFI_Count; i++) {
573 printf("%4d",Pop[i][j]);
574 }
575 printf("\n");
576 }
577
578 for (i=0; i<CGT_PopCount; i++) Fitness[i]=0;
579 for (i=0; i<CGT_PopCount; i++) {
580 printf("%2d:",i);
581 for (j=0; j<CGT_PopCount; j++) if (i!=j) {
582 StartNewGame();
583 for (l=0; l<CGT_PlayMaxMoves; l++) {
584 for (k=0; k<VFI_Count; k++) ValFac[k]=Pop[k][i];
585 SetSearchDepth(i==CGT_PopCount-1 ? CGT_PlayDepth+2 : CGT_PlayDepth);
586 // SetSearchDepth(playDepth);
587 if (!SearchMove(&move)) break;
588 DoMove(move);
589 for (k=0; k<VFI_Count; k++) ValFac[k]=Pop[k][j];
590 SetSearchDepth(j==CGT_PopCount-1 ? CGT_PlayDepth+2 : CGT_PlayDepth);
591 // SetSearchDepth(playDepth);
592 if (!SearchMove(&move)) break;
593 DoMove(move);
594 }
595 m=0;
596 if (l<CGT_PlayMaxMoves) {
597 if (Turn&TF_Black) m+=100; else m-=100;
598 printf("M");
599 }
600 else printf(" ");
601 for (k=0; k<32; k++) if (Pieces[k].Type) {
602 if (Pieces[k].Type&TF_White) m+=Pieces[k].Value;
603 else m-=Pieces[k].Value;
604 }
605 printf("%4d ",m); fflush(stdout);
606 Fitness[i]+=m; // if (m>0) Fitness[i]+=m;
607 Fitness[j]-=m; // if (m<0) Fitness[j]-=m;
608 }
609 printf("\n");
610 }
611 printf("Fitness:\n");
612 for (j=0; j<CGT_PopCount; j++) {
613 printf("%2d: ",j);
614 for (i=0; i<VFI_Count; i++) {
615 printf("%4d",Pop[i][j]);
616 }
617 printf(" = %d\n",Fitness[j]);
618 }
619
620 for (j=0; j<CGT_PopCount; j++) for (i=0; i<VFI_Count; i++) {
621 PopTmp[i][j]=Pop[i][j];
622 }
623 for (j=0; j<CGT_PopCount/2; j++) {
624 m=Fitness[0]; k=0;
625 // for (i=1; i<CGT_PopCount; i++) {
626 for (i=1; i<CGT_PopCount-1; i++) {
627 if (m<Fitness[i]) { m=Fitness[i]; k=i; }
628 }
629 Fitness[k]=INT_MIN;
630 for (i=0; i<VFI_Count; i++) {
631 Pop[i][j]=PopTmp[i][k];
632 }
633 }
634 if (Fitness[0]!=INT_MIN) {
635 for (i=0; i<VFI_Count; i++) {
636 Pop[i][CGT_PopCount/2-1]=PopTmp[i][0];
637 }
638 }
639
640 for (j=CGT_PopCount/2; j<CGT_PopCount ;j++) {
641 k=Random(0,CGT_PopCount/2-1);
642 l=Random(0,CGT_PopCount/2-2);
643 if (l>=k) l++;
644 for (i=0; i<VFI_Count; i++) {
645 if (Random(0,1)) m=Pop[i][k]; else m=Pop[i][l];
646 if (Random(0,7)==0) {
647 if (m<=12) m+=Random(-2,2);
648 else m+=Random(-128,128)*m/128/10;
649 }
650
651 if (m>255) m=255; else if (m<1) m=1;
652 Pop[i][j]=m;
653 }
654 }
655
656 goto L_Loop;
657 }
658
659
UpdateCachedInfo()660 void SilChessMachine::UpdateCachedInfo()
661 {
662 CachedIsCheck=IsCheck(false);
663 if (!IsAnyLegalMove()) {
664 CachedIsMate=CachedIsCheck;
665 CachedIsDraw=!CachedIsCheck;
666 }
667 else {
668 CachedIsMate=false;
669 CachedIsDraw=false;
670 }
671 CachedValue=Value();
672 CachedInfoValid=true;
673 }
674
675
SortMoves(Move * m,int count) const676 void SilChessMachine::SortMoves(Move * m, int count) const
677 {
678 int lr[512*2];
679 int * p;
680 int v[512];
681 int vm,tv;
682 int i,j;
683 Move tpm;
684
685 for (i=0; i<count; i++) {
686 ((SilChessMachine*)this)->TBStart();
687 ((SilChessMachine*)this)->TBDoMove(m[i]);
688 if (IsCheck(true)) v[i]=INT_MAX;
689 else v[i]=Value();
690 ((SilChessMachine*)this)->TakeBack();
691 }
692
693 p=lr; p[0]=0; p[1]=count-1;
694 for (;;) {
695 i=p[0]; j=p[1]; vm=v[(i+j)/2];
696 for (;;) {
697 while (v[i]<vm) i++;
698 while (v[j]>vm) j--;
699 if (i>=j) break;
700 if (v[i]!=v[j]) {
701 tpm=m[i]; m[i]=m[j]; m[j]=tpm;
702 tv =v[i]; v[i]=v[j]; v[j]=tv ;
703 }
704 i++; j--;
705 }
706 while (i<p[1] && v[i]==vm) i++;
707 while (j>p[0] && v[j]==vm) j--;
708 if (i<p[1]) {
709 if (j>p[0]) {
710 p[2]=p[0];
711 p[3]=j;
712 p[0]=i;
713 p+=2;
714 }
715 else p[0]=i;
716 }
717 else if (j>p[0]) p[1]=j;
718 else if (p>lr) p-=2;
719 else break;
720 }
721 }
722
723
Value() const724 int SilChessMachine::Value() const
725 {
726 int v;
727 int i;
728
729 // Value the whole situation from sight of the one who is on.
730
731 for (v=0, i=0; i<32; i++) if (Pieces[i].Type) v+=ValuePiece(Pieces[i]);
732 return v;
733 }
734
735
ValuePiece(const Piece & p) const736 int SilChessMachine::ValuePiece(const Piece & p) const
737 {
738 int v;
739
740 // Value the piece from sight of the one who is on.
741
742 v =
743 p.Value*ValFac[VFI_Piece] +
744 ValuePayingHit(p) +
745 ValueThreats(p) +
746 ValueMobility(p) +
747 ValueTies(p) +
748 ValueCenter(p) +
749 ValueKing(p) +
750 ValuePawn(p)
751 ;
752 if (!(p.Type&Turn)) v=-v;
753 return v;
754 }
755
756
ValuePayingHit(const Piece & p) const757 int SilChessMachine::ValuePayingHit(const Piece & p) const
758 {
759 Piece * n[16];
760 int w[32];
761 int v;
762 int t,f,i,k;
763
764 // Value how worth it is to hit piece p.
765
766 for (i=0; i<16; i++) n[i]=p.N[i];
767 t=(~p.Type)&(TF_White|TF_Black);
768 k=0;
769 w[k]=p.Value;
770 goto L_Loop;
771
772 L_Hit:
773 k++;
774 w[k]=n[i]->Value;
775 if (i&1) n[i]=NULL; else n[i]=n[i]->N[i];
776 t^=TF_White|TF_Black;
777
778 L_Loop:
779 if (t==TF_White) {
780 if (n[6] && n[6]->Type==(TF_Pawn|TF_White) &&
781 n[6]->Y==p.Y+1) { i=6; goto L_Hit; }
782 if (n[2] && n[2]->Type==(TF_Pawn|TF_White) &&
783 n[2]->Y==p.Y+1) { i=2; goto L_Hit; }
784 }
785 else {
786 if (n[10] && n[10]->Type==(TF_Pawn|TF_Black) &&
787 n[10]->Y==p.Y-1) { i=10; goto L_Hit; }
788 if (n[14] && n[14]->Type==(TF_Pawn|TF_Black) &&
789 n[14]->Y==p.Y-1) { i=14; goto L_Hit; }
790 }
791
792 f=t|TF_Knight;
793 if (n[ 1] && n[ 1]->Type==f) { i= 1; goto L_Hit; }
794 if (n[ 3] && n[ 3]->Type==f) { i= 3; goto L_Hit; }
795 if (n[ 5] && n[ 5]->Type==f) { i= 5; goto L_Hit; }
796 if (n[ 7] && n[ 7]->Type==f) { i= 7; goto L_Hit; }
797 if (n[ 9] && n[ 9]->Type==f) { i= 9; goto L_Hit; }
798 if (n[11] && n[11]->Type==f) { i=11; goto L_Hit; }
799 if (n[13] && n[13]->Type==f) { i=13; goto L_Hit; }
800 if (n[15] && n[15]->Type==f) { i=15; goto L_Hit; }
801
802 f=t|TF_Bishop;
803 if (n[ 2] && n[ 2]->Type==f) { i= 2; goto L_Hit; }
804 if (n[ 6] && n[ 6]->Type==f) { i= 6; goto L_Hit; }
805 if (n[10] && n[10]->Type==f) { i=10; goto L_Hit; }
806 if (n[14] && n[14]->Type==f) { i=14; goto L_Hit; }
807
808 f=t|TF_Rook;
809 if (n[ 0] && n[ 0]->Type==f) { i= 0; goto L_Hit; }
810 if (n[ 4] && n[ 4]->Type==f) { i= 4; goto L_Hit; }
811 if (n[ 8] && n[ 8]->Type==f) { i= 8; goto L_Hit; }
812 if (n[12] && n[12]->Type==f) { i=12; goto L_Hit; }
813
814 f=t|TF_Queen;
815 if (n[ 0] && n[ 0]->Type==f) { i= 0; goto L_Hit; }
816 if (n[ 2] && n[ 2]->Type==f) { i= 2; goto L_Hit; }
817 if (n[ 4] && n[ 4]->Type==f) { i= 4; goto L_Hit; }
818 if (n[ 6] && n[ 6]->Type==f) { i= 6; goto L_Hit; }
819 if (n[ 8] && n[ 8]->Type==f) { i= 8; goto L_Hit; }
820 if (n[10] && n[10]->Type==f) { i=10; goto L_Hit; }
821 if (n[12] && n[12]->Type==f) { i=12; goto L_Hit; }
822 if (n[14] && n[14]->Type==f) { i=14; goto L_Hit; }
823
824 f=t|TF_King;
825 if (n[ 0] && n[ 0]->Type==f && n[ 0]->X==p.X+1) { i= 0; goto L_Hit; }
826 if (n[ 2] && n[ 2]->Type==f && n[ 2]->X==p.X+1) { i= 2; goto L_Hit; }
827 if (n[ 4] && n[ 4]->Type==f && n[ 4]->Y==p.Y+1) { i= 4; goto L_Hit; }
828 if (n[ 6] && n[ 6]->Type==f && n[ 6]->Y==p.Y+1) { i= 6; goto L_Hit; }
829 if (n[ 8] && n[ 8]->Type==f && n[ 8]->X==p.X-1) { i= 8; goto L_Hit; }
830 if (n[10] && n[10]->Type==f && n[10]->X==p.X-1) { i=10; goto L_Hit; }
831 if (n[12] && n[12]->Type==f && n[12]->Y==p.Y-1) { i=12; goto L_Hit; }
832 if (n[14] && n[14]->Type==f && n[14]->Y==p.Y-1) { i=14; goto L_Hit; }
833
834 v=0;
835 while (k>0) {
836 k--;
837 v=w[k]-v;
838 if (v<0) v=0;
839 }
840 return -v * ValFac[(p.Type&Turn) ? VFI_PayingTurnOppo : VFI_PayingTurn];
841 }
842
843
ValueThreats(const Piece & p) const844 int SilChessMachine::ValueThreats(const Piece & p) const
845 {
846 const Piece * const * n;
847 int v,type;
848
849 // Value how many pieces are threatened or covered by piece p.
850
851 type=p.Type; n=p.N;
852 v=0;
853 if (type&TF_Pawn) {
854 if (type&TF_Black) {
855 if (n[2] && n[2]->Y==p.Y+1) v++;
856 if (n[6] && n[6]->Y==p.Y+1) v++;
857 }
858 else {
859 if (n[10] && n[10]->Y==p.Y-1) v++;
860 if (n[14] && n[14]->Y==p.Y-1) v++;
861 }
862 }
863 else if (type&(TF_Bishop|TF_Rook|TF_Queen)) {
864 if (type&(TF_Rook|TF_Queen)) {
865 if (n[ 0]) v++;
866 if (n[ 4]) v++;
867 if (n[ 8]) v++;
868 if (n[12]) v++;
869 }
870 if (type&(TF_Bishop|TF_Queen)) {
871 if (n[ 2]) v++;
872 if (n[ 6]) v++;
873 if (n[10]) v++;
874 if (n[14]) v++;
875 }
876 }
877 else if (type&TF_Knight) {
878 if (n[ 1]) v++;
879 if (n[ 3]) v++;
880 if (n[ 5]) v++;
881 if (n[ 7]) v++;
882 if (n[ 9]) v++;
883 if (n[11]) v++;
884 if (n[13]) v++;
885 if (n[15]) v++;
886 }
887 else if (type&TF_King) {
888 if (n[ 0] && n[ 0]->X==p.X+1) v++;
889 if (n[ 2] && n[ 2]->X==p.X+1) v++;
890 if (n[ 4] && n[ 4]->Y==p.Y+1) v++;
891 if (n[ 6] && n[ 6]->Y==p.Y+1) v++;
892 if (n[ 8] && n[ 8]->X==p.X-1) v++;
893 if (n[10] && n[10]->X==p.X-1) v++;
894 if (n[12] && n[12]->Y==p.Y-1) v++;
895 if (n[14] && n[14]->Y==p.Y-1) v++;
896 }
897
898 return v * ValFac[VFI_Threats];
899 }
900
901
ValueMobility(const Piece & p) const902 int SilChessMachine::ValueMobility(const Piece & p) const
903 {
904 const Piece * const * n;
905 int v,x,y,type;
906
907 // Value the mobility of piece p.
908
909 type=p.Type; x=p.X; y=p.Y; n=p.N; v=0;
910 if (type&TF_Pawn) {
911 if (type&TF_Black) {
912 if (n[4]) v=n[4]->Y-y-1; else v=7-y;
913 if (y==1) { if (v>2) v=2; } else { if (v>1) v=1; }
914 }
915 else {
916 if (n[12]) v=y-n[12]->Y-1; else v=y;
917 if (y==6) { if (v>2) v=2; } else { if (v>1) v=1; }
918 }
919 }
920 else if (type&(TF_Bishop|TF_Rook|TF_Queen)) {
921 if (type&(TF_Rook|TF_Queen)) {
922 if (n[ 0]) v+=n[ 0]->X-x-1; else v+=7-x;
923 if (n[ 4]) v+=n[ 4]->Y-y-1; else v+=7-y;
924 if (n[ 8]) v+=x-n[ 8]->X-1; else v+=x;
925 if (n[12]) v+=y-n[12]->Y-1; else v+=y;
926 }
927 if (type&(TF_Bishop|TF_Queen)) {
928 if (n[ 2]) v+=n[ 2]->X-x-1; else if (x>=y ) v+=7-x; else v+=7-y;
929 if (n[ 6]) v+=x-n[ 6]->X-1; else if (x<=7-y) v+=x ; else v+=7-y;
930 if (n[10]) v+=x-n[10]->X-1; else if (x<=y ) v+=x ; else v+=y ;
931 if (n[14]) v+=n[14]->X-x-1; else if (7-x<=y) v+=7-x; else v+=y ;
932 }
933 }
934 else if (type&TF_Knight) {
935 if (x>0) {
936 if (y<6 && !n[5]) v++;
937 if (y>1 && !n[11]) v++;
938 if (x>1) {
939 if (y<7 && !n[7]) v++;
940 if (y>0 && !n[9]) v++;
941 }
942 }
943 if (x<7) {
944 if (y<6 && !n[3]) v++;
945 if (y>1 && !n[13]) v++;
946 if (x<6) {
947 if (y<7 && !n[1]) v++;
948 if (y>0 && !n[15]) v++;
949 }
950 }
951 }
952 return v * ValFac[VFI_Mobility];
953 }
954
955
ValueTies(const Piece & p) const956 int SilChessMachine::ValueTies(const Piece & p) const
957 {
958 const Piece * const * n;
959 int v;
960 int t;
961
962 // Value ties of the enemy by piece p.
963
964 if (!(p.Type&(TF_Bishop|TF_Rook|TF_Queen))) return 0;
965 v=0;
966 n=p.N;
967 t=p.Type&(TF_White|TF_Black);
968 if (p.Type&(TF_Rook|TF_Queen)) {
969 if (n[0] && n[0]->N[0] && !(n[0]->Type&t) && !(n[0]->N[0]->Type&t))
970 v+=n[0]->Value+n[0]->N[0]->Value;
971 if (n[4] && n[4]->N[4] && !(n[4]->Type&t) && !(n[4]->N[4]->Type&t))
972 v+=n[4]->Value+n[4]->N[4]->Value;
973 if (n[8] && n[8]->N[8] && !(n[8]->Type&t) && !(n[8]->N[8]->Type&t))
974 v+=n[8]->Value+n[8]->N[8]->Value;
975 if (n[12] && n[12]->N[12] && !(n[12]->Type&t) && !(n[12]->N[12]->Type&t))
976 v+=n[12]->Value+n[12]->N[12]->Value;
977 }
978 if (p.Type&(TF_Bishop|TF_Queen)) {
979 if (n[2] && n[2]->N[2] && !(n[2]->Type&t) && !(n[2]->N[2]->Type&t))
980 v+=n[2]->Value+n[2]->N[2]->Value;
981 if (n[6] && n[6]->N[6] && !(n[6]->Type&t) && !(n[6]->N[6]->Type&t))
982 v+=n[6]->Value+n[6]->N[6]->Value;
983 if (n[10] && n[10]->N[10] && !(n[10]->Type&t) && !(n[10]->N[10]->Type&t))
984 v+=n[10]->Value+n[10]->N[10]->Value;
985 if (n[14] && n[14]->N[14] && !(n[14]->Type&t) && !(n[14]->N[14]->Type&t))
986 v+=n[14]->Value+n[14]->N[14]->Value;
987 }
988
989 return (v * ValFac[VFI_Ties])/2;
990 }
991
992
ValueCenter(const Piece & p) const993 int SilChessMachine::ValueCenter(const Piece & p) const
994 {
995 int x,y;
996
997 // Value how centered piece p is on the board.
998
999 x=p.X; if (x>3) x=7-x;
1000 y=p.Y; if (y>3) y=7-y;
1001 if (x>y) x=y;
1002 return x * ValFac[VFI_Center];
1003 }
1004
1005
ValueKing(const Piece & p) const1006 int SilChessMachine::ValueKing(const Piece & p) const
1007 {
1008 const Piece * const * n;
1009 int v;
1010 int t,X,Y,i,j;
1011
1012 // Value the king: Is he well guarded, centered, mobile and not in check?
1013
1014 if (!(p.Type&TF_King)) return 0;
1015
1016 v=0; n=p.N; X=p.X; Y=p.Y;
1017 t=(~p.Type)&(TF_White|TF_Black);
1018
1019 i=0;
1020 if (n[ 0]) { if (n[ 0]->Type&t) i+=7; else i+=n[ 0]->X-X-1; }
1021 else i+=7-X;
1022 if (n[ 4]) { if (n[ 4]->Type&t) i+=7; else i+=n[ 4]->Y-Y-1; }
1023 else i+=7-Y;
1024 if (n[ 8]) { if (n[ 8]->Type&t) i+=7; else i+=X-n[ 8]->X-1; }
1025 else i+=X;
1026 if (n[12]) { if (n[12]->Type&t) i+=7; else i+=Y-n[12]->Y-1; }
1027 else i+=Y;
1028 if (n[ 2]) { if (n[ 2]->Type&t) i+=7; else i+=n[ 2]->X-X-1; }
1029 else if (X>=Y ) i+=7-X; else i+=7-Y;
1030 if (n[ 6]) { if (n[ 6]->Type&t) i+=7; else i+=X-n[ 6]->X-1; }
1031 else if (X<=7-Y) i+=X ; else i+=7-Y;
1032 if (n[10]) { if (n[10]->Type&t) i+=7; else i+=X-n[10]->X-1; }
1033 else if (X<=Y ) i+=X ; else i+=Y ;
1034 if (n[14]) { if (n[14]->Type&t) i+=7; else i+=n[14]->X-X-1; }
1035 else if (7-X<=Y) i+=7-X; else i+=Y ;
1036 v-=i*ValFac[VFI_KingCover];
1037
1038 i=0;
1039 if (X<7) {
1040 if (!n[0] || n[0]->X>X+1) i++;
1041 if (Y<7 && (!n[2] || n[2]->X>X+1)) i++;
1042 }
1043 if (Y<7) {
1044 if (!n[4] || n[4]->Y>Y+1) i++;
1045 if (X>0 && (!n[6] || n[6]->Y>Y+1)) i++;
1046 }
1047 if (X>0) {
1048 if (!n[8] || n[8]->X<X-1) i++;
1049 if (Y>0 && (!n[10] || n[10]->X<X-1)) i++;
1050 }
1051 if (Y>0) {
1052 if (!n[12] || n[12]->Y<Y-1) i++;
1053 if (X<7 && (!n[14] || n[14]->Y<Y-1)) i++;
1054 }
1055 v+=i*ValFac[VFI_KingMobility];
1056
1057 i=X; if (i>3) i=7-i;
1058 j=Y; if (j>3) j=7-j;
1059 if (i>j) i=j;
1060 v-=i*ValFac[VFI_KingNotCentered];
1061
1062 if (IsThreatened(p.X,p.Y,t)) v-=ValFac[VFI_KingCheck];
1063
1064 return v;
1065 }
1066
1067
ValuePawn(const Piece & p) const1068 int SilChessMachine::ValuePawn(const Piece & p) const
1069 {
1070 const Piece * const * n;
1071 int v;
1072 int t;
1073
1074 // Value the pawn: Are there no gabs between the pawns? And will
1075 // he become a queen soon?
1076
1077 t=p.Type;
1078 if (!(t&TF_Pawn)) return 0;
1079 v=0;
1080 n=p.N;
1081 if (
1082 (n[ 0] && n[ 0]->Type==t && n[ 0]->X==p.X+1) ||
1083 (n[ 2] && n[ 2]->Type==t && n[ 2]->X==p.X+1) ||
1084 (n[14] && n[14]->Type==t && n[14]->X==p.X+1) ||
1085 (n[13] && n[13]->Type==t ) ||
1086 (n[ 3] && n[ 3]->Type==t )
1087 ) v+=ValFac[VFI_PawnBeside];
1088 if (t&TF_White) {
1089 v+=(7-p.Y)*ValFac[VFI_PawnOnward];
1090 if (p.Y==1) {
1091 v+=ValFac[VFI_PawnHeaven];
1092 if (!n[12]) v+=ValFac[VFI_PawnHeaven];
1093 }
1094 }
1095 else {
1096 v+=p.Y*ValFac[VFI_PawnOnward];
1097 if (p.Y==6) {
1098 v+=ValFac[VFI_PawnHeaven];
1099 if (!n[4]) v+=ValFac[VFI_PawnHeaven];
1100 }
1101 }
1102 return v;
1103 }
1104
1105
IsAnyLegalMove() const1106 bool SilChessMachine::IsAnyLegalMove() const
1107 {
1108 Move m[512];
1109 int mc,i;
1110 bool check;
1111 SilChessMachine * machine;
1112
1113 mc=EnumeratePossibleMoves(m);
1114 machine=(SilChessMachine*)this;
1115 for (i=0; i<mc; i++) {
1116 machine->TBStart();
1117 machine->TBDoMove(m[i]);
1118 check=machine->IsCheck(true);
1119 machine->TakeBack();
1120 if (!check) return true;
1121 }
1122 return false;
1123 }
1124
1125
IsCheck(bool invertTurn) const1126 bool SilChessMachine::IsCheck(bool invertTurn) const
1127 {
1128 int i,side,king;
1129
1130 if (!invertTurn) {
1131 king=TF_King|Turn;
1132 side=Turn^(TF_White|TF_Black);
1133 }
1134 else {
1135 king=TF_King|(Turn^(TF_White|TF_Black));
1136 side=Turn;
1137 }
1138 for (i=0; i<32; i++) {
1139 if (Pieces[i].Type==king) {
1140 return IsThreatened(Pieces[i].X,Pieces[i].Y,side);
1141 }
1142 }
1143 return false;
1144 }
1145
1146
EnumeratePossibleMoves(Move * buf) const1147 int SilChessMachine::EnumeratePossibleMoves(Move * buf) const
1148 {
1149 const Piece * p, * pend;
1150 Move * m;
1151 int x1,y1,x2,y2,x,y;
1152
1153 # define SCMEPM_ADD_MOVE(x1,y1,x2,y2) \
1154 ( \
1155 m->X1=(signed char)(x1), \
1156 m->Y1=(signed char)(y1), \
1157 m->X2=(signed char)(x2), \
1158 m->Y2=(signed char)(y2), \
1159 m++ \
1160 )
1161
1162 m=buf;
1163 for (p=Pieces, pend=Pieces+32; p<pend; p++) if (p->Type&Turn) {
1164 x1=p->X;
1165 y1=p->Y;
1166 if (p->Type&TF_Pawn) {
1167 if (Turn==TF_Black) {
1168 y2=7; if (p->N[4]) y2=p->N[4]->Y-1;
1169 if (y1<y2) {
1170 SCMEPM_ADD_MOVE(x1,y1,x1,y1+1);
1171 }
1172 if (y1==1 && y1+2<=y2) {
1173 SCMEPM_ADD_MOVE(x1,y1,x1,y1+2);
1174 }
1175 if ((p->N[2] && p->N[2]->X==x1+1 && (p->N[2]->Type&TF_White)) ||
1176 (y1==4 && p->N[0] && p->N[0]->X==x1+1 &&
1177 p->N[0]->Type==(TF_Pawn|TF_White) &&
1178 MoveCount>0 && Moves[MoveCount-1].Y1==6 &&
1179 Moves[MoveCount-1].Y2==4 && Moves[MoveCount-1].X2==x1+1)) {
1180 SCMEPM_ADD_MOVE(x1,y1,x1+1,y1+1);
1181 }
1182 if ((p->N[6] && p->N[6]->X==x1-1 && (p->N[6]->Type&TF_White)) ||
1183 (y1==4 && p->N[8] && p->N[8]->X==x1-1 &&
1184 p->N[8]->Type==(TF_Pawn|TF_White) &&
1185 MoveCount>0 && Moves[MoveCount-1].Y1==6 &&
1186 Moves[MoveCount-1].Y2==4 && Moves[MoveCount-1].X2==x1-1)) {
1187 SCMEPM_ADD_MOVE(x1,y1,x1-1,y1+1);
1188 }
1189 }
1190 else {
1191 y2=0; if (p->N[12]) y2=p->N[12]->Y+1;
1192 if (y1>y2) {
1193 SCMEPM_ADD_MOVE(x1,y1,x1,y1-1);
1194 }
1195 if (y1==6 && y1-2>=y2) {
1196 SCMEPM_ADD_MOVE(x1,y1,x1,y1-2);
1197 }
1198 if ((p->N[14] && p->N[14]->X==x1+1 && (p->N[14]->Type&TF_Black)) ||
1199 (y1==3 && p->N[0] && p->N[0]->X==x1+1 &&
1200 p->N[0]->Type==(TF_Pawn|TF_Black) &&
1201 MoveCount>0 && Moves[MoveCount-1].Y1==1 &&
1202 Moves[MoveCount-1].Y2==3 && Moves[MoveCount-1].X2==x1+1)) {
1203 SCMEPM_ADD_MOVE(x1,y1,x1+1,y1-1);
1204 }
1205 if ((p->N[10] && p->N[10]->X==x1-1 && (p->N[10]->Type&TF_Black)) ||
1206 (y1==3 && p->N[8] && p->N[8]->X==x1-1 &&
1207 p->N[8]->Type==(TF_Pawn|TF_Black) &&
1208 MoveCount>0 && Moves[MoveCount-1].Y1==1 &&
1209 Moves[MoveCount-1].Y2==3 && Moves[MoveCount-1].X2==x1-1)) {
1210 SCMEPM_ADD_MOVE(x1,y1,x1-1,y1-1);
1211 }
1212 }
1213 }
1214 else if (p->Type&(TF_Bishop|TF_Rook|TF_Queen)) {
1215 if (p->Type&(TF_Rook|TF_Queen)) {
1216 x2=7; if (p->N[ 0]) { x2=p->N[ 0]->X; if (p->N[ 0]->Type&Turn) x2--; }
1217 for (x=x1+1; x<=x2; x++) SCMEPM_ADD_MOVE(x1,y1,x,y1);
1218 y2=7; if (p->N[ 4]) { y2=p->N[ 4]->Y; if (p->N[ 4]->Type&Turn) y2--; }
1219 for (y=y1+1; y<=y2; y++) SCMEPM_ADD_MOVE(x1,y1,x1,y);
1220 x2=0; if (p->N[ 8]) { x2=p->N[ 8]->X; if (p->N[ 8]->Type&Turn) x2++; }
1221 for (x=x1-1; x>=x2; x--) SCMEPM_ADD_MOVE(x1,y1,x,y1);
1222 y2=0; if (p->N[12]) { y2=p->N[12]->Y; if (p->N[12]->Type&Turn) y2++; }
1223 for (y=y1-1; y>=y2; y--) SCMEPM_ADD_MOVE(x1,y1,x1,y);
1224 }
1225 if (p->Type&(TF_Bishop|TF_Queen)) {
1226 x2=7; if (p->N[ 2]) { x2=p->N[ 2]->X; if (p->N[ 2]->Type&Turn) x2--; }
1227 if (x2>x1+7-y1) x2=x1+7-y1;
1228 for (x=x1+1; x<=x2; x++) SCMEPM_ADD_MOVE(x1,y1,x,y1+x-x1);
1229 x2=0; if (p->N[ 6]) { x2=p->N[ 6]->X; if (p->N[ 6]->Type&Turn) x2++; }
1230 if (x2<x1+y1-7) x2=x1+y1-7;
1231 for (x=x1-1; x>=x2; x--) SCMEPM_ADD_MOVE(x1,y1,x,y1+x1-x);
1232 x2=0; if (p->N[10]) { x2=p->N[10]->X; if (p->N[10]->Type&Turn) x2++; }
1233 if (x2<x1-y1) x2=x1-y1;
1234 for (x=x1-1; x>=x2; x--) SCMEPM_ADD_MOVE(x1,y1,x,y1+x-x1);
1235 x2=7; if (p->N[14]) { x2=p->N[14]->X; if (p->N[14]->Type&Turn) x2--; }
1236 if (x2>x1+y1) x2=x1+y1;
1237 for (x=x1+1; x<=x2; x++) SCMEPM_ADD_MOVE(x1,y1,x,y1+x1-x);
1238 }
1239 }
1240 else if (p->Type&TF_Knight) {
1241 if (x1>0) {
1242 if (y1<6 && (!p->N[5] || !(p->N[5]->Type&Turn))) {
1243 SCMEPM_ADD_MOVE(x1,y1,x1-1,y1+2);
1244 }
1245 if (y1>1 && (!p->N[11] || !(p->N[11]->Type&Turn))) {
1246 SCMEPM_ADD_MOVE(x1,y1,x1-1,y1-2);
1247 }
1248 if (x1>1) {
1249 if (y1<7 && (!p->N[7] || !(p->N[7]->Type&Turn))) {
1250 SCMEPM_ADD_MOVE(x1,y1,x1-2,y1+1);
1251 }
1252 if (y1>0 && (!p->N[9] || !(p->N[9]->Type&Turn))) {
1253 SCMEPM_ADD_MOVE(x1,y1,x1-2,y1-1);
1254 }
1255 }
1256 }
1257 if (x1<7) {
1258 if (y1<6 && (!p->N[3] || !(p->N[3]->Type&Turn))) {
1259 SCMEPM_ADD_MOVE(x1,y1,x1+1,y1+2);
1260 }
1261 if (y1>1 && (!p->N[13] || !(p->N[13]->Type&Turn))) {
1262 SCMEPM_ADD_MOVE(x1,y1,x1+1,y1-2);
1263 }
1264 if (x1<6) {
1265 if (y1<7 && (!p->N[1] || !(p->N[1]->Type&Turn))) {
1266 SCMEPM_ADD_MOVE(x1,y1,x1+2,y1+1);
1267 }
1268 if (y1>0 && (!p->N[15] || !(p->N[15]->Type&Turn))) {
1269 SCMEPM_ADD_MOVE(x1,y1,x1+2,y1-1);
1270 }
1271 }
1272 }
1273 }
1274 else if (p->Type&TF_King) {
1275 if (x1<7) {
1276 if (!p->N[0] || p->N[0]->X>x1+1 || !(p->N[0]->Type&Turn)) {
1277 SCMEPM_ADD_MOVE(x1,y1,x1+1,y1);
1278 }
1279 if (y1<7 && (!p->N[2] || p->N[2]->X>x1+1 || !(p->N[2]->Type&Turn))) {
1280 SCMEPM_ADD_MOVE(x1,y1,x1+1,y1+1);
1281 }
1282 }
1283 if (y1<7) {
1284 if (!p->N[4] || p->N[4]->Y>y1+1 || !(p->N[4]->Type&Turn)) {
1285 SCMEPM_ADD_MOVE(x1,y1,x1,y1+1);
1286 }
1287 if (x1>0 && (!p->N[6] || p->N[6]->Y>y1+1 || !(p->N[6]->Type&Turn))) {
1288 SCMEPM_ADD_MOVE(x1,y1,x1-1,y1+1);
1289 }
1290 }
1291 if (x1>0) {
1292 if (!p->N[8] || p->N[8]->X<x1-1 || !(p->N[8]->Type&Turn)) {
1293 SCMEPM_ADD_MOVE(x1,y1,x1-1,y1);
1294 }
1295 if (y1>0 && (!p->N[10] || p->N[10]->X<x1-1 || !(p->N[10]->Type&Turn))) {
1296 SCMEPM_ADD_MOVE(x1,y1,x1-1,y1-1);
1297 }
1298 }
1299 if (y1>0) {
1300 if (!p->N[12] || p->N[12]->Y<y1-1 || !(p->N[12]->Type&Turn)) {
1301 SCMEPM_ADD_MOVE(x1,y1,x1,y1-1);
1302 }
1303 if (x1<7 && (!p->N[14] || p->N[14]->Y<y1-1 || !(p->N[14]->Type&Turn))) {
1304 SCMEPM_ADD_MOVE(x1,y1,x1+1,y1-1);
1305 }
1306 }
1307 if ((p->State&SF_CanCastle) && x1==4) {
1308 if (p->N[0] && (p->N[0]->State&SF_CanCastle) &&
1309 !IsThreatened(x1,y1,Turn^(TF_White|TF_Black)) &&
1310 !IsThreatened(x1+1,y1,Turn^(TF_White|TF_Black))) {
1311 SCMEPM_ADD_MOVE(x1,y1,x1+2,y1);
1312 }
1313 if (p->N[8] && (p->N[8]->State&SF_CanCastle) &&
1314 !IsThreatened(x1,y1,Turn^(TF_White|TF_Black)) &&
1315 !IsThreatened(x1-1,y1,Turn^(TF_White|TF_Black))) {
1316 SCMEPM_ADD_MOVE(x1,y1,x1-2,y1);
1317 }
1318 }
1319 }
1320 }
1321 return m-buf;
1322 }
1323
1324
IsThreatened(int x,int y,int tside) const1325 bool SilChessMachine::IsThreatened(int x, int y, int tside) const
1326 {
1327 Piece * nbuf[16];
1328 Piece * const * n;
1329 const Piece * p;
1330
1331 p=Board[y*8+x];
1332 if (p) n=p->N; else { CalcNeighbours(x,y,nbuf); n=nbuf; }
1333 p=n[1];
1334 if (p && p->Type==(TF_Knight|tside)) goto L_Threatened;
1335 p=n[3];
1336 if (p && p->Type==(TF_Knight|tside)) goto L_Threatened;
1337 p=n[5];
1338 if (p && p->Type==(TF_Knight|tside)) goto L_Threatened;
1339 p=n[7];
1340 if (p && p->Type==(TF_Knight|tside)) goto L_Threatened;
1341 p=n[9];
1342 if (p && p->Type==(TF_Knight|tside)) goto L_Threatened;
1343 p=n[11];
1344 if (p && p->Type==(TF_Knight|tside)) goto L_Threatened;
1345 p=n[13];
1346 if (p && p->Type==(TF_Knight|tside)) goto L_Threatened;
1347 p=n[15];
1348 if (p && p->Type==(TF_Knight|tside)) goto L_Threatened;
1349 p=n[0];
1350 if (p && (p->Type&tside)) {
1351 if (p->Type&(TF_Queen|TF_Rook)) goto L_Threatened;
1352 if ((p->Type&TF_King) && p->X==x+1) goto L_Threatened;
1353 }
1354 p=n[4];
1355 if (p && (p->Type&tside)) {
1356 if (p->Type&(TF_Queen|TF_Rook)) goto L_Threatened;
1357 if ((p->Type&TF_King) && p->Y==y+1) goto L_Threatened;
1358 }
1359 p=n[8];
1360 if (p && (p->Type&tside)) {
1361 if (p->Type&(TF_Queen|TF_Rook)) goto L_Threatened;
1362 if ((p->Type&TF_King) && p->X==x-1) goto L_Threatened;
1363 }
1364 p=n[12];
1365 if (p && (p->Type&tside)) {
1366 if (p->Type&(TF_Queen|TF_Rook)) goto L_Threatened;
1367 if ((p->Type&TF_King) && p->Y==y-1) goto L_Threatened;
1368 }
1369 p=n[2];
1370 if (p && (p->Type&tside)) {
1371 if (p->Type&(TF_Queen|TF_Bishop)) goto L_Threatened;
1372 if (p->X==x+1) {
1373 if (p->Type&TF_King) goto L_Threatened;
1374 if (p->Type==(TF_Pawn|TF_White)) goto L_Threatened;
1375 }
1376 }
1377 p=n[6];
1378 if (p && (p->Type&tside)) {
1379 if (p->Type&(TF_Queen|TF_Bishop)) goto L_Threatened;
1380 if (p->X==x-1) {
1381 if (p->Type&TF_King) goto L_Threatened;
1382 if (p->Type==(TF_Pawn|TF_White)) goto L_Threatened;
1383 }
1384 }
1385 p=n[10];
1386 if (p && (p->Type&tside)) {
1387 if (p->Type&(TF_Queen|TF_Bishop)) goto L_Threatened;
1388 if (p->X==x-1) {
1389 if (p->Type&TF_King) goto L_Threatened;
1390 if (p->Type==(TF_Pawn|TF_Black)) goto L_Threatened;
1391 }
1392 }
1393 p=n[14];
1394 if (p && (p->Type&tside)) {
1395 if (p->Type&(TF_Queen|TF_Bishop)) goto L_Threatened;
1396 if (p->X==x+1) {
1397 if (p->Type&TF_King) goto L_Threatened;
1398 if (p->Type==(TF_Pawn|TF_Black)) goto L_Threatened;
1399 }
1400 }
1401 return false;
1402 L_Threatened:
1403 return true;
1404 }
1405
1406
TBDoMove(const Move & m)1407 void SilChessMachine::TBDoMove(const Move & m)
1408 {
1409 Piece * s, * t;
1410 int x1,y1,x2,y2;
1411
1412 CachedInfoValid=false;
1413
1414 Moves[MoveCount]=m;
1415 TBSetInt(MoveCount,MoveCount+1);
1416 TBSetInt(Turn,Turn^(TF_White|TF_Black));
1417
1418 x1=m.X1;
1419 y1=m.Y1;
1420 x2=m.X2;
1421 y2=m.Y2;
1422
1423 s=Board[y1*8+x1];
1424 t=Board[y2*8+x2];
1425
1426 TBUnlinkPiece(*s);
1427 if (x1!=x2) TBSetInt(s->X,x2);
1428 if (y1!=y2) TBSetInt(s->Y,y2);
1429 if (s->State&SF_CanCastle) TBSetInt(s->State,s->State&~SF_CanCastle);
1430 if (s->Type&TF_Pawn) {
1431 if (y2==0 || y2==7) {
1432 TBSetInt(s->Type,s->Type^(TF_Queen|TF_Pawn));
1433 TBSetInt(s->Value,QueenValue);
1434 }
1435 if (x1!=x2 && !t) t=Board[y1*8+x2];
1436 }
1437 else if (s->Type&TF_King) {
1438 if (x2-x1>1 || x2-x1<-1) {
1439 if (x2>x1) t=Board[y1*8+7]; else t=Board[y1*8+0];
1440 TBUnlinkPiece(*t);
1441 TBSetInt(t->X,(x2+x1)/2);
1442 TBSetInt(t->State,t->State&~SF_CanCastle);
1443 TBLinkPiece(*t);
1444 t=NULL;
1445 }
1446 }
1447 if (t) {
1448 TBUnlinkPiece(*t);
1449 TBSetInt(t->Type,0);
1450 }
1451 TBLinkPiece(*s);
1452 }
1453
1454
TBLinkPiece(Piece & p)1455 void SilChessMachine::TBLinkPiece(Piece & p)
1456 {
1457 Piece * n[16];
1458 Piece * q;
1459 int i;
1460
1461 CalcNeighbours(p.X,p.Y,n);
1462 TBSetPtr(Board[p.Y*8+p.X],&p);
1463 for (i=0; i<16; i++) {
1464 q=n[i];
1465 if (q) TBSetPtr(q->N[(i+8)&15],&p);
1466 if (p.N[i]!=q) TBSetPtr(p.N[i],q);
1467 }
1468 }
1469
1470
TBUnlinkPiece(Piece & p)1471 void SilChessMachine::TBUnlinkPiece(Piece & p)
1472 {
1473 TBSetPtr(Board[p.Y*8+p.X],NULL);
1474 if (p.N[ 0]) TBSetPtr(p.N[ 0]->N[ 8],p.N[ 8]);
1475 if (p.N[ 1]) TBSetPtr(p.N[ 1]->N[ 9],NULL);
1476 if (p.N[ 2]) TBSetPtr(p.N[ 2]->N[10],p.N[10]);
1477 if (p.N[ 3]) TBSetPtr(p.N[ 3]->N[11],NULL);
1478 if (p.N[ 4]) TBSetPtr(p.N[ 4]->N[12],p.N[12]);
1479 if (p.N[ 5]) TBSetPtr(p.N[ 5]->N[13],NULL);
1480 if (p.N[ 6]) TBSetPtr(p.N[ 6]->N[14],p.N[14]);
1481 if (p.N[ 7]) TBSetPtr(p.N[ 7]->N[15],NULL);
1482 if (p.N[ 8]) TBSetPtr(p.N[ 8]->N[ 0],p.N[ 0]);
1483 if (p.N[ 9]) TBSetPtr(p.N[ 9]->N[ 1],NULL);
1484 if (p.N[10]) TBSetPtr(p.N[10]->N[ 2],p.N[ 2]);
1485 if (p.N[11]) TBSetPtr(p.N[11]->N[ 3],NULL);
1486 if (p.N[12]) TBSetPtr(p.N[12]->N[ 4],p.N[ 4]);
1487 if (p.N[13]) TBSetPtr(p.N[13]->N[ 5],NULL);
1488 if (p.N[14]) TBSetPtr(p.N[14]->N[ 6],p.N[ 6]);
1489 if (p.N[15]) TBSetPtr(p.N[15]->N[ 7],NULL);
1490 }
1491
1492
TakeBack()1493 void SilChessMachine::TakeBack()
1494 {
1495 TBIntEntry * it;
1496 TBPtrEntry * pt;
1497
1498 CachedInfoValid=false;
1499
1500 for (it=TBIntTop-1; it->Ptr; it--) *(it->Ptr)=it->Val;
1501 TBIntTop=it;
1502
1503 for (pt=TBPtrTop-1; pt->Ptr; pt--) *(pt->Ptr)=pt->Val;
1504 TBPtrTop=pt;
1505 }
1506
1507
CalcNeighbours(int x,int y,Piece ** n) const1508 void SilChessMachine::CalcNeighbours(int x, int y, Piece * * n) const
1509 {
1510 Piece **p0,**p,**pe;
1511
1512 for (p=n, pe=n+16; p<pe; p++) *p=NULL;
1513 p0=(Piece**)(Board+y*8+x);
1514 for (p=p0+1, pe=p0-x+7; p<=pe; p++) {
1515 if (*p) { n[0]=*p; break; }
1516 }
1517 for (p=p0+9, pe=p0+9*(7-(x>y?x:y)); p<=pe; p+=9) {
1518 if (*p) { n[2]=*p; break; }
1519 }
1520 for (p=p0+8, pe=p0-y*8+7*8; p<=pe; p+=8) {
1521 if (*p) { n[4]=*p; break; }
1522 }
1523 for (p=p0+7, pe=p0+7*(x<(7-y)?x:(7-y)); p<=pe; p+=7) {
1524 if (*p) { n[6]=*p; break; }
1525 }
1526 for (p=p0-1, pe=p0-x ; p>=pe; p--) {
1527 if (*p) { n[8]=*p; break; }
1528 }
1529 for (p=p0-9, pe=p0-9*(x<y?x:y); p>=pe; p-=9) {
1530 if (*p) { n[10]=*p; break; }
1531 }
1532 for (p=p0-8, pe=p0-y*8; p>=pe; p-=8) {
1533 if (*p) { n[12]=*p; break; }
1534 }
1535 for (p=p0-7, pe=p0-7*((7-x)<y?(7-x):y); p>=pe; p-=7) {
1536 if (*p) { n[14]=*p; break; }
1537 }
1538 if (x>0) {
1539 if (y<6) n[5]=p0[2*8-1];
1540 if (y>1) n[11]=p0[-2*8-1];
1541 if (x>1) {
1542 if (y<7) n[7]=p0[1*8-2];
1543 if (y>0) n[9]=p0[-1*8-2];
1544 }
1545 }
1546 if (x<7) {
1547 if (y<6) n[3]=p0[2*8+1];
1548 if (y>1) n[13]=p0[-2*8+1];
1549 if (x<6) {
1550 if (y<7) n[1]=p0[1*8+2];
1551 if (y>0) n[15]=p0[-1*8+2];
1552 }
1553 }
1554 }
1555
1556
Random(int min,int max)1557 int SilChessMachine::Random(int min, int max)
1558 {
1559 static unsigned int seed=0;
1560 static bool initialized=false;
1561 unsigned int r,n;
1562
1563 if (min>=max) return min;
1564 if (!initialized) {
1565 seed=(unsigned int)time(NULL);
1566 initialized=true;
1567 }
1568 seed=seed*1664525+1013904223;
1569 r=seed;
1570 n=max+1-min;
1571 if (n<65536) r>>=16;
1572 return r%n+min;
1573 }
1574
1575
PrintASCII(bool flipped,const char * lastMove) const1576 void SilChessMachine::PrintASCII(bool flipped, const char * lastMove) const
1577 {
1578 const char * icons[13]={
1579 "....."
1580 "....."
1581 ".....",
1582 "....."
1583 ".._.."
1584 "..O..",
1585 "....."
1586 "../>."
1587 "./O\\.",
1588 "....."
1589 "..|.."
1590 "./O\\.",
1591 "....."
1592 ".|-|."
1593 ".|O|.",
1594 "....."
1595 ".\\\"/."
1596 ".]O[.",
1597 "....."
1598 ".\"\"\"."
1599 ".(O).",
1600 "....."
1601 ".._.."
1602 "..#..",
1603 "....."
1604 "../>."
1605 "./#\\.",
1606 "....."
1607 "..|.."
1608 "./#\\.",
1609 "....."
1610 ".|-|."
1611 ".|#|.",
1612 "....."
1613 ".\\\"/."
1614 ".]#[.",
1615 "....."
1616 ".\"\"\"."
1617 ".(#)."
1618 };
1619 int x,y,xi,yi,i;
1620
1621 for (y=0; y<8; y++) {
1622 for (yi=0; yi<3; yi++) {
1623 printf("\n");
1624 if (yi==1) printf("%d",flipped ? y+1 : 8-y);
1625 else printf(" ");
1626 for (x=0; x<8; x++) {
1627 for (xi=0; xi<5; xi++) {
1628 if (flipped) i=icons[GetField(7-x,7-y)][yi*5+xi];
1629 else i=icons[GetField(x,y)][yi*5+xi];
1630 if (!((x+y)&1) && i=='.') i=' ';
1631 printf("%c",i);
1632 }
1633 }
1634 }
1635 }
1636 printf(" %s\n ",lastMove);
1637 for (x=0; x<8; x++) {
1638 for (xi=0; xi<5; xi++) {
1639 if (xi==2) printf("%c", flipped ? 'H'-x : 'A'+x);
1640 else printf(" ");
1641 }
1642 }
1643 }
1644
1645
PrintASCII2(bool flipped,const char * lastMove) const1646 void SilChessMachine::PrintASCII2(bool flipped, const char * lastMove) const
1647 {
1648 const char * icons[7]={
1649 " "
1650 " "
1651 " ",
1652 " "
1653 " (#) "
1654 " )#( ",
1655 " "
1656 " /##> "
1657 " /##\\ ",
1658 " O "
1659 " (###) "
1660 " /#\\ ",
1661 " "
1662 " [###] "
1663 " |###| ",
1664 " \\ | / "
1665 " >#< "
1666 " /###\\ ",
1667 " | | | "
1668 " (###) "
1669 " /###\\ "
1670 };
1671 int x,y,xi,yi,i,s;
1672
1673 for (y=0; y<8; y++) {
1674 for (yi=0; yi<3; yi++) {
1675 printf("\n");
1676 if (yi==1) printf("%d",flipped ? y+1 : 8-y);
1677 else printf(" ");
1678 for (x=0; x<8; x++) {
1679 for (xi=0; xi<7; xi++) {
1680 if (flipped) s=GetField(7-x,7-y); else s=GetField(x,y);
1681 i=icons[s>6?s-6:s][yi*7+xi];
1682 if (i==' ') {
1683 if (((x+y)&1)) i=':'; else i=' ';
1684 }
1685 else if (i=='#') {
1686 if (s>6) i=' '; else i='#';
1687 }
1688 printf("%c",i);
1689 }
1690 }
1691 }
1692 }
1693 printf(" %s\n ",lastMove);
1694 for (x=0; x<8; x++) {
1695 for (xi=0; xi<7; xi++) {
1696 if (xi==3) printf("%c",flipped ? 'H'-x : 'A'+x);
1697 else printf(" ");
1698 }
1699 }
1700 }
1701
1702
PrintANSI(bool flipped,const char * lastMove) const1703 void SilChessMachine::PrintANSI(bool flipped, const char * lastMove) const
1704 {
1705 const char * icons[7]={
1706 " "
1707 " "
1708 " ",
1709 " _ "
1710 " (\") "
1711 " |#| ",
1712 " /o\\ "
1713 " /#\\#> "
1714 " \\##\\ ",
1715 " O "
1716 " (#) "
1717 " /#\\ ",
1718 " [###] "
1719 " |#| "
1720 " /###\\ ",
1721 " \\\\|// "
1722 " )#( "
1723 " /###\\ ",
1724 " |%%%| "
1725 " (###) "
1726 " /###\\ "
1727 };
1728 int x,y,i,xi,yi,s;
1729
1730 printf("\n\033[31m\033[43m");
1731 printf(" ");
1732 for (x=0; x<8; x++) {
1733 for (xi=0; xi<7; xi++) {
1734 if (xi==3) printf("%c",flipped ? 'h'-x : 'a'+x);
1735 else printf(" ");
1736 }
1737 }
1738 printf(" ");
1739 printf("\033[m");
1740 for (y=0; y<8; y++) {
1741 for (yi=0; yi<3; yi++) {
1742 printf("\n\033[31m\033[43m");
1743 if (yi==1) printf("%d ",flipped ? y+1 : 8-y);
1744 else printf(" ");
1745 printf("\033[1m");
1746 for (x=0; x<8; x++) {
1747 if (flipped) s=GetField(7-x,7-y); else s=GetField(x,y);
1748 if (((x+y)&1)) printf("\033[42m");
1749 else printf("\033[46m");
1750 if (s>6) printf("\033[30m");
1751 else printf("\033[37m");
1752 for (xi=0; xi<7; xi++) {
1753 i=icons[s>6?s-6:s][yi*7+xi];
1754 printf("%c",i);
1755 }
1756 }
1757 printf("\033[m\033[31m\033[43m");
1758 if (yi==1) printf(" %d",flipped ? y+1 : 8-y);
1759 else printf(" ");
1760 printf("\033[m");
1761 }
1762 }
1763 printf(" %s\n\033[31m\033[43m ",lastMove);
1764 for (x=0; x<8; x++) {
1765 for (xi=0; xi<7; xi++) {
1766 if (xi==3) printf("%c",flipped ? 'h'-x : 'a'+x);
1767 else printf(" ");
1768 }
1769 }
1770 printf(" ");
1771 printf("\033[m");
1772 }
1773
1774
PrintDOS(bool flipped,const char * lastMove) const1775 void SilChessMachine::PrintDOS(bool flipped, const char * lastMove) const
1776 {
1777 const char * icons[7]={
1778 " "
1779 " "
1780 " ",
1781 " "
1782 " (#) "
1783 " )#( ",
1784 " "
1785 " /##> "
1786 " /##\\ ",
1787 " O "
1788 " (###) "
1789 " /#\\ ",
1790 " "
1791 " [###] "
1792 " |###| ",
1793 " \\ | / "
1794 " >#< "
1795 " /###\\ ",
1796 " | | | "
1797 " (###) "
1798 " /###\\ "
1799 };
1800 int x,y,xi,yi,i,s;
1801
1802 for (y=0; y<8; y++) {
1803 for (yi=0; yi<3; yi++) {
1804 printf("\n");
1805 if (yi==1) printf("%d",flipped ? y+1 : 8-y);
1806 else printf(" ");
1807 for (x=0; x<8; x++) {
1808 for (xi=0; xi<7; xi++) {
1809 if (flipped) s=GetField(7-x,7-y); else s=GetField(x,y);
1810 i=icons[s>6?s-6:s][yi*7+xi];
1811 if (i==' ') {
1812 if (((x+y)&1)) i=177; else i=176;
1813 }
1814 else if (i=='#') {
1815 if (s>6) i=' '; else i='#';
1816 }
1817 printf("%c",i);
1818 }
1819 }
1820 }
1821 }
1822 printf(" %s\n ",lastMove);
1823 for (x=0; x<8; x++) {
1824 for (xi=0; xi<7; xi++) {
1825 if (xi==3) printf("%c",flipped ? 'H'-x : 'A'+x);
1826 else printf(" ");
1827 }
1828 }
1829 }
1830
1831
PrintMINI(bool flipped,const char * lastMove) const1832 void SilChessMachine::PrintMINI(bool flipped, const char * lastMove) const
1833 {
1834 const char * icons=".pnbrqkPNBRQK";
1835 int x,y,i;
1836
1837 for (y=0; y<8; y++) {
1838 printf("\n");
1839 printf("%d",flipped ? y+1 :8-y);
1840 for (x=0; x<8; x++) {
1841 if (flipped) i=icons[GetField(7-x,7-y)];
1842 else i=icons[GetField(x,y)];
1843 if (!((x+y)&1)) {
1844 if (i=='.') i=' ';
1845 printf(" %c",i);
1846 }
1847 else {
1848 printf(".%c",i);
1849 }
1850 }
1851 }
1852 printf(" %s\n ",lastMove);
1853 for (x=0; x<8; x++) {
1854 printf("%c ",flipped ? 'h'-x : 'a'+x);
1855 }
1856 }
1857