Restore previous copyright information that got removed by error.
[gnushogi.git] / gnushogi / search.c
blob2cfff174703854fc4fcd821aead631ae07bd1a84
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 #if !defined OLDTIME && defined HAVE_GETTIMEOFDAY
35 double pow(double x, double y);
36 #endif
38 short background = 0;
39 static short DepthBeyond;
40 unsigned short PrVar[MAXDEPTH];
41 extern short recycle, ISZERO;
42 extern void FlagString(unsigned short flags, char *s);
44 #ifdef NULLMOVE
45 short null; /* Null-move already made or not */
46 short PVari; /* Is this the PV */
47 #endif
49 short zwndw;
53 /* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
58 * Check for draw by fourfold repetition
59 * (same side, same captures, same board).
60 * WARNING: this is not save (sp? safe?) yet due to possible hash collisions.
63 short
64 repetition()
66 short i, cnt = 0;
68 #ifndef NOREPETITION
69 struct GameRec *g;
71 if (GameCnt > Game50 + 6)
73 for (i = GameCnt - 1; i >= Game50; i -= 2)
75 g = &GameList[i];
77 if (g->hashkey == hashkey && g->hashbd == hashbd)
78 cnt++;
81 #endif
83 return cnt;
88 int plyscore, globalscore;
92 * Find the best move in the tree between indexes p1 and p2. Swap the best
93 * move into the p1 element.
96 int
97 pick(short p1, short p2)
99 struct leaf *p, *q, *r, *k;
100 short s0;
101 struct leaf temp;
103 k = p = &Tree[p1];
104 q = &Tree[p2];
105 s0 = p->score;
107 for (r = p + 1; r <= q; r++)
109 if ((r->score) > s0)
111 s0 = r->score;
112 p = r;
116 if (p != k)
118 temp = *p;
119 *p = *k;
120 *k = temp;
121 return true;
124 return false;
127 int bookflag = false;
128 int Jscore = 0;
130 int TCcount;
131 long TCleft = 0;
137 * Select a move by calling function search() at progressively deeper ply
138 * until time is up or a mate or draw is reached. An alpha-beta window of
139 * -Awindow to +Bwindow points is set around the score returned from the
140 * previous iteration. If Sdepth != 0 then the program has correctly
141 * predicted the opponents move and the search will start at a depth of
142 * Sdepth + 1 rather than a depth of 1.
145 void
146 SelectMove(short side, SelectMove_mode iop)
148 static short i, tempb, tempc, tempsf, tempst, xside, rpt;
149 static short alpha, beta, score;
150 static struct GameRec *g;
151 short sqking, in_check, blockable;
153 #ifdef BOOKTEST
154 printf("hashbd = %ld (hashkey >> 16)|side = %d\n",
155 hashbd, (hashkey >> 16)|side);
156 #endif
158 flag.timeout = false;
159 flag.back = false;
160 flag.musttimeout = false;
162 xside = side ^ 1;
164 #if ttblsz
165 recycle = (GameCnt % rehash) - rehash;
166 #endif
168 ExaminePosition(side);
170 /* if background mode set to infinite */
171 if (iop == BACKGROUND_MODE)
173 background = true;
174 /* if background mode set response time to infinite */
175 ResponseTime = 9999999;
177 else
179 player = side;
180 SetResponseTime(side);
183 #ifdef QUIETBACKGROUND
184 if (!background)
185 #endif /* QUIETBACKGROUND */
186 ShowResponseTime();
188 ExtraTime = 0;
190 score = ScorePosition(side);
192 #ifdef QUIETBACKGROUND
193 if (!background)
194 #endif /* QUIETBACKGROUND */
195 ShowSidetoMove();
197 #ifdef QUIETBACKGROUND
198 if (!background)
199 #endif /* QUIETBACKGROUND */
200 SearchStartStuff(side);
202 #ifdef HISTORY
203 array_zero(history, sizeof_history);
204 #endif
206 FROMsquare = TOsquare = -1;
207 PV = 0;
209 if (iop == FOREGROUND_MODE)
210 hint = 0;
213 * If the last move was the hint, select the computed answer to the
214 * hint as first move to examine.
217 #if MAXDEPTH > 3
218 if (GameCnt > 0)
220 SwagHt = (GameList[GameCnt].gmove == PrVar[2]) ? PrVar[3] : 0;
222 else
223 #endif
224 SwagHt = 0;
227 for (i = 0; i < MAXDEPTH; i++)
228 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
230 /* set initial window for search */
232 if (flag.tsume)
234 alpha = -(SCORE_LIMIT + 999);
235 beta = SCORE_LIMIT + 999;
237 else
239 alpha = score - ((computer == white) ? BAwindow : WAwindow);
240 beta = score + ((computer == white) ? BBwindow : WBwindow);
243 rpt = 0;
244 TrPnt[1] = 0;
245 root = &Tree[0];
247 sqking = PieceList[side][0];
248 in_check = (board[sqking] == king)
249 ? SqAttacked(sqking, side^1, &blockable)
250 : false;
252 MoveList(side, 1, in_check, blockable);
254 for (i = TrPnt[1]; i < TrPnt[2]; i++)
256 if (!pick(i, TrPnt[2] - 1))
257 break;
260 /* Can I get a book move? */
262 if (flag.regularstart && Book)
264 flag.timeout = bookflag = OpeningBook(&hint, side);
266 if (TCflag)
267 ResponseTime += ResponseTime;
270 /* Zero stats for hash table. */
272 reminus = replus = 0;
273 GenCnt = NodeCnt = ETnodes = EvalNodes = HashCnt
274 = FHashAdd = HashAdd = FHashCnt = THashCol = HashCol = 0;
276 globalscore = plyscore = score;
277 Jscore = 0;
278 zwndw = 20;
281 /********************* main loop ********************************/
283 Sdepth = (MaxSearchDepth < (MINDEPTH - 1))
284 ? MaxSearchDepth
285 : (MINDEPTH - 1);
287 while (!flag.timeout)
289 /* go down a level at a time */
290 Sdepth++;
292 #ifdef NULLMOVE
293 null = 0;
294 PVari = 1;
295 #endif
297 /* terminate search at DepthBeyond ply past goal depth */
298 if (flag.tsume)
299 DepthBeyond = Sdepth;
300 else
301 #if defined SLOW_CPU
302 DepthBeyond = Sdepth + ((Sdepth == 1) ? 3 : 5);
303 #else
304 DepthBeyond = Sdepth + ((Sdepth == 1) ? 7 : 11);
305 #endif
307 # ifdef QUIETBACKGROUND
308 if (!background)
309 #endif /* QUIETBACKGROUND */
310 ShowDepth(' ');
312 /* search at this level returns score of PV */
313 score = search(side, 1, Sdepth, alpha, beta, PrVar, &rpt);
315 /* save PV as killer */
316 for (i = 1; i <= Sdepth; i++)
317 killr0[i] = PrVar[i];
319 /* low search failure re-search with (-inf, score) limits */
320 if (score < alpha)
322 reminus++;
323 #ifdef QUIETBACKGROUND
324 if (!background)
325 #endif /* QUIETBACKGROUND */
326 ShowDepth('-');
328 if (TCflag && TCcount < MAXTCCOUNTR)
330 if (hard_time_limit)
331 ExtraTime += (MAXTCCOUNTR - TCcount) * TCleft;
332 else
333 ExtraTime += (8 * TCleft);
335 TCcount = MAXTCCOUNTR - 1;
338 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
339 (SCORE_LIMIT + 999), PrVar, &rpt);
341 /* high search failure re-search with (score, +inf) limits */
342 else if (score > beta && !(root->flags & exact))
344 replus++;
345 #ifdef QUIETBACKGROUND
346 if (!background)
347 #endif /* QUIETBACKGROUND */
348 ShowDepth('+');
350 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
351 (SCORE_LIMIT + 999), PrVar, &rpt);
354 /**************** out of search ***********************************/
355 CheckForTimeout(score, globalscore, Jscore, zwndw);
357 /************************ time control ****************************/
359 /* save PV as killer */
360 for (i = 1; i <= Sdepth + 1; i++)
361 killr0[i] = PrVar[i];
363 if (!flag.timeout)
364 Tscore[0] = score;
366 /* if (!flag.timeout) */
368 for (i = TrPnt[1] + 1; i < TrPnt[2]; i++)
369 if (!pick (i, TrPnt[2] - 1))
370 break;
373 /* if done or nothing good to look at quit */
374 if ((root->flags & exact) || (score < -SCORE_LIMIT))
375 flag.timeout = true;
377 /* find the next best move put below root */
379 if (!flag.timeout)
381 #if !defined NODYNALPHA
382 Jscore = (plyscore + score) >> 1;
383 #endif
384 zwndw = 20 + abs(Jscore / 12);
385 plyscore = score;
387 /* recompute search window */
388 beta = score + ((computer == white) ? BBwindow : WBwindow);
389 #if !defined NODYNALPHA
390 alpha = ((Jscore < score) ? Jscore : score)
391 - ((computer == white) ? BAwindow : WAwindow)
392 - zwndw;
393 #else
394 alpha = score - ((computer == white) ? BAwindow : WAwindow);
395 #endif
398 #ifdef QUIETBACKGROUND
399 if (!background)
400 #endif /* QUIETBACKGROUND */
401 ShowResults(score, PrVar, '.');
404 /********************** end of main loop ***************************/
406 /* background mode */
407 if (iop == BACKGROUND_MODE)
408 return;
410 if (rpt >= 3)
412 root->flags |= draw;
413 DRAW = CP[101]; /* Repetition */
415 else
418 * If there are no moves and we're not in check (stalemate) then
419 * it's mate in shogi (whereas it's a draw in chess).
422 if (GameCnt == MAXMOVES)
424 root->flags |= draw;
425 DRAW = CP[80]; /* Max Moves */
429 /* not in book so set hint to guessed move for other side */
430 if (!bookflag)
431 hint = ((PrVar[1]) ? PrVar[2] : 0);
433 /* if not mate or draw make move and output it */
434 if (((score > -(SCORE_LIMIT + 999))
435 && (rpt <= 3)) || (root->flags & draw))
437 MakeMove(side, &Tree[0], &tempb, &tempc,
438 &tempsf, &tempst, &INCscore);
439 algbr(root->f, root->t, (short) root->flags);
441 else
443 algbr(0, 0, 0); /* Zero move string when mate. */
444 root->score = score; /* When mate, ignore distinctions!
445 * --SMC */
448 g = &GameList[GameCnt];
450 if ((g->flags & capture) && (g->piece == king))
451 flag.mate = flag.illegal = true;
453 /* If Time Control get the elapsed time */
454 if (TCflag)
455 ElapsedTime(COMPUTE_AND_INIT_MODE);
457 /* update time control info */
458 OutputMove();
460 /* if mate set flag */
461 if ((score == -(SCORE_LIMIT + 999) || score == (SCORE_LIMIT + 998)))
462 flag.mate = true;
464 /* add move to game list */
465 g->score = score;
466 g->nodes = NodeCnt;
467 g->time = (et +50)/100;
468 /* g->time = TCcount; */
469 g->depth = Sdepth;
471 /* update time control info */
472 if (TCflag)
474 TimeControl.clock[side] -= (et + OperatorTime);
475 timecomp[compptr] = (et + OperatorTime);
477 /* finished our required moves - setup the next set */
478 --TimeControl.moves[side];
481 /* check for end conditions */
482 if ((root->flags & draw) /* && flag.bothsides */)
484 flag.mate = true;
486 else if (GameCnt == MAXMOVES)
488 flag.mate = true;
490 /* out of move store, you lose */
491 else
493 /* switch to other side */
494 player = xside;
497 /* if mate clear hint */
498 if (flag.mate)
499 hint = 0;
501 Sdepth = 0;
507 * Perform an alpha-beta search to determine the score for the current
508 * board position. If depth <= 0 only capturing moves and responses to
509 * check are generated and searched, otherwise all moves are processed. The
510 * search depth is modified for check evasions, certain re-captures and
511 * threats. Extensions may continue for up to 11 ply beyond the nominal
512 * search depth.
516 search(short side,
517 short ply,
518 short depth,
519 short alpha,
520 short beta,
521 unsigned short *bstline,
522 short *rpt)
524 short j, pnt;
525 short tempb, tempc, tempsf, tempst;
526 short xside, pbst, score, rcnt, in_check, blockable;
527 unsigned short mv, nxtline[MAXDEPTH];
528 struct leaf *node, tmp;
529 short best = -(SCORE_LIMIT + 3000);
530 short bestwidth = 0;
531 short mustcut;
533 #ifdef NULLMOVE
534 short PVsave;
535 short PVarisave;
536 #endif
538 NodeCnt++;
540 /* look every ZNODE nodes for a timeout */
541 #ifdef NULLMOVE
542 if (!null)
544 #endif
545 if (NodeCnt > ETnodes)
547 ElapsedTime(COMPUTE_MODE);
549 if (flag.back)
551 flag.back = false;
552 flag.timeout = true;
553 flag.musttimeout = false;
555 else if (TCflag || MaxResponseTime)
557 if ((et >= (ResponseTime + ExtraTime))
558 && (Sdepth > MINDEPTH))
560 /* try to extend to finish ply */
561 if (flag.back || (TCflag && TCcount < MAXTCCOUNTX))
563 flag.back = false;
564 flag.musttimeout = true;
565 TCcount++;
566 ExtraTime += TCleft;
568 else
570 flag.back = false;
571 flag.timeout = true;
572 flag.musttimeout = false;
576 else if (flag.back)
578 flag.back = false;
579 flag.timeout = true;
580 flag.musttimeout = false;
583 #ifdef QUIETBACKGROUND
584 if (!background)
585 #endif
586 ShowResponseTime();
588 else if (!TCflag && flag.musttimeout && Sdepth > MINDEPTH)
590 flag.timeout = true;
591 flag.musttimeout = false;
593 #ifdef NULLMOVE
595 #endif
597 xside = side ^ 1;
598 score = evaluate(side, ply, alpha, beta,
599 INCscore, &in_check, &blockable);
602 * check for possible repitition if so call repitition - rpt is
603 * repeat count
606 if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
608 *rpt = repetition();
611 * repeat position >3 don't need to return score it's taken
612 * care of above
615 if (*rpt == 1)
617 score /= 3;
618 score *= 2;
620 else if (*rpt == 2)
621 score /= 2;
623 else
625 *rpt = 0;
628 /* score > SCORE_LIMIT its a draw or mate */
629 if (score > SCORE_LIMIT)
631 bstline[ply] = 0;
632 return score;
635 /* Do we need to add depth because of special conditions */
636 /* if in check or in capture sequence search deeper */
638 /***************** depth extensions *****************/
640 if (depth > 0)
642 /* Allow opponent a chance to check again */
643 if (in_check)
645 if (depth < 2)
646 depth = 2;
648 else if (flag.rcptr
649 && (score > alpha) && (score < beta)
650 && (ply > 2)
651 && CptrFlag[ply - 1] && CptrFlag[ply - 2])
653 if (hard_time_limit)
655 if (!flag.timeout)
656 ++depth;
658 else
660 ++depth;
665 else
667 short timeout = 0;
669 if (hard_time_limit)
670 timeout = flag.timeout;
672 if ((score >= alpha)
673 && (in_check
674 || ((!timeout && (hung[side] > 1))
675 && (ply == Sdepth + 1))))
677 depth = 1;
679 else if ((score <= beta)
680 && (((ply < Sdepth + 4) && (ply > 4))
681 && ChkFlag[ply - 2]
682 && ChkFlag[ply - 4]
683 && (ChkFlag[ply - 2] != ChkFlag[ply - 4])))
685 depth = 1;
689 /***************************************************/
690 /* try the local transition table if it's there */
692 #if ttblsz
693 if (/* depth > 0 && */ flag.hash && ply > 1)
695 if (use_ttable
696 && ProbeTTable(side, depth, ply, &alpha, &beta, &score) == true)
698 bstline[ply] = PV;
699 bstline[ply + 1] = 0;
701 if (beta == -((SCORE_LIMIT + 1000) * 2))
702 return score;
704 if (alpha > beta)
705 return alpha;
708 #ifdef HASHFILE
709 /* ok try the transition file if its there */
710 else if (hashfile
711 && (depth > HashDepth)
712 && (GameCnt < HashMoveLimit)
713 && (ProbeFTable(side, depth, ply, &alpha, &beta, &score)
714 == true))
716 PutInTTable(side, score, depth, ply, alpha, beta, PV);
717 bstline[ply] = PV;
718 bstline[ply + 1] = 0;
720 if (beta == -((SCORE_LIMIT + 1000) * 2))
721 return score;
723 if (alpha > beta)
725 return alpha;
728 #endif /* HASHFILE */
730 #endif /* ttblsz */
732 if (TrPnt[ply] > (TREE - 300))
733 mustcut = true;
734 else
735 mustcut = false;
738 * If more then DepthBeyond ply past goal depth or at goal depth and
739 * score > beta quit - means we are out of the window.
742 if (mustcut || (ply > DepthBeyond) || ((depth < 1) && (score > beta)))
743 return score;
746 * If below first ply and not at goal depth generate all moves else
747 * only capture moves.
750 if (ply > 1)
752 if ((depth > 0) || (ply < (SDEPTHLIM))
753 || (background && (ply < Sdepth + 2)))
754 MoveList(side, ply, in_check, blockable);
755 else
756 CaptureList(side, ply, in_check, blockable);
759 /* no moves return what we have */
762 * normally a search will continue til past goal and no more capture
763 * moves exist
766 /* unless it hits DepthBeyond */
767 if (TrPnt[ply] == TrPnt[ply + 1])
768 return score;
770 /* if not at goal set best = -inf else current score */
771 best = (depth > 0) ? -(SCORE_LIMIT + 3000) : score;
773 #ifdef NULLMOVE
775 PVarisave = PVari;
777 /* CHECKME: is the & really an && here? */
778 if (!null && /* no previous null-move */
779 !PVari && /* no null-move during the PV */
780 (ply > 2) & /* not at ply 1 */
781 (ply <= Sdepth) &&
782 (depth > 3) &&
783 !in_check) /* no check */
784 /* enough material such that zugzwang is unlikely
785 * but who knows which value is suitable? */
788 OK, we make a null move, i.e. this means we have nothing to do
789 but we have to keep the some arrays up to date otherwise gnushogi
790 gets confused. Maybe somebody knows exactly which information is
791 important and which isn't.
793 Another idea is that we try the null-move first and generate the
794 moves later. This may save time but we have to take care that
795 PV and other variables contain the right value so that the move
796 ordering works right.
799 struct GameRec *g;
801 nxtline[ply + 1] = 0;
802 CptrFlag[ply] = 0;
803 TesujiFlag[ply] = 0;
804 Tscore[ply] = score;
805 PVsave = PV;
806 PV = 0;
807 null = 1;
808 g = &GameList[++GameCnt];
809 g->hashkey = hashkey;
810 g->hashbd = hashbd;
811 FROMsquare = TOsquare = -1;
812 g->Game50 = Game50;
813 g->gmove = -1;
814 g->flags = 0;
815 g->piece = 0;
816 g->color = neutral;
818 best = -search(xside, ply + 1, depth - 2,
819 -beta - 1, -beta, nxtline, &rcnt);
820 null = 0;
821 PV = PVsave;
822 GameCnt--;
824 if (best < alpha)
826 best = -(SCORE_LIMIT + 3000);
828 else if (best > beta)
830 return best;
832 else
834 best = -(SCORE_LIMIT + 3000);
837 #endif
839 /* if best so far is better than alpha set alpha to best */
840 if (best > alpha)
841 alpha = best;
843 /********************** main loop ****************************/
845 /* look at each move until no more or beta cutoff */
846 for (pnt = pbst = TrPnt[ply];
847 (pnt < TrPnt[ply + 1]) && (best <= beta);
848 pnt++)
850 /* find the most interesting looking of the remaining moves */
851 if (ply > 1)
852 pick(pnt, TrPnt[ply + 1] - 1);
854 #ifdef NULLMOVE
855 PVari = PVarisave && (pnt == TrPnt[ply]); /* Is this the PV? */
856 #endif
858 node = &Tree[pnt];
860 /* is this a forbidden move */
861 if (/* ply == 1 && */ node->score <= DONTUSE)
862 continue;
864 nxtline[ply + 1] = 0;
866 /* if at top level */
867 #if !defined NOPOST
868 if (ply == 1)
870 /* at the top update search status */
871 if (flag.post)
873 #ifdef QUIETBACKGROUND
874 if (!background)
875 #endif /* QUIETBACKGROUND */
876 ShowCurrentMove(pnt, node->f, node->t);
879 #endif
881 if (!(node->flags & exact))
883 /* make the move and go deeper */
885 MakeMove(side, node, &tempb, &tempc, &tempsf,
886 &tempst, &INCscore);
887 CptrFlag[ply] = ((node->flags & capture) != 0);
888 TesujiFlag[ply] = (node->flags & tesuji)
889 && (node->flags & dropmask);
890 Tscore[ply] = node->score;
891 PV = node->reply;
893 node->score = -search(xside, ply + 1,
894 (depth > 0) ? (depth - 1) : 0,
895 -beta, -alpha,
896 nxtline, &rcnt);
899 * if(!flag.timeout)
900 * node->score = score;
903 node->width = ((ply % 2) == 1)
904 ? (TrPnt[ply + 2] - TrPnt[ply + 1])
905 : 0;
907 if ((node->score > SCORE_LIMIT) || (node->score < -SCORE_LIMIT) )
908 node->flags |= exact;
909 else if (rcnt == 1)
910 node->score /= 2;
912 if (((rcnt >= 3)
913 || ((node->score == (SCORE_LIMIT + 999) - ply)
914 && !ChkFlag[ply])))
916 node->flags |= (draw | exact);
917 DRAW = CP[58]; /* Draw */
918 node->score = ((side == computer) ? contempt : -contempt);
921 node->reply = nxtline[ply + 1];
923 /* reset to try next move */
924 UnmakeMove(side, node, &tempb, &tempc, &tempsf, &tempst);
927 /* if best move so far */
928 /* CHECKME: flag.timeout isn't valid if no hard time limit */
929 if (!flag.timeout
930 && ((node->score > best)
931 || ((node->score == best) && (node->width > bestwidth))))
934 * All things being equal pick the denser part of the
935 * tree.
937 bestwidth = node->width;
940 * If not at goal depth and better than alpha and not
941 * an exact score increment by depth.
944 if ((depth > 0) && (node->score > alpha)
945 && !(node->flags & exact))
947 node->score += depth;
950 best = node->score;
951 pbst = pnt;
953 if (best > alpha)
954 alpha = best;
956 /* update best line */
957 for (j = ply + 1; nxtline[j] > 0; j++)
958 bstline[j] = nxtline[j];
960 bstline[j] = 0;
961 bstline[ply] = (node->f << 8) | node->t;
963 /* if at the top */
964 if (ply == 1)
967 * If it's better than the root score make it the root.
969 if ((best > root->score)
970 || ((best == root->score)
971 && (bestwidth > root->width)))
973 tmp = Tree[pnt];
975 for (j = pnt - 1; j >= 0; j--)
976 Tree[j + 1] = Tree[j];
978 Tree[0] = tmp;
979 pbst = 0;
982 #ifdef QUIETBACKGROUND
983 if (!background)
985 #endif /* QUIETBACKGROUND */
986 if (Sdepth > 2)
988 if (best > beta)
990 ShowResults(best, bstline, '+');
992 else if (best < alpha)
994 ShowResults(best, bstline, '-');
996 else
998 ShowResults (best, bstline, '&');
1001 #ifdef QUIETBACKGROUND
1003 #endif
1007 if (flag.timeout)
1008 return Tscore[ply - 1];
1011 /******************************************************/
1013 node = &Tree[pbst];
1014 mv = (node->f << 8) | node->t;
1016 #ifdef NULLMOVE
1017 PVari = PVarisave;
1018 #endif
1021 * We have a move so put it in local table - if it's already there
1022 * done else if not there or needs to be updated also put it in
1023 * hashfile
1026 #if ttblsz
1027 if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
1029 # ifdef HASHFILE /* MCV: warning: this confuses the formatter. */
1030 if (use_ttable
1031 && PutInTTable(side, best, depth, ply, alpha, beta, mv)
1032 && hashfile
1033 && (depth > HashDepth)
1034 && (GameCnt < HashMoveLimit))
1035 # else
1036 if (use_ttable
1037 && PutInTTable(side, best, depth, ply, alpha, beta, mv))
1038 # endif
1040 PutInFTable(side, best, depth, ply,
1041 alpha, beta, node->f, node->t);
1044 #endif /* ttblsz */
1046 if (depth > 0)
1048 #if defined HISTORY
1049 unsigned short h, x;
1050 h = mv;
1052 if (history[x = hindex(side, h)] < HISTORYLIM)
1053 history[x] += (unsigned short) 1 << depth;
1054 #endif
1056 if (node->t != (short)(GameList[GameCnt].gmove & 0xFF))
1058 if (best <= beta)
1060 killr3[ply] = mv;
1062 else if (mv != killr1[ply])
1064 killr2[ply] = killr1[ply];
1065 killr1[ply] = mv;
1069 killr0[ply] = ((best > SCORE_LIMIT) ? mv : 0);
1072 return best;
1078 * Update the PieceList and Pindex arrays when a piece is captured or when a
1079 * capture is unmade.
1082 void
1083 UpdatePieceList(short side, short sq, UpdatePieceList_mode iop)
1085 short i;
1087 if (iop == REMOVE_PIECE)
1089 PieceCnt[side]--;
1091 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1093 PieceList[side][i] = PieceList[side][i + 1];
1094 Pindex[PieceList[side][i]] = i;
1097 else if (board[sq] == king)
1099 /* king must have index 0 */
1100 for (i = PieceCnt[side]; i >= 0; i--)
1102 PieceList[side][i + 1] = PieceList[side][i];
1103 Pindex[PieceList[side][i + 1]] = i + 1;
1106 PieceCnt[side]++;
1107 PieceList[side][0] = sq;
1108 Pindex[sq] = 0;
1110 else
1112 PieceCnt[side]++;
1113 PieceList[side][PieceCnt[side]] = sq;
1114 Pindex[sq] = PieceCnt[side];
1120 /* Make or Unmake drop move. */
1122 void
1123 drop(short side, short piece, short f, short t, short iop)
1125 if (iop == 1)
1127 short n;
1128 board[t] = piece;
1129 color[t] = side;
1131 #if !defined SAVE_SVALUE
1132 svalue[t] = 0;
1133 #endif
1135 n = Captured[side][piece]--;
1137 UpdateDropHashbd(side, piece, n);
1138 UpdateHashbd(side, piece, -1, t);
1139 UpdatePieceList(side, t, ADD_PIECE);
1141 if (piece == pawn)
1143 ++PawnCnt[side][column(t)];
1146 Mvboard[t]++;
1147 HasPiece[side][piece]++;
1149 else
1151 short n;
1152 board[t] = no_piece;
1153 color[t] = neutral;
1154 n = ++Captured[side][piece];
1156 UpdateDropHashbd(side, piece, n);
1157 UpdateHashbd(side, piece, -1, t);
1158 UpdatePieceList(side, t, REMOVE_PIECE);
1160 if (piece == pawn)
1161 --PawnCnt[side][column(t)];
1163 Mvboard[t]--;
1164 HasPiece[side][piece]--;
1169 #ifdef HASHKEYTEST
1171 CheckHashKey()
1173 unsigned long chashkey, chashbd;
1174 short side, sq;
1175 chashbd = chashkey = 0;
1177 for (sq = 0; sq < NO_SQUARES; sq++)
1179 if (color[sq] != neutral)
1181 chashbd ^= (*hashcode)[color[sq]][board[sq]][sq].bd;
1182 chashkey ^= (*hashcode)[color[sq]][board[sq]][sq].key;
1185 /* hashcodes for initial board are 0 ! */
1186 if (Stcolor[sq] != neutral)
1188 chashbd ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].bd;
1189 chashkey ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].key;
1193 for (side = 0; side <= 1; side++)
1195 short piece;
1197 for (piece = 0; piece < NO_PIECES; piece++)
1199 short n = Captured[side][piece];
1201 if (n > 0)
1203 short i;
1205 for (i = 1; i <= n; i++)
1207 chashbd ^= (*drop_hashcode)[side][piece][i].bd;
1208 chashkey ^= (*drop_hashcode)[side][piece][i].key;
1214 if (chashbd != hashbd)
1215 printf("chashbd %lu != hashbd %lu\n", chashbd, hashbd);
1217 if (chashkey != hashkey)
1218 printf("chashkey %lu != hashkey %lu\n", chashkey, hashkey);
1220 if (chashbd != hashbd || chashkey != hashkey)
1221 return 1;
1223 return 0;
1225 #endif
1231 * Update Arrays board[], color[], and Pindex[] to reflect the new board
1232 * position obtained after making the move pointed to by node. Also update
1233 * miscellaneous stuff that changes when a move is made.
1236 void
1237 MakeMove(short side,
1238 struct leaf *node,
1239 short *tempb, /* piece at to square */
1240 short *tempc, /* color of to square */
1241 short *tempsf, /* static value of piece on from */
1242 short *tempst, /* static value of piece on to */
1243 short *INCscore) /* score increment */
1245 short f, t, xside;
1246 struct GameRec *g;
1247 short fromb, fromc;
1249 xside = side ^ 1;
1250 g = &GameList[++GameCnt];
1251 g->hashkey = hashkey;
1252 g->hashbd = hashbd;
1253 FROMsquare = f = node->f;
1254 TOsquare = t = (node->t & 0x7f);
1255 *INCscore = (short)node->INCscore;
1256 g->Game50 = Game50;
1257 g->gmove = (f << 8) | node->t;
1258 g->flags = node->flags;
1260 #ifdef HASHKEYTEST
1261 if (CheckHashKey())
1263 short i;
1264 algbr(f, t, node->flags);
1265 printf("error before MakeMove: %s\n", mvstr[0]);
1266 UpdateDisplay(0, 0, 1, 0);
1268 for (i = 1; i <= GameCnt; i++)
1270 movealgbr(GameList[i].gmove, mvstr[0]);
1271 printf("%d: %s\n", i, mvstr[0]);
1274 exit(1);
1276 #endif
1278 rpthash[side][hashkey & 0xFF]++, ISZERO++;
1280 if (f > NO_SQUARES)
1282 g->fpiece = (node->flags & pmask);
1283 g->piece = *tempb = no_piece;
1284 g->color = *tempc = neutral;
1286 #if !defined SAVE_SVALUE
1287 *tempsf = 0;
1288 *tempst = svalue[t];
1289 #endif
1291 (void)drop(side, g->fpiece, f, t, 1);
1293 else
1295 #if !defined SAVE_SVALUE
1296 *tempsf = svalue[f];
1297 *tempst = svalue[t];
1298 #endif
1300 g->fpiece = board[f];
1301 g->piece = *tempb = board[t];
1302 g->color = *tempc = color[t];
1303 fromb = board[f];
1304 fromc = color[f];
1306 if (*tempc != neutral)
1308 /* Capture a piece */
1309 UpdatePieceList(*tempc, t, REMOVE_PIECE);
1311 /* if capture decrement pawn count */
1312 if (*tempb == pawn)
1313 --PawnCnt[*tempc][column(t)];
1315 mtl[xside] -= (*value)[stage][*tempb];
1316 HasPiece[xside][*tempb]--;
1319 short n, upiece = unpromoted[*tempb];
1321 /* add "upiece" captured by "side" */
1322 n = ++Captured[side][upiece];
1324 UpdateDropHashbd(side, upiece, n);
1325 mtl[side] += (*value)[stage][upiece];
1328 /* remove "*tempb" of "xside" from board[t] */
1329 UpdateHashbd(xside, *tempb, -1, t);
1331 #if !defined SAVE_SVALUE
1332 *INCscore += *tempst; /* add value of catched piece
1333 * to own score */
1334 #endif
1336 Mvboard[t]++;
1339 color[t] = fromc;
1341 #if !defined SAVE_SVALUE
1342 svalue[t] = svalue[f];
1343 svalue[f] = 0;
1344 #endif
1346 Pindex[t] = Pindex[f];
1347 PieceList[side][Pindex[t]] = t;
1348 color[f] = neutral;
1349 board[f] = no_piece;
1351 if (node->flags & promote)
1353 short tob;
1355 board[t] = tob = promoted[fromb];
1357 /* remove unpromoted piece from board[f] */
1358 UpdateHashbd(side, fromb, f, -1);
1360 /* add promoted piece to board[t] */
1361 UpdateHashbd(side, tob, -1, t);
1362 mtl[side] += value[stage][tob] - value[stage][fromb];
1364 if (fromb == pawn)
1365 --PawnCnt[side][column(f)];
1367 HasPiece[side][fromb]--;
1368 HasPiece[side][tob]++;
1370 #if !defined SAVE_SVALUE
1371 *INCscore -= *tempsf;
1372 #endif
1374 else
1376 board[t] = fromb;
1377 /* remove piece from board[f] and add it to board[t] */
1378 UpdateHashbd(side, fromb, f, t);
1381 Mvboard[f]++;
1384 #ifdef HASHKEYTEST
1385 algbr(f, t, node->flags);
1387 if (CheckHashKey())
1389 printf("error in MakeMove: %s\n", mvstr[0]);
1390 exit(1);
1392 #endif
1399 * Take back a move.
1402 void
1403 UnmakeMove(short side,
1404 struct leaf *node,
1405 short *tempb,
1406 short *tempc,
1407 short *tempsf,
1408 short *tempst)
1410 short f, t, xside;
1412 xside = side ^ 1;
1413 f = node->f;
1414 t = node->t & 0x7f;
1415 Game50 = GameList[GameCnt].Game50;
1417 if (node->flags & dropmask)
1419 (void)drop(side, (node->flags & pmask), f, t, 2);
1421 #if !defined SAVE_SVALUE
1422 svalue[t] = *tempst;
1423 #endif
1425 else
1427 short tob, fromb;
1429 color[f] = color[t];
1430 board[f] = tob = fromb = board[t];
1432 #if !defined SAVE_SVALUE
1433 svalue[f] = *tempsf;
1434 #endif
1436 Pindex[f] = Pindex[t];
1437 PieceList[side][Pindex[f]] = f;
1438 color[t] = *tempc;
1439 board[t] = *tempb;
1441 #if !defined SAVE_SVALUE
1442 svalue[t] = *tempst;
1443 #endif
1445 /* Undo move */
1446 if (node->flags & promote)
1448 board[f] = fromb = unpromoted[tob];
1449 mtl[side] += value[stage][fromb] - value[stage][tob];
1451 if (fromb == pawn)
1452 ++PawnCnt[side][column(f)];
1454 HasPiece[side][fromb]++;
1455 HasPiece[side][tob]--;
1457 /* add unpromoted piece to board[f] */
1458 UpdateHashbd(side, fromb, f, -1);
1460 /* remove promoted piece from board[t] */
1461 UpdateHashbd(side, tob, -1, t);
1463 else
1465 if (fromb == pawn)
1467 --PawnCnt[side][column(t)];
1468 ++PawnCnt[side][column(f)];
1471 /* remove piece from board[t] and add it to board[f] */
1472 UpdateHashbd(side, fromb, f, t);
1475 /* Undo capture */
1476 if (*tempc != neutral)
1478 short n, upiece = unpromoted[*tempb];
1480 UpdatePieceList(*tempc, t, ADD_PIECE);
1482 if (*tempb == pawn)
1483 ++PawnCnt[*tempc][column(t)];
1485 mtl[xside] += (*value)[stage][*tempb];
1486 HasPiece[xside][*tempb]++;
1487 mtl[side] -= (*value)[stage][upiece];
1489 /* remove "upiece" captured by "side" */
1490 n = Captured[side][upiece]--;
1492 UpdateDropHashbd(side, upiece, n);
1494 /* replace captured piece on board[t] */
1495 UpdateHashbd(xside, *tempb, -1, t);
1496 Mvboard[t]--;
1499 Mvboard[f]--;
1502 GameCnt--;
1503 rpthash[side][hashkey & 0xFF]--, ISZERO--;
1505 #ifdef HASHKEYTEST
1506 algbr(f, t, node->flags);
1508 if (CheckHashKey())
1510 printf("error in UnmakeMove: %s\n", mvstr[0]);
1511 exit(1);
1513 #endif
1519 * Scan thru the board seeing what's on each square. If a piece is found,
1520 * update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1521 * determine the material for each side and set the hashkey and hashbd
1522 * variables to represent the current board position. Array
1523 * PieceList[side][indx] contains the location of all the pieces of either
1524 * side. Array Pindex[sq] contains the indx into PieceList for a given
1525 * square.
1528 void
1529 InitializeStats(void)
1531 short i, sq;
1533 for (i = 0; i < NO_COLS; i++)
1534 PawnCnt[black][i] = PawnCnt[white][i] = 0;
1536 mtl[black] = mtl[white] = 0;
1537 PieceCnt[black] = PieceCnt[white] = 0;
1538 hashbd = hashkey = 0;
1540 for (sq = 0; sq < NO_SQUARES; sq++)
1542 if (color[sq] != neutral)
1544 mtl[color[sq]] += (*value)[stage][board[sq]];
1546 if (board[sq] == pawn)
1547 ++PawnCnt[color[sq]][column(sq)];
1549 Pindex[sq] = ((board[sq] == king) ? 0 : ++PieceCnt[color[sq]]);
1550 PieceList[color[sq]][Pindex[sq]] = sq;
1551 UpdateHashbd(color[sq], board[sq], sq, -1);
1554 /* hashcodes for initial board are 0 ! */
1555 if (Stcolor[sq] != neutral)
1556 UpdateHashbd(Stcolor[sq], Stboard[sq], sq, -1);
1560 short side;
1562 for (side = 0; side <= 1; side++)
1564 short piece;
1566 for (piece = 0; piece < NO_PIECES; piece++)
1568 short n = Captured[side][piece];
1570 if (n > 0)
1572 Captured[side][piece] = 0;
1574 for (i = 1; i <= n; i++)
1576 ++Captured[side][piece];
1577 UpdateDropHashbd(side, piece, i);
1578 mtl[side] += (*value)[stage][piece];
1585 #ifdef HASHKEYTEST
1586 if (CheckHashKey())
1588 printf("error in InitializeStats\n");
1589 exit(1);
1591 #endif