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