Deal with simple compiler warnings: dead code, unused parameters, etc.
[gnushogi.git] / gnushogi / search.c
blobe87e1d46b5ecc76053475e9d3fcaf35ababf5a2f
1 /*
2 * FILE: search.c
4 * ----------------------------------------------------------------------
5 * Copyright (c) 1993, 1994, 1995 Matthias Mutz
6 * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
8 * GNU SHOGI is based on GNU CHESS
10 * Copyright (c) 1988, 1989, 1990 John Stanback
11 * Copyright (c) 1992 Free Software Foundation
13 * This file is part of GNU SHOGI.
15 * GNU Shogi is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 3 of the License,
18 * or (at your option) any later version.
20 * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
21 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 * for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with GNU Shogi; see the file COPYING. If not, see
27 * <http://www.gnu.org/licenses/>.
28 * ----------------------------------------------------------------------
32 #include "gnushogi.h"
34 short background = 0;
35 static short DepthBeyond;
36 unsigned short PrVar[MAXDEPTH];
37 extern short recycle, ISZERO;
38 extern void FlagString(unsigned short flags, char *s);
40 #ifdef NULLMOVE
41 short null; /* Null-move already made or not */
42 short PVari; /* Is this the PV */
43 #endif
45 short zwndw;
49 /* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
54 * Check for draw by fourfold repetition
55 * (same side, same captures, same board).
56 * WARNING: this is not save (sp? safe?) yet due to possible hash collisions.
59 short
60 repetition()
62 short i, cnt = 0;
64 #ifndef NOREPETITION
65 struct GameRec *g;
67 if (GameCnt > Game50 + 6)
69 for (i = GameCnt - 1; i >= Game50; i -= 2)
71 g = &GameList[i];
73 if (g->hashkey == hashkey && g->hashbd == hashbd)
74 cnt++;
77 #endif
79 return cnt;
84 int plyscore, globalscore;
88 * Find the best move in the tree between indexes p1 and p2. Swap the best
89 * move into the p1 element.
92 int
93 pick(short p1, short p2)
95 struct leaf *p, *q, *r, *k;
96 short s0;
97 struct leaf temp;
99 k = p = &Tree[p1];
100 q = &Tree[p2];
101 s0 = p->score;
103 for (r = p + 1; r <= q; r++)
105 if ((r->score) > s0)
107 s0 = r->score;
108 p = r;
112 if (p != k)
114 temp = *p;
115 *p = *k;
116 *k = temp;
117 return true;
120 return false;
123 int bookflag = false;
124 int Jscore = 0;
126 int TCcount;
127 long TCleft = 0;
133 * Select a move by calling function search() at progressively deeper ply
134 * until time is up or a mate or draw is reached. An alpha-beta window of
135 * -Awindow to +Bwindow points is set around the score returned from the
136 * previous iteration. If Sdepth != 0 then the program has correctly
137 * predicted the opponents move and the search will start at a depth of
138 * Sdepth + 1 rather than a depth of 1.
141 void
142 SelectMove(short side, SelectMove_mode iop)
144 static short i, tempb, tempc, tempsf, tempst, xside, rpt;
145 static short alpha, beta, score;
146 static struct GameRec *g;
147 short sqking, in_check, blockable;
149 #ifdef BOOKTEST
150 printf("hashbd = %ld (hashkey >> 16)|side = %d\n",
151 hashbd, (hashkey >> 16)|side);
152 #endif
154 flag.timeout = false;
155 flag.back = false;
156 flag.musttimeout = false;
158 xside = side ^ 1;
160 #if ttblsz
161 recycle = (GameCnt % rehash) - rehash;
162 #endif
164 ExaminePosition(side);
166 /* if background mode set to infinite */
167 if (iop == BACKGROUND_MODE)
169 background = true;
170 /* if background mode set response time to infinite */
171 ResponseTime = 9999999;
173 else
175 background = false; /* [HGM] with ponder on we did not switch back to foreground mode??? */
176 player = side;
177 SetResponseTime(side);
180 #ifdef QUIETBACKGROUND
181 if (!background)
182 #endif /* QUIETBACKGROUND */
183 dsp->ShowResponseTime();
185 ExtraTime = 0;
187 score = ScorePosition(side);
189 #ifdef QUIETBACKGROUND
190 if (!background)
191 #endif /* QUIETBACKGROUND */
192 dsp->ShowSidetoMove();
194 #ifdef QUIETBACKGROUND
195 if (!background)
196 #endif /* QUIETBACKGROUND */
197 dsp->SearchStartStuff(side);
199 #ifdef HISTORY
200 array_zero(history, sizeof_history);
201 #endif
203 FROMsquare = TOsquare = -1;
204 PV = 0;
206 if (iop == FOREGROUND_MODE)
207 hint = 0;
210 * If the last move was the hint, select the computed answer to the
211 * hint as first move to examine.
214 #if MAXDEPTH > 3
215 if (GameCnt > 0)
217 SwagHt = (GameList[GameCnt].gmove == PrVar[2]) ? PrVar[3] : 0;
219 else
220 #endif
221 SwagHt = 0;
224 for (i = 0; i < MAXDEPTH; i++)
225 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
227 /* set initial window for search */
229 if (flag.tsume)
231 alpha = -(SCORE_LIMIT + 999);
232 beta = SCORE_LIMIT + 999;
234 else
236 alpha = score - ((computer == white) ? BAwindow : WAwindow);
237 beta = score + ((computer == white) ? BBwindow : WBwindow);
240 rpt = 0;
241 TrPnt[1] = 0;
242 root = &Tree[0];
244 sqking = PieceList[side][0];
245 in_check = (board[sqking] == king)
246 ? SqAttacked(sqking, side^1, &blockable)
247 : false;
249 MoveList(side, 1, in_check, blockable);
251 for (i = TrPnt[1]; i < TrPnt[2]; i++)
253 if (!pick(i, TrPnt[2] - 1))
254 break;
257 /* Can I get a book move? */
259 if (flag.regularstart && Book)
261 flag.timeout = bookflag = OpeningBook(&hint);
263 if (TCflag)
264 ResponseTime += ResponseTime;
267 /* Zero stats for hash table. */
269 reminus = replus = 0;
270 GenCnt = NodeCnt = ETnodes = EvalNodes = HashCnt
271 = FHashAdd = HashAdd = FHashCnt = THashCol = HashCol = 0;
273 globalscore = plyscore = score;
274 Jscore = 0;
275 zwndw = 20;
278 /********************* main loop ********************************/
280 Sdepth = (MaxSearchDepth < (MINDEPTH - 1))
281 ? MaxSearchDepth
282 : (MINDEPTH - 1);
284 while (!flag.timeout)
286 /* go down a level at a time */
287 Sdepth++;
289 #ifdef NULLMOVE
290 null = 0;
291 PVari = 1;
292 #endif
294 /* terminate search at DepthBeyond ply past goal depth */
295 if (flag.tsume)
296 DepthBeyond = Sdepth;
297 else
298 #if defined SLOW_CPU
299 DepthBeyond = Sdepth + ((Sdepth == 1) ? 3 : 5);
300 #else
301 DepthBeyond = Sdepth + ((Sdepth == 1) ? 7 : 11);
302 #endif
304 # ifdef QUIETBACKGROUND
305 if (!background)
306 #endif /* QUIETBACKGROUND */
307 dsp->ShowDepth(' ');
309 /* search at this level returns score of PV */
310 score = search(side, 1, Sdepth, alpha, beta, PrVar, &rpt);
312 /* save PV as killer */
313 for (i = 1; i <= Sdepth; i++)
314 killr0[i] = PrVar[i];
316 /* low search failure re-search with (-inf, score) limits */
317 if (score < alpha)
319 reminus++;
320 #ifdef QUIETBACKGROUND
321 if (!background)
322 #endif /* QUIETBACKGROUND */
323 dsp->ShowDepth('-');
325 if (TCflag && TCcount < MAXTCCOUNTR)
327 if (hard_time_limit)
328 ExtraTime += (MAXTCCOUNTR - TCcount) * TCleft;
329 else
330 ExtraTime += (8 * TCleft);
332 TCcount = MAXTCCOUNTR - 1;
335 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
336 (SCORE_LIMIT + 999), PrVar, &rpt);
338 /* high search failure re-search with (score, +inf) limits */
339 else if (score > beta && !(root->flags & exact))
341 replus++;
342 #ifdef QUIETBACKGROUND
343 if (!background)
344 #endif /* QUIETBACKGROUND */
345 dsp->ShowDepth('+');
347 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
348 (SCORE_LIMIT + 999), PrVar, &rpt);
351 /**************** out of search ***********************************/
352 CheckForTimeout(score, globalscore, Jscore, zwndw);
354 /************************ time control ****************************/
356 /* save PV as killer */
357 for (i = 1; i <= Sdepth + 1; i++)
358 killr0[i] = PrVar[i];
360 if (!flag.timeout)
361 Tscore[0] = score;
363 /* if (!flag.timeout) */
365 for (i = TrPnt[1] + 1; i < TrPnt[2]; i++)
366 if (!pick (i, TrPnt[2] - 1))
367 break;
370 /* if done or nothing good to look at quit */
371 if ((root->flags & exact) || (score < -SCORE_LIMIT))
372 flag.timeout = true;
374 /* find the next best move put below root */
376 if (!flag.timeout)
378 #if !defined NODYNALPHA
379 Jscore = (plyscore + score) >> 1;
380 #endif
381 zwndw = 20 + abs(Jscore / 12);
382 plyscore = score;
384 /* recompute search window */
385 beta = score + ((computer == white) ? BBwindow : WBwindow);
386 #if !defined NODYNALPHA
387 alpha = ((Jscore < score) ? Jscore : score)
388 - ((computer == white) ? BAwindow : WAwindow)
389 - zwndw;
390 #else
391 alpha = score - ((computer == white) ? BAwindow : WAwindow);
392 #endif
395 #ifdef QUIETBACKGROUND
396 if (!background)
397 #endif /* QUIETBACKGROUND */
398 dsp->ShowResults(score, PrVar, '.');
401 /********************** end of main loop ***************************/
403 /* background mode */
404 if (iop == BACKGROUND_MODE)
405 return;
407 if (rpt >= 3)
409 root->flags |= draw;
410 DRAW = DRAW_REPETITION;
412 else
415 * If there are no moves and we're not in check (stalemate) then
416 * it's mate in shogi (whereas it's a draw in chess).
419 if (GameCnt == MAXMOVES)
421 root->flags |= draw;
422 DRAW = DRAW_MAXMOVES;
426 /* not in book so set hint to guessed move for other side */
427 if (!bookflag)
428 hint = ((PrVar[1]) ? PrVar[2] : 0);
430 /* if not mate or draw make move and output it */
431 if (((score > -(SCORE_LIMIT + 999))
432 && (rpt <= 3)) || (root->flags & draw))
434 MakeMove(side, &Tree[0], &tempb, &tempc,
435 &tempsf, &tempst, &INCscore);
436 algbr(root->f, root->t, (short) root->flags);
438 else
440 algbr(0, 0, 0); /* Zero move string when mate. */
441 root->score = score; /* When mate, ignore distinctions!
442 * --SMC */
445 g = &GameList[GameCnt];
447 if ((g->flags & capture) && (g->piece == king))
448 flag.mate = flag.illegal = true;
450 /* If Time Control get the elapsed time */
451 if (TCflag)
452 ElapsedTime(COMPUTE_AND_INIT_MODE);
454 /* update time control info */
455 dsp->OutputMove();
457 /* if mate set flag */
458 if ((score == -(SCORE_LIMIT + 999) || score == (SCORE_LIMIT + 998)))
459 flag.mate = true;
461 /* add move to game list */
462 g->score = score;
463 g->nodes = NodeCnt;
464 g->time = (et +50)/100;
465 /* g->time = TCcount; */
466 g->depth = Sdepth;
468 /* update time control info */
469 if (TCflag)
471 TimeControl.clock[side] -= (et + OperatorTime);
472 timecomp[compptr] = (et + OperatorTime);
474 /* finished our required moves - setup the next set */
475 --TimeControl.moves[side];
478 /* check for end conditions */
479 if ((root->flags & draw) /* && flag.bothsides */)
481 flag.mate = true;
483 else if (GameCnt == MAXMOVES)
485 flag.mate = true;
487 /* out of move store, you lose */
488 else
490 /* switch to other side */
491 player = xside;
494 /* if mate clear hint */
495 if (flag.mate)
496 hint = 0;
498 Sdepth = 0;
504 * Perform an alpha-beta search to determine the score for the current
505 * board position. If depth <= 0 only capturing moves and responses to
506 * check are generated and searched, otherwise all moves are processed. The
507 * search depth is modified for check evasions, certain re-captures and
508 * threats. Extensions may continue for up to 11 ply beyond the nominal
509 * search depth.
513 search(short side,
514 short ply,
515 short depth,
516 short alpha,
517 short beta,
518 unsigned short *bstline,
519 short *rpt)
521 short j, pnt;
522 short tempb, tempc, tempsf, tempst;
523 short xside, pbst, score, rcnt, in_check, blockable;
524 unsigned short mv, nxtline[MAXDEPTH];
525 struct leaf *node, tmp;
526 short best = -(SCORE_LIMIT + 3000);
527 short bestwidth = 0;
528 short mustcut;
530 #ifdef NULLMOVE
531 short PVsave;
532 short PVarisave;
533 #endif
535 NodeCnt++;
537 /* look every ZNODE nodes for a timeout */
538 #ifdef NULLMOVE
539 if (!null)
541 #endif
542 if (NodeCnt > ETnodes)
544 ElapsedTime(COMPUTE_MODE);
546 if (flag.back)
548 flag.back = false;
549 flag.timeout = true;
550 flag.musttimeout = false;
552 else if (TCflag || MaxResponseTime)
554 if ((et >= (ResponseTime + ExtraTime))
555 && (Sdepth > MINDEPTH))
557 /* try to extend to finish ply */
558 if (flag.back || (TCflag && TCcount < MAXTCCOUNTX))
560 flag.back = false;
561 flag.musttimeout = true;
562 TCcount++;
563 ExtraTime += TCleft;
565 else
567 flag.back = false;
568 flag.timeout = true;
569 flag.musttimeout = false;
573 else if (flag.back)
575 flag.back = false;
576 flag.timeout = true;
577 flag.musttimeout = false;
580 #ifdef QUIETBACKGROUND
581 if (!background)
582 #endif
583 dsp->ShowResponseTime();
585 else if (!TCflag && flag.musttimeout && Sdepth > MINDEPTH)
587 flag.timeout = true;
588 flag.musttimeout = false;
590 #ifdef NULLMOVE
592 #endif
594 xside = side ^ 1;
595 score = evaluate(side, ply, alpha, beta,
596 INCscore, &in_check, &blockable);
599 * check for possible repitition if so call repitition - rpt is
600 * repeat count
603 if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
605 *rpt = repetition();
608 * repeat position >3 don't need to return score it's taken
609 * care of above
612 if (*rpt == 1)
614 score /= 3;
615 score *= 2;
617 else if (*rpt == 2)
618 score /= 2;
620 else
622 *rpt = 0;
625 /* score > SCORE_LIMIT its a draw or mate */
626 if (score > SCORE_LIMIT)
628 bstline[ply] = 0;
629 return score;
632 /* Do we need to add depth because of special conditions */
633 /* if in check or in capture sequence search deeper */
635 /***************** depth extensions *****************/
637 if (depth > 0)
639 /* Allow opponent a chance to check again */
640 if (in_check)
642 if (depth < 2)
643 depth = 2;
645 else if (flag.rcptr
646 && (score > alpha) && (score < beta)
647 && (ply > 2)
648 && CptrFlag[ply - 1] && CptrFlag[ply - 2])
650 if (hard_time_limit)
652 if (!flag.timeout)
653 ++depth;
655 else
657 ++depth;
662 else
664 short timeout = 0;
666 if (hard_time_limit)
667 timeout = flag.timeout;
669 if ((score >= alpha)
670 && (in_check
671 || ((!timeout && (hung[side] > 1))
672 && (ply == Sdepth + 1))))
674 depth = 1;
676 else if ((score <= beta)
677 && (((ply < Sdepth + 4) && (ply > 4))
678 && ChkFlag[ply - 2]
679 && ChkFlag[ply - 4]
680 && (ChkFlag[ply - 2] != ChkFlag[ply - 4])))
682 depth = 1;
686 /***************************************************/
687 /* try the local transition table if it's there */
689 #if ttblsz
690 if (/* depth > 0 && */ flag.hash && ply > 1)
692 if (use_ttable
693 && ProbeTTable(side, depth, ply, &alpha, &beta, &score) == true)
695 bstline[ply] = PV;
696 bstline[ply + 1] = 0;
698 if (beta == -((SCORE_LIMIT + 1000) * 2))
699 return score;
701 if (alpha > beta)
702 return alpha;
705 #ifdef HASHFILE
706 /* ok try the transition file if its there */
707 else if (hashfile
708 && (depth > HashDepth)
709 && (GameCnt < HashMoveLimit)
710 && (ProbeFTable(side, depth, ply, &alpha, &beta, &score)
711 == true))
713 PutInTTable(side, score, depth, ply, beta, PV);
714 bstline[ply] = PV;
715 bstline[ply + 1] = 0;
717 if (beta == -((SCORE_LIMIT + 1000) * 2))
718 return score;
720 if (alpha > beta)
722 return alpha;
725 #endif /* HASHFILE */
727 #endif /* ttblsz */
729 if (TrPnt[ply] > (TREE - 300))
730 mustcut = true;
731 else
732 mustcut = false;
735 * If more then DepthBeyond ply past goal depth or at goal depth and
736 * score > beta quit - means we are out of the window.
739 if (mustcut || (ply > DepthBeyond) || ((depth < 1) && (score > beta)))
740 return score;
743 * If below first ply and not at goal depth generate all moves else
744 * only capture moves.
747 if (ply > 1)
749 if ((depth > 0) || (ply < (SDEPTHLIM))
750 || (background && (ply < Sdepth + 2)))
751 MoveList(side, ply, in_check, blockable);
752 else
753 CaptureList(side, ply, in_check, blockable);
756 /* no moves return what we have */
759 * normally a search will continue til past goal and no more capture
760 * moves exist
763 /* unless it hits DepthBeyond */
764 if (TrPnt[ply] == TrPnt[ply + 1])
765 return score;
767 /* if not at goal set best = -inf else current score */
768 best = (depth > 0) ? -(SCORE_LIMIT + 3000) : score;
770 #ifdef NULLMOVE
772 PVarisave = PVari;
774 /* CHECKME: is the & really an && here? */
775 if (!null && /* no previous null-move */
776 !PVari && /* no null-move during the PV */
777 (ply > 2) & /* not at ply 1 */
778 (ply <= Sdepth) &&
779 (depth > 3) &&
780 !in_check) /* no check */
781 /* enough material such that zugzwang is unlikely
782 * but who knows which value is suitable? */
785 OK, we make a null move, i.e. this means we have nothing to do
786 but we have to keep the some arrays up to date otherwise gnushogi
787 gets confused. Maybe somebody knows exactly which information is
788 important and which isn't.
790 Another idea is that we try the null-move first and generate the
791 moves later. This may save time but we have to take care that
792 PV and other variables contain the right value so that the move
793 ordering works right.
796 struct GameRec *g;
798 nxtline[ply + 1] = 0;
799 CptrFlag[ply] = 0;
800 TesujiFlag[ply] = 0;
801 Tscore[ply] = score;
802 PVsave = PV;
803 PV = 0;
804 null = 1;
805 g = &GameList[++GameCnt];
806 g->hashkey = hashkey;
807 g->hashbd = hashbd;
808 FROMsquare = TOsquare = -1;
809 g->Game50 = Game50;
810 g->gmove = -1;
811 g->flags = 0;
812 g->piece = 0;
813 g->color = neutral;
815 best = -search(xside, ply + 1, depth - 2,
816 -beta - 1, -beta, nxtline, &rcnt);
817 null = 0;
818 PV = PVsave;
819 GameCnt--;
821 if (best < alpha)
823 best = -(SCORE_LIMIT + 3000);
825 else if (best > beta)
827 return best;
829 else
831 best = -(SCORE_LIMIT + 3000);
834 #endif
836 /* if best so far is better than alpha set alpha to best */
837 if (best > alpha)
838 alpha = best;
840 /********************** main loop ****************************/
842 /* look at each move until no more or beta cutoff */
843 for (pnt = pbst = TrPnt[ply];
844 (pnt < TrPnt[ply + 1]) && (best <= beta);
845 pnt++)
847 /* find the most interesting looking of the remaining moves */
848 if (ply > 1)
849 pick(pnt, TrPnt[ply + 1] - 1);
851 #ifdef NULLMOVE
852 PVari = PVarisave && (pnt == TrPnt[ply]); /* Is this the PV? */
853 #endif
855 node = &Tree[pnt];
857 /* is this a forbidden move */
858 if (/* ply == 1 && */ node->score <= DONTUSE)
859 continue;
861 nxtline[ply + 1] = 0;
863 /* if at top level */
864 #if !defined NOPOST
865 if (ply == 1)
867 /* at the top update search status */
868 if (flag.post)
870 #ifdef QUIETBACKGROUND
871 if (!background)
872 #endif /* QUIETBACKGROUND */
873 dsp->ShowCurrentMove(pnt, node->f, node->t);
876 #endif
878 if (!(node->flags & exact))
880 /* make the move and go deeper */
882 MakeMove(side, node, &tempb, &tempc, &tempsf,
883 &tempst, &INCscore);
884 CptrFlag[ply] = ((node->flags & capture) != 0);
885 TesujiFlag[ply] = (node->flags & tesuji)
886 && (node->flags & dropmask);
887 Tscore[ply] = node->score;
888 PV = node->reply;
890 node->score = -search(xside, ply + 1,
891 (depth > 0) ? (depth - 1) : 0,
892 -beta, -alpha,
893 nxtline, &rcnt);
896 * if(!flag.timeout)
897 * node->score = score;
900 node->width = ((ply % 2) == 1)
901 ? (TrPnt[ply + 2] - TrPnt[ply + 1])
902 : 0;
904 if ((node->score > SCORE_LIMIT) || (node->score < -SCORE_LIMIT) )
905 node->flags |= exact;
906 else if (rcnt == 1)
907 node->score /= 2;
909 if (((rcnt >= 3)
910 || ((node->score == (SCORE_LIMIT + 999) - ply)
911 && !ChkFlag[ply])))
913 node->flags |= (draw | exact);
914 DRAW = DRAW_JUSTDRAW;
915 node->score = ((side == computer) ? contempt : -contempt);
918 node->reply = nxtline[ply + 1];
920 /* reset to try next move */
921 UnmakeMove(side, node, &tempb, &tempc, &tempsf, &tempst);
924 /* if best move so far */
925 /* CHECKME: flag.timeout isn't valid if no hard time limit */
926 if (!flag.timeout
927 && ((node->score > best)
928 || ((node->score == best) && (node->width > bestwidth))))
931 * All things being equal pick the denser part of the
932 * tree.
934 bestwidth = node->width;
937 * If not at goal depth and better than alpha and not
938 * an exact score increment by depth.
941 if ((depth > 0) && (node->score > alpha)
942 && !(node->flags & exact))
944 node->score += depth;
947 best = node->score;
948 pbst = pnt;
950 if (best > alpha)
951 alpha = best;
953 /* update best line */
954 for (j = ply + 1; nxtline[j] > 0; j++)
955 bstline[j] = nxtline[j];
957 bstline[j] = 0;
958 bstline[ply] = (node->f << 8) | node->t;
960 /* if at the top */
961 if (ply == 1)
964 * If it's better than the root score make it the root.
966 if ((best > root->score)
967 || ((best == root->score)
968 && (bestwidth > root->width)))
970 tmp = Tree[pnt];
972 for (j = pnt - 1; j >= 0; j--)
973 Tree[j + 1] = Tree[j];
975 Tree[0] = tmp;
976 pbst = 0;
979 #ifdef QUIETBACKGROUND
980 if (!background)
982 #endif /* QUIETBACKGROUND */
983 if (Sdepth > 2)
985 if (best > beta)
987 dsp->ShowResults(best, bstline, '+');
989 else if (best < alpha)
991 dsp->ShowResults(best, bstline, '-');
993 else
995 dsp->ShowResults(best, bstline, '&');
998 #ifdef QUIETBACKGROUND
1000 #endif
1004 if (flag.timeout)
1005 return Tscore[ply - 1];
1008 /******************************************************/
1010 node = &Tree[pbst];
1011 mv = (node->f << 8) | node->t;
1013 #ifdef NULLMOVE
1014 PVari = PVarisave;
1015 #endif
1018 * We have a move so put it in local table - if it's already there
1019 * done else if not there or needs to be updated also put it in
1020 * hashfile
1023 #if ttblsz
1024 if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
1026 # ifdef HASHFILE /* MCV: warning: this confuses the formatter. */
1027 if (use_ttable
1028 && PutInTTable(side, best, depth, ply, beta, mv)
1029 && hashfile
1030 && (depth > HashDepth)
1031 && (GameCnt < HashMoveLimit))
1032 # else
1033 if (use_ttable
1034 && PutInTTable(side, best, depth, ply, beta, mv))
1035 # endif
1037 PutInFTable(side, best, depth, ply,
1038 alpha, beta, node->f, node->t);
1041 #endif /* ttblsz */
1043 if (depth > 0)
1045 #if defined HISTORY
1046 unsigned short h, x;
1047 h = mv;
1049 if (history[x = hindex(side, h)] < HISTORYLIM)
1050 history[x] += (unsigned short) 1 << depth;
1051 #endif
1053 if (node->t != (short)(GameList[GameCnt].gmove & 0xFF))
1055 if (best <= beta)
1057 killr3[ply] = mv;
1059 else if (mv != killr1[ply])
1061 killr2[ply] = killr1[ply];
1062 killr1[ply] = mv;
1066 killr0[ply] = ((best > SCORE_LIMIT) ? mv : 0);
1069 return best;
1075 * Update the PieceList and Pindex arrays when a piece is captured or when a
1076 * capture is unmade.
1079 void
1080 UpdatePieceList(short side, short sq, UpdatePieceList_mode iop)
1082 short i;
1084 if (iop == REMOVE_PIECE)
1086 PieceCnt[side]--;
1088 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1090 PieceList[side][i] = PieceList[side][i + 1];
1091 Pindex[PieceList[side][i]] = i;
1094 else if (board[sq] == king)
1096 /* king must have index 0 */
1097 for (i = PieceCnt[side]; i >= 0; i--)
1099 PieceList[side][i + 1] = PieceList[side][i];
1100 Pindex[PieceList[side][i + 1]] = i + 1;
1103 PieceCnt[side]++;
1104 PieceList[side][0] = sq;
1105 Pindex[sq] = 0;
1107 else
1109 PieceCnt[side]++;
1110 PieceList[side][PieceCnt[side]] = sq;
1111 Pindex[sq] = PieceCnt[side];
1117 /* Make or Unmake drop move. */
1119 static void
1120 drop(short side, short piece, short t, short iop)
1122 if (iop == 1)
1124 short n;
1125 board[t] = piece;
1126 color[t] = side;
1128 #if !defined SAVE_SVALUE
1129 svalue[t] = 0;
1130 #endif
1132 n = Captured[side][piece]--;
1134 UpdateDropHashbd(side, piece, n);
1135 UpdateHashbd(side, piece, -1, t);
1136 UpdatePieceList(side, t, ADD_PIECE);
1138 if (piece == pawn)
1140 ++PawnCnt[side][column(t)];
1143 Mvboard[t]++;
1144 HasPiece[side][piece]++;
1146 else
1148 short n;
1149 board[t] = no_piece;
1150 color[t] = neutral;
1151 n = ++Captured[side][piece];
1153 UpdateDropHashbd(side, piece, n);
1154 UpdateHashbd(side, piece, -1, t);
1155 UpdatePieceList(side, t, REMOVE_PIECE);
1157 if (piece == pawn)
1158 --PawnCnt[side][column(t)];
1160 Mvboard[t]--;
1161 HasPiece[side][piece]--;
1166 #ifdef HASHKEYTEST
1168 CheckHashKey()
1170 unsigned long chashkey, chashbd;
1171 short side, sq;
1172 chashbd = chashkey = 0;
1174 for (sq = 0; sq < NO_SQUARES; sq++)
1176 if (color[sq] != neutral)
1178 chashbd ^= (*hashcode)[color[sq]][board[sq]][sq].bd;
1179 chashkey ^= (*hashcode)[color[sq]][board[sq]][sq].key;
1182 /* hashcodes for initial board are 0 ! */
1183 if (Stcolor[sq] != neutral)
1185 chashbd ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].bd;
1186 chashkey ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].key;
1190 for (side = 0; side <= 1; side++)
1192 short piece;
1194 for (piece = 0; piece < NO_PIECES; piece++)
1196 short n = Captured[side][piece];
1198 if (n > 0)
1200 short i;
1202 for (i = 1; i <= n; i++)
1204 chashbd ^= (*drop_hashcode)[side][piece][i].bd;
1205 chashkey ^= (*drop_hashcode)[side][piece][i].key;
1211 if (chashbd != hashbd)
1212 printf("chashbd %lu != hashbd %lu\n", chashbd, hashbd);
1214 if (chashkey != hashkey)
1215 printf("chashkey %lu != hashkey %lu\n", chashkey, hashkey);
1217 if (chashbd != hashbd || chashkey != hashkey)
1218 return 1;
1220 return 0;
1222 #endif
1228 * Update Arrays board[], color[], and Pindex[] to reflect the new board
1229 * position obtained after making the move pointed to by node. Also update
1230 * miscellaneous stuff that changes when a move is made.
1233 void
1234 MakeMove(short side,
1235 struct leaf *node,
1236 short *tempb, /* piece at to square */
1237 short *tempc, /* color of to square */
1238 short *tempsf, /* static value of piece on from */
1239 short *tempst, /* static value of piece on to */
1240 short *INCscore) /* score increment */
1242 short f, t, xside;
1243 struct GameRec *g;
1244 short fromb, fromc;
1246 xside = side ^ 1;
1247 g = &GameList[++GameCnt];
1248 g->hashkey = hashkey;
1249 g->hashbd = hashbd;
1250 FROMsquare = f = node->f;
1251 TOsquare = t = (node->t & 0x7f);
1252 *INCscore = (short)node->INCscore;
1253 g->Game50 = Game50;
1254 g->gmove = (f << 8) | node->t;
1255 g->flags = node->flags;
1257 #ifdef HASHKEYTEST
1258 if (CheckHashKey())
1260 short i;
1261 algbr(f, t, node->flags);
1262 printf("error before MakeMove: %s\n", mvstr[0]);
1263 UpdateDisplay(0, 0, 1, 0);
1265 for (i = 1; i <= GameCnt; i++)
1267 movealgbr(GameList[i].gmove, mvstr[0]);
1268 printf("%d: %s\n", i, mvstr[0]);
1271 exit(1);
1273 #endif
1275 rpthash[side][hashkey & 0xFF]++, ISZERO++;
1277 if (f > NO_SQUARES)
1279 g->fpiece = (node->flags & pmask);
1280 g->piece = *tempb = no_piece;
1281 g->color = *tempc = neutral;
1283 #if !defined SAVE_SVALUE
1284 *tempsf = 0;
1285 *tempst = svalue[t];
1286 #endif
1288 (void)drop(side, g->fpiece, t, 1);
1290 else
1292 #if !defined SAVE_SVALUE
1293 *tempsf = svalue[f];
1294 *tempst = svalue[t];
1295 #endif
1297 g->fpiece = board[f];
1298 g->piece = *tempb = board[t];
1299 g->color = *tempc = color[t];
1300 fromb = board[f];
1301 fromc = color[f];
1303 if (*tempc != neutral)
1305 /* Capture a piece */
1306 UpdatePieceList(*tempc, t, REMOVE_PIECE);
1308 /* if capture decrement pawn count */
1309 if (*tempb == pawn)
1310 --PawnCnt[*tempc][column(t)];
1312 mtl[xside] -= (*value)[stage][*tempb];
1313 HasPiece[xside][*tempb]--;
1316 short n, upiece = unpromoted[*tempb];
1318 /* add "upiece" captured by "side" */
1319 n = ++Captured[side][upiece];
1321 UpdateDropHashbd(side, upiece, n);
1322 mtl[side] += (*value)[stage][upiece];
1325 /* remove "*tempb" of "xside" from board[t] */
1326 UpdateHashbd(xside, *tempb, -1, t);
1328 #if !defined SAVE_SVALUE
1329 *INCscore += *tempst; /* add value of catched piece
1330 * to own score */
1331 #endif
1333 Mvboard[t]++;
1336 color[t] = fromc;
1338 #if !defined SAVE_SVALUE
1339 svalue[t] = svalue[f];
1340 svalue[f] = 0;
1341 #endif
1343 Pindex[t] = Pindex[f];
1344 PieceList[side][Pindex[t]] = t;
1345 color[f] = neutral;
1346 board[f] = no_piece;
1348 if (node->flags & promote)
1350 short tob;
1352 board[t] = tob = promoted[fromb];
1354 /* remove unpromoted piece from board[f] */
1355 UpdateHashbd(side, fromb, f, -1);
1357 /* add promoted piece to board[t] */
1358 UpdateHashbd(side, tob, -1, t);
1359 mtl[side] += value[stage][tob] - value[stage][fromb];
1361 if (fromb == pawn)
1362 --PawnCnt[side][column(f)];
1364 HasPiece[side][fromb]--;
1365 HasPiece[side][tob]++;
1367 #if !defined SAVE_SVALUE
1368 *INCscore -= *tempsf;
1369 #endif
1371 else
1373 board[t] = fromb;
1374 /* remove piece from board[f] and add it to board[t] */
1375 UpdateHashbd(side, fromb, f, t);
1378 Mvboard[f]++;
1381 #ifdef HASHKEYTEST
1382 algbr(f, t, node->flags);
1384 if (CheckHashKey())
1386 printf("error in MakeMove: %s\n", mvstr[0]);
1387 exit(1);
1389 #endif
1396 * Take back a move.
1399 void
1400 UnmakeMove(short side,
1401 struct leaf *node,
1402 short *tempb,
1403 short *tempc,
1404 short *tempsf,
1405 short *tempst)
1407 short f, t, xside;
1409 xside = side ^ 1;
1410 f = node->f;
1411 t = node->t & 0x7f;
1412 Game50 = GameList[GameCnt].Game50;
1414 if (node->flags & dropmask)
1416 (void)drop(side, (node->flags & pmask), t, 2);
1418 #if !defined SAVE_SVALUE
1419 svalue[t] = *tempst;
1420 #endif
1422 else
1424 short tob, fromb;
1426 color[f] = color[t];
1427 board[f] = tob = fromb = board[t];
1429 #if !defined SAVE_SVALUE
1430 svalue[f] = *tempsf;
1431 #endif
1433 Pindex[f] = Pindex[t];
1434 PieceList[side][Pindex[f]] = f;
1435 color[t] = *tempc;
1436 board[t] = *tempb;
1438 #if !defined SAVE_SVALUE
1439 svalue[t] = *tempst;
1440 #endif
1442 /* Undo move */
1443 if (node->flags & promote)
1445 board[f] = fromb = unpromoted[tob];
1446 mtl[side] += value[stage][fromb] - value[stage][tob];
1448 if (fromb == pawn)
1449 ++PawnCnt[side][column(f)];
1451 HasPiece[side][fromb]++;
1452 HasPiece[side][tob]--;
1454 /* add unpromoted piece to board[f] */
1455 UpdateHashbd(side, fromb, f, -1);
1457 /* remove promoted piece from board[t] */
1458 UpdateHashbd(side, tob, -1, t);
1460 else
1462 if (fromb == pawn)
1464 --PawnCnt[side][column(t)];
1465 ++PawnCnt[side][column(f)];
1468 /* remove piece from board[t] and add it to board[f] */
1469 UpdateHashbd(side, fromb, f, t);
1472 /* Undo capture */
1473 if (*tempc != neutral)
1475 short n, upiece = unpromoted[*tempb];
1477 UpdatePieceList(*tempc, t, ADD_PIECE);
1479 if (*tempb == pawn)
1480 ++PawnCnt[*tempc][column(t)];
1482 mtl[xside] += (*value)[stage][*tempb];
1483 HasPiece[xside][*tempb]++;
1484 mtl[side] -= (*value)[stage][upiece];
1486 /* remove "upiece" captured by "side" */
1487 n = Captured[side][upiece]--;
1489 UpdateDropHashbd(side, upiece, n);
1491 /* replace captured piece on board[t] */
1492 UpdateHashbd(xside, *tempb, -1, t);
1493 Mvboard[t]--;
1496 Mvboard[f]--;
1499 GameCnt--;
1500 rpthash[side][hashkey & 0xFF]--, ISZERO--;
1502 #ifdef HASHKEYTEST
1503 algbr(f, t, node->flags);
1505 if (CheckHashKey())
1507 printf("error in UnmakeMove: %s\n", mvstr[0]);
1508 exit(1);
1510 #endif
1516 * Scan thru the board seeing what's on each square. If a piece is found,
1517 * update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1518 * determine the material for each side and set the hashkey and hashbd
1519 * variables to represent the current board position. Array
1520 * PieceList[side][indx] contains the location of all the pieces of either
1521 * side. Array Pindex[sq] contains the indx into PieceList for a given
1522 * square.
1525 void
1526 InitializeStats(void)
1528 short i, sq;
1530 for (i = 0; i < NO_COLS; i++)
1531 PawnCnt[black][i] = PawnCnt[white][i] = 0;
1533 mtl[black] = mtl[white] = 0;
1534 PieceCnt[black] = PieceCnt[white] = 0;
1535 hashbd = hashkey = 0;
1537 for (sq = 0; sq < NO_SQUARES; sq++)
1539 if (color[sq] != neutral)
1541 mtl[color[sq]] += (*value)[stage][board[sq]];
1543 if (board[sq] == pawn)
1544 ++PawnCnt[color[sq]][column(sq)];
1546 Pindex[sq] = ((board[sq] == king) ? 0 : ++PieceCnt[color[sq]]);
1547 PieceList[color[sq]][Pindex[sq]] = sq;
1548 UpdateHashbd(color[sq], board[sq], sq, -1);
1551 /* hashcodes for initial board are 0 ! */
1552 if (Stcolor[sq] != neutral)
1553 UpdateHashbd(Stcolor[sq], Stboard[sq], sq, -1);
1557 short side;
1559 for (side = 0; side <= 1; side++)
1561 short piece;
1563 for (piece = 0; piece < NO_PIECES; piece++)
1565 short n = Captured[side][piece];
1567 if (n > 0)
1569 Captured[side][piece] = 0;
1571 for (i = 1; i <= n; i++)
1573 ++Captured[side][piece];
1574 UpdateDropHashbd(side, piece, i);
1575 mtl[side] += (*value)[stage][piece];
1582 #ifdef HASHKEYTEST
1583 if (CheckHashKey())
1585 printf("error in InitializeStats\n");
1586 exit(1);
1588 #endif