2 * search.c - C source for GNU SHOGI
4 * Copyright (c) 1993, 1994, 1995 Matthias Mutz
6 * GNU SHOGI is based on GNU CHESS
8 * Copyright (c) 1988,1989,1990 John Stanback Copyright (c) 1992 Free Software
11 * This file is part of GNU SHOGI.
13 * GNU Shogi is free software; you can redistribute it and/or modify it under
14 * the terms of the GNU General Public License as published by the Free
15 * Software Foundation; either version 1, or (at your option)
18 * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT ANY
19 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
23 * You should have received a copy of the GNU General Public License along with
24 * GNU Shogi; see the file COPYING. If not, write to the Free Software
25 * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31 #if !defined OLDTIME && defined HASGETTIMEOFDAY
35 static short int DepthBeyond;
36 unsigned short int PrVar[MAXDEPTH];
37 extern short int recycle, ISZERO;
39 short int null; /* Null-move already made or not */
40 short int PVari; /* Is this the PV */
46 unsigned short DBLINE[MAXDEPTH];
47 struct leaf far *dbptr;
54 extern short debug_eval;
55 extern FILE *debug_eval_file;
64 debug41 (short int score, short unsigned int xxx[], char ch)
69 struct leaf far *xnode;
71 D = fopen ("/tmp/DEBUG", "a+");
78 fprintf (D, "%2d%c %6d %4ld %8ld ", Sdepth, ch, score, et / 100, NodeCnt);
80 for (i = 1; xxx[i]; i++)
82 if ((i > 1) && (i % 8 == 1))
84 algbr ((short) (xxx[i] >> 8), (short) (xxx[i] & 0xFF), false);
85 fprintf (D, "%5s ", mvstr[0]);
96 /* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
104 /* Check for draw by fourfold repetition
105 * (same side, same captures, same board).
106 * WARNING: this is not save yet due to possible hash collisions.
110 short int i, cnt = 0;
113 struct GameRec far *g;
115 if (GameCnt > Game50 + 6)
117 for (i = GameCnt-1; i >= Game50; i -= 2)
120 if ( g->hashkey == hashkey && g->hashbd == hashbd )
133 int plyscore, globalscore;
135 pick (short int p1, short int p2)
138 * Find the best move in the tree between indexes p1 and p2. Swap the best
139 * move into the p1 element.
143 register struct leaf far *p, *q, *r, *k;
150 for (r = p + 1; r <= q; r++)
167 unsigned short trace[MAXDEPTH];
169 unsigned short tracelog[MAXDEPTH];
174 int bookflag = false;
177 /* #define PLYDEBUG */
180 static int MaxPly = 0;
181 static int MaxDepth = 0;
190 static void debug4(short Sdepth, short alpha, short beta, short stage)
196 printf ("Sdepth %d alpha %d beta %d stage %d\n", Sdepth, alpha, beta, stage);
197 for (j = 1; j < 2; j++)
201 for (idb = TrPnt[j]; idb < TrPnt[j + 1]; idb++)
203 algbr (Tree[idb].f, Tree[idb].t, Tree[idb].flags);
204 printf ("level 4 %d-->%d %s %d %d\n", j, idb, mvstr[0], Tree[idb].score, Tree[idb].width);
213 SelectMove (short int side, SelectMove_mode iop)
217 * Select a move by calling function search() at progressively deeper ply
218 * until time is up or a mate or draw is reached. An alpha-beta window of
219 * -Awindow to +Bwindow points is set around the score returned from the
220 * previous iteration. If Sdepth != 0 then the program has correctly
221 * predicted the opponents move and the search will start at a depth of
222 * Sdepth+1 rather than a depth of 1.
226 static short int i, tempb, tempc, tempsf, tempst, xside, rpt;
227 static short int alpha, beta, score;
228 static struct GameRec far *g;
230 short sqking, in_check, blockable;
239 if ( debuglevel & (512 | 1024) ) {
241 short c1,c2,r1,r2,piece;
250 traceply = atoi(&b[1]);
251 else if ( b[0] == '\0' )
255 if ( b[1] = '*' || b[1] == '\'' )
257 for (piece = pawn; piece <= king; piece++)
258 if ( b[0] == pxx[piece] || b[0] == qxx[piece] )
264 trace[++tracen] = ((NO_SQUARES+piece) << 8) | locn (r2, c2);
272 trace[++tracen] = (locn (r1, c1) << 8) | locn (r2, c2);
274 trace[tracen] |= 0x80;
277 if (tracen == 0 && traceply > 0)
286 printf("hashbd = %ld (hashkey>>16)|side = %d\n",
287 hashbd,(hashkey>>16)|side);
290 flag.timeout = false;
292 flag.musttimeout = false;
297 recycle = (GameCnt % rehash) - rehash;
300 ExaminePosition (side);
302 /* if background mode set to infinite */
303 if (iop == BACKGROUND_MODE)
306 /* if background mode set response time to infinite */
307 ResponseTime = 9999999;
312 SetResponseTime (side);
315 #ifdef QUIETBACKGROUND
317 #endif /* QUIETBACKGROUND */
322 score = ScorePosition (side);
324 #ifdef QUIETBACKGROUND
326 #endif /* QUIETBACKGROUND */
329 #ifdef QUIETBACKGROUND
331 #endif /* QUIETBACKGROUND */
332 SearchStartStuff (side);
335 array_zero (history, sizeof_history);
338 FROMsquare = TOsquare = -1;
340 if (iop == FOREGROUND_MODE)
345 char buf1[8], buf2[8], buf3[8], buf4[8];
346 movealgbr(GameList[GameCnt].gmove,buf1);
347 movealgbr(PrVar[1],buf2);
348 movealgbr(PrVar[2],buf3);
349 movealgbr(PrVar[3],buf4);
350 printf("gmove: %s PrVar[1]: %s PrVar[2]: %s PrVar[3]: %s\n",
351 buf1, buf2, buf3, buf4);
356 * If the last move was the hint, select the computed answer to the
357 * hint as first move to examine.
362 SwagHt = (GameList[GameCnt].gmove == PrVar[2]) ? PrVar[3] : 0;
370 movealgbr(SwagHt,buf);
371 printf("SwagHt = %s\n", buf);
375 for (i = 0; i < MAXDEPTH; i++)
376 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
378 /* set initial window for search */
381 alpha = -(SCORE_LIMIT+999);
382 beta = SCORE_LIMIT+999;
384 alpha = score - ((computer == white) ? BAwindow : WAwindow);
385 beta = score + ((computer == white) ? BBwindow : WBwindow);
392 sqking = PieceList[side][0];
393 in_check = (board[sqking] == king) ? SqAtakd(sqking, side^1, &blockable) : false;
395 MoveList (side, 1, in_check, blockable);
396 for (i = TrPnt[1]; i < TrPnt[2]; i++)
397 if (!pick (i, TrPnt[2] - 1))
403 for (j = TrPnt[1]; j < TrPnt[2]; j++)
405 struct leaf far *node = &Tree[j];
406 algbr (node->f, node->t, node->flags);
407 fprintf (debug_eval_file, "%s %s %s %s %d",
408 mvstr[0], mvstr[1], mvstr[2], mvstr[3],node->score);
411 FlagString(node->flags, s);
412 fprintf(debug_eval_file,"%s",s);
414 fprintf (debug_eval_file, "\n");
419 /* can I get a book move? */
421 if (flag.regularstart && Book)
423 flag.timeout = bookflag = OpeningBook (&hint, side);
426 ResponseTime += ResponseTime;
429 /* zero stats for hash table */
431 reminus = replus = 0;
432 GenCnt = NodeCnt = ETnodes = EvalNodes = HashCnt = FHashAdd = HashAdd = FHashCnt = THashCol = HashCol = 0;
434 globalscore = plyscore = score;
439 debug4(Sdepth,alpha,beta,stage);
442 /********************* main loop ********************************/
444 Sdepth = (MaxSearchDepth < (MINDEPTH-1)) ? MaxSearchDepth : (MINDEPTH-1);
446 while (!flag.timeout)
448 /* go down a level at a time */
454 /* terminate search at DepthBeyond ply past goal depth */
456 DepthBeyond = Sdepth;
459 DepthBeyond = Sdepth + ((Sdepth == 1) ? 3 : 5);
461 DepthBeyond = Sdepth + ((Sdepth == 1) ? 7 : 11);
464 #if !defined BAREBONES
465 #ifdef QUIETBACKGROUND
467 #endif /* QUIETBACKGROUND */
470 /* search at this level returns score of PV */
471 score = search (side, 1, Sdepth, alpha, beta, PrVar, &rpt);
473 /* save PV as killer */
474 for (i = 1; i <= Sdepth; i++)
475 killr0[i] = PrVar[i];
477 /* low search failure re-search with (-inf,score) limits */
480 #if !defined BAREBONES
482 #ifdef QUIETBACKGROUND
484 #endif /* QUIETBACKGROUND */
487 if (TCflag && TCcount < MAXTCCOUNTR)
490 ExtraTime += (MAXTCCOUNTR - TCcount) * TCleft;
492 ExtraTime += (8 * TCleft);
494 TCcount = MAXTCCOUNTR - 1;
497 score = search (side, 1, Sdepth, -(SCORE_LIMIT+999), (SCORE_LIMIT+999), PrVar, &rpt);
500 /* high search failure re-search with (score, +inf) limits */
501 else if (score > beta && !(root->flags & exact))
503 #if !defined BAREBONES
505 #ifdef QUIETBACKGROUND
507 #endif /* QUIETBACKGROUND */
510 score = search (side, 1, Sdepth, -(SCORE_LIMIT+999), (SCORE_LIMIT+999), PrVar, &rpt);
513 /**************** out of search ********************************************/
514 CheckForTimeout (score, globalscore, Jscore, zwndw);
516 /************************ time control ***********************************/
518 /* save PV as killer */
519 for (i = 1; i <= Sdepth + 1; i++)
520 killr0[i] = PrVar[i];
523 /* if (!flag.timeout) */
525 for (i = TrPnt[1]+1; i < TrPnt[2]; i++)
526 if (!pick (i, TrPnt[2] - 1))
529 /* if done or nothing good to look at quit */
530 if ((root->flags & exact) || (score < -SCORE_LIMIT))
532 /* find the next best move put below root */
534 if (flag.timeout && !background)
538 struct leaf far *xnode;
540 D = fopen ("/tmp/DEBUG", "a+");
541 fprintf (D, " %d ply %d sco %d TC %d gl %d cnt %d\n",
542 Sdepth, plyscore, score, TCcount,
543 globalpnt, TrPnt[2] - TrPnt[1]);
544 for (i = 1; tmp[i]; i++)
546 algbr (tmp[i] >> 8, tmp[i] & 0xff, 0);
547 fprintf (D, "%s ", mvstr[0]);
550 for (i = 1; PrVar[i]; i++)
552 algbr (PrVar[i] >> 8, PrVar[i] & 0xff, 0);
553 fprintf (D, "%s ", mvstr[0]);
556 algbr (root->f, root->t, root->flags);
557 fprintf (D, "%s ", mvstr[0]);
565 #if !defined NODYNALPHA
566 Jscore = (plyscore + score) >> 1;
568 zwndw = 20 + abs (Jscore / 12);
570 /* recompute search window */
571 beta = score + ((computer == white) ? BBwindow : WBwindow);
572 #if !defined NODYNALPHA
573 alpha = ((Jscore < score) ? Jscore : score) - ((computer == white) ? BAwindow : WAwindow) - zwndw;
575 alpha = score - ((computer == white) ? BAwindow : WAwindow);
578 #if !defined BAREBONES
579 #ifdef QUIETBACKGROUND
581 #endif /* QUIETBACKGROUND */
582 ShowResults (score, PrVar, '.');
584 debug41 (score, PrVar, '.');
592 printf ("Sdepth %d alpha %d beta %d stage %d\n", Sdepth, alpha, beta, stage);
593 for (j = 1; j < 2; j++)
597 for (idb = TrPnt[j]; idb < TrPnt[j + 1]; idb++)
599 algbr (Tree[idb].f, Tree[idb].t, Tree[idb].flags);
600 printf ("level 16 %d-->%d %s %d %d %x\n", Sdepth, idb, mvstr[0], Tree[idb].score, Tree[idb].width, Tree[idb].flags);
607 /******************************* end of main loop ***********************************/
609 /* background mode */
610 if (iop == BACKGROUND_MODE)
616 debug4(Sdepth,alpha,beta,stage);
622 DRAW = CP[101]; /* Repetition */
625 /* if no moves and not in check then mate for shogi (draw for chess) */
627 if ((score == -(SCORE_LIMIT+999)) && !(SqAtakd (PieceList[side][0], xside, &blocked)))
630 DRAW = CP[87]; /* No moves */
634 if (GameCnt == MAXMOVES)
637 DRAW = CP[80]; /* Max Moves */
639 /* not in book so set hint to guessed move for other side */
641 hint = ((PrVar[1]) ? PrVar[2] : 0);
643 /* if not mate or draw make move and output it */
644 if (((score > -(SCORE_LIMIT+999)) && (rpt <= 3)) || (root->flags & draw))
646 MakeMove (side, &Tree[0], &tempb, &tempc, &tempsf, &tempst, &INCscore);
647 algbr (root->f, root->t, (short) root->flags);
651 algbr (0, 0, 0); /* Zero move string when mate. */
652 root->score = score; /* When mate, ignore distinctions!
655 g = &GameList[GameCnt];
656 if ((g->flags & capture) && (g->piece == king))
658 flag.mate = flag.illegal = true;
660 /* If Time Control get the elapsed time */
662 ElapsedTime (COMPUTE_AND_INIT_MODE);
663 /* update time control info */
665 /* if mate set flag */
667 printf("score=%d\n",score);
669 if ((score == -(SCORE_LIMIT+999) || score == (SCORE_LIMIT+998)))
671 /* add move to game list */
674 g->time = (et +50)/100;
682 g->d2 = ResponseTime;
690 /* update time control info */
694 TimeControl.clock[side] -= (et + OperatorTime + 45);
695 timecomp[compptr] = (et + OperatorTime + 45);
697 TimeControl.clock[side] -= (et + OperatorTime);
698 timecomp[compptr] = (et + OperatorTime);
700 /* finished our required moves - setup the next set */
701 --TimeControl.moves[side];
703 /* check for end conditions */
704 if ((root->flags & draw) /* && flag.bothsides */ )
708 else if (GameCnt == MAXMOVES)
712 /* out of move store, you loose */
714 /* switch to other side */
716 /* if mate clear hint */
725 search (short int side,
726 register short int ply,
727 register short int depth,
730 short unsigned int *bstline,
734 * Perform an alpha-beta search to determine the score for the current board
735 * position. If depth <= 0 only capturing moves and
736 * responses to check are generated and searched, otherwise all moves are
737 * processed. The search depth is modified for check evasions, certain
738 * re-captures and threats. Extensions may continue for up to 11 ply beyond
739 * the nominal search depth.
744 register short j, pnt;
745 short tempb, tempc, tempsf, tempst;
746 short xside, pbst, score, rcnt, slk, in_check, blockable;
747 unsigned short mv, nxtline[MAXDEPTH];
748 struct leaf far *node, tmp;
749 short best = -(SCORE_LIMIT+3000);
764 printf("ply %d\n",ply);
766 if (depth > MaxDepth) {
768 printf("depth %d\n",depth);
771 /* look every ZNODE nodes for a timeout */
775 if (NodeCnt > ETnodes )
777 ElapsedTime (COMPUTE_MODE);
782 flag.musttimeout = false;
784 else if (TCflag || MaxResponseTime)
786 if ((et >= (ResponseTime + ExtraTime)) && (Sdepth > MINDEPTH) )
788 /* try to extend to finish ply */
789 if (flag.back || (TCflag && TCcount < MAXTCCOUNTX))
791 flag.musttimeout = true;
798 flag.musttimeout = false;
806 flag.musttimeout = false;
808 #ifdef QUIETBACKGROUND
813 else if (!TCflag && flag.musttimeout && Sdepth > MINDEPTH)
816 flag.musttimeout = false;
823 score = evaluate (side, ply, alpha, beta, INCscore, &in_check, &blockable);
826 * check for possible repitition if so call repitition - rpt is
829 if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
831 *rpt = repetition ();
834 * repeat position >3 don't need to return score it's taken
837 if (*rpt == 1) { score /= 3; score *= 2; }
838 else if (*rpt == 2) score /= 2;
843 /* score > SCORE_LIMIT its a draw or mate */
844 if (score > SCORE_LIMIT)
849 /* Do we need to add depth because of special conditions */
850 /* if in check or in capture sequence search deeper */
851 /*************************************** depth extensions ***********************************/
854 /* Allow opponent a chance to check again */
856 if (depth < 2) depth = 2;
857 } else if ( flag.rcptr &&
861 (score > alpha) && (score < beta) && (ply > 2) &&
862 CptrFlag[ply - 1] && CptrFlag[ply - 2])
867 if (score >= alpha &&
869 (in_check || (!flag.timeout && hung[side] > 1 && ply == Sdepth + 1)))
871 (in_check || (hung[side] > 1 && ply == Sdepth + 1)))
874 else if (score <= beta &&
875 ((ply < Sdepth + 4) && (ply > 4) &&
876 ChkFlag[ply - 2] && ChkFlag[ply - 4] &&
877 ChkFlag[ply - 2] != ChkFlag[ply - 4]))
880 else if ( score >= alpha &&
881 TesujiFlag[ply - 1] )
885 /*******************************************************************************************/
886 /* try the local transition table if it's there */
889 if ( /* depth > 0 && */ flag.hash && ply > 1 )
891 if (use_ttable && ProbeTTable (side, depth, ply, &alpha, &beta, &score) == true)
894 bstline[ply + 1] = 0;
898 algbr (PV >> 8, PV & 0xff, 0);
899 printf ("-get-> d=%d s=%d p=%d a=%d b=%d %s\n", depth, score, ply, alpha, beta, mvstr[0]);
902 if (beta == -((SCORE_LIMIT+1000)*2)) {
910 /* ok try the transition file if its there */
911 else if (hashfile && (depth > HashDepth) && (GameCnt < HashMoveLimit)
912 && (ProbeFTable (side, depth, ply, &alpha, &beta, &score) == true))
914 PutInTTable (side, score, depth, ply, alpha, beta, PV);
916 bstline[ply + 1] = 0;
917 if (beta == -((SCORE_LIMIT+1000)*2)) {
928 struct leaf far *xnode;
931 D = fopen ("/tmp/DEBUG", "w");
933 fprintf (D, "hashfile failure\n");
934 algbr (PV >> 8, PV & 0xff, 0);
935 fprintf (D, "inout move is %s\n", mvstr);
936 fprintf (D, "legal move are \n");
937 for (r = TrPnt[ply]; r < TrPnt[ply + 1]; r++)
940 algbr (xnode->f, xnode->t, (short) xnode->flags);
941 fprintf (D, "%s %s %s %s\n", mvstr[0], mvstr[1], mvstr[2], mvstr[3]);
948 #endif /* HASHFILE */
952 if ( TrPnt[ply] > TREE-300 )
956 printf("mustcut ply %d TrPnt[ply] %d\n",ply,TrPnt[ply]);
965 * if more then DepthBeyond ply past goal depth or at goal depth and
966 * score > beta quit - means we are out of the window
968 if (mustcut || ply > DepthBeyond || (depth < 1 && score > beta))
974 * if below first ply and not at goal depth generate all moves else
978 if (depth > 0 || ply < (SDEPTHLIM) ||
979 (background && ply < Sdepth + 2))
981 MoveList (side, ply, in_check, blockable);
985 CaptureList (side, ply, in_check, blockable);
988 /* no moves return what we have */
991 * normally a search will continue til past goal and no more capture
994 /* unless it hits DepthBeyond */
995 if (TrPnt[ply] == TrPnt[ply + 1])
1000 /* if not at goal set best = -inf else current score */
1001 best = (depth > 0) ? -(SCORE_LIMIT+3000) : score;
1005 if (!null && /* no previous null-move */
1006 !PVari && /* no null-move during the PV */
1007 (ply > 2) & /* not at ply 1 */
1010 !in_check) /* no check */
1011 /* enough material such that zugzwang is unlike but who knows which value
1015 /* ok, we make a null move, i.e. this means we have nothing to do
1016 but we have to keep the some arrays up to date otherwise gnuchess
1017 gets confused. Maybe somebody knows exactly which informations are
1018 important and which not.
1020 Another idea is that we try the null-move first and generate the
1021 moves later. This may save time but we have to take care that
1022 PV and other variables contain the right value so that the move
1023 ordering works right.
1025 register struct GameRec far *g;
1027 nxtline[ply + 1] = 0;
1029 TesujiFlag[ply] = 0;
1030 Tscore[ply] = score;
1034 g = &GameList[++GameCnt];
1035 g->hashkey = hashkey;
1037 FROMsquare = TOsquare = -1;
1044 best = -search (xside, ply+1, depth - 2, - beta-1, -beta, nxtline, &rcnt);
1049 best = -(SCORE_LIMIT+3000);
1050 else if (best > beta) {
1053 best = -(SCORE_LIMIT+3000);
1056 /* if best so far is better than alpha set alpha to best */
1059 /********************** main loop ************************************************************************/
1060 /* look at each move until no more or beta cutoff */
1061 for (pnt = pbst = TrPnt[ply]; pnt < TrPnt[ply + 1] && best <= beta; pnt++)
1063 /* find the most interesting looking of the remaining moves */
1065 pick (pnt, TrPnt[ply + 1] - 1);
1067 PVari = PVarisave && (pnt == TrPnt[ply]); /* Is this the PV? */
1071 /* is this a forbidden move */
1072 if (/* ply == 1 && */ node->score <= DONTUSE)
1075 if(debuglevel & (512 | 1024)){
1076 if ( !tracen ) traceflag = ((ply >traceply)?false:true);
1078 if(ply <= tracen && (ply ==1 || traceflag))
1080 if(trace[ply] == (Tree[pnt].t |(Tree[pnt].f<<8))) traceflag = true; else traceflag = false; }
1081 tracelog[ply] = (Tree[pnt].t | (Tree[pnt].f<<8));
1082 tracelog[ply+1] = 0;
1085 nxtline[ply + 1] = 0;
1087 /* if at top level */
1090 { /* at the top update search status */
1092 #ifdef QUIETBACKGROUND
1094 #endif /* QUIETBACKGROUND */
1095 ShowCurrentMove (pnt, node->f, node->t);
1098 if ( !(node->flags & exact) )
1100 /* make the move and go deeper */
1104 algbr(node->f, node->t, 0);
1105 fprintf(debug_eval_file,"%s (ply %d depth %d)\n",
1106 mvstr[0], ply, depth);
1109 MakeMove (side, node, &tempb, &tempc, &tempsf, &tempst, &INCscore);
1110 CptrFlag[ply] = (node->flags & capture);
1111 TesujiFlag[ply] = (node->flags & tesuji) && (node->flags & dropmask);
1112 Tscore[ply] = node->score;
1115 xxxtmp = node->score;
1116 tracetmp = traceflag;
1118 node->score = -search (xside, ply + 1,
1119 (depth > 0)?depth-1:0,
1123 if(!flag.timeout)node->score = score;
1125 node->width = (ply % 2 == 1) ? (TrPnt[ply + 2] - TrPnt[ply + 1]) : 0;
1126 if (node->score > SCORE_LIMIT || node->score < -SCORE_LIMIT)
1127 node->flags |= exact;
1131 traceflag = tracetmp;
1132 if (debuglevel & 256 || ((debuglevel & 1024) && traceflag &&
1133 (!traceply || ply<= traceply))) {
1135 algbr(node->f, node->t, node->flags);
1136 for (i = 1; i < ply; i++)
1138 printf("%s S%d d%d p%d n%d s%d a%d b%d best%d x%d\n",
1139 mvstr[0], Sdepth, depth, ply, node->score, score, alpha, beta, best,xxxtmp);
1142 if ((rcnt >= 3 || (node->score == (SCORE_LIMIT+999) - ply && !ChkFlag[ply])))
1144 node->flags |= (draw | exact);
1145 DRAW = CP[58]; /* Draw */
1146 node->score = ((side == computer) ? contempt : -contempt);
1148 node->reply = nxtline[ply + 1];
1149 /* reset to try next move */
1150 UnmakeMove (side, node, &tempb, &tempc, &tempsf, &tempst);
1152 /* if best move so far */
1153 if (!flag.timeout && ((node->score > best) || ((node->score == best) && (node->width > bestwidth))))
1156 * all things being equal pick the denser part of the
1159 bestwidth = node->width;
1162 * if not at goal depth and better than alpha and not
1163 * an exact score increment by depth
1165 if (depth > 0 && node->score > alpha && !(node->flags & exact))
1167 node->score += depth;
1171 if (best > alpha) { alpha = best; }
1172 /* update best line */
1173 for (j = ply + 1; nxtline[j] > 0; j++) bstline[j] = nxtline[j];
1175 bstline[ply] = (node->f << 8) | node->t;
1180 * if its better than the root score make it
1183 if ((best > root->score) || ((best == root->score) && (bestwidth > root->width)))
1186 for (j = pnt - 1; j >= 0; j--) Tree[j + 1] = Tree[j];
1191 #ifdef QUIETBACKGROUND
1193 #endif /* QUIETBACKGROUND */
1197 ShowResults (best, bstline, '+');
1199 debug41 (best, bstline, '+');
1202 else if (best < alpha)
1204 ShowResults (best, bstline, '-');
1206 debug41 (best, bstline, '-');
1210 ShowResults (best, bstline, '&');
1212 debug41 (best, bstline, '&');
1214 #else /* !BAREBONES */
1215 if ( !background && Sdepth > 2) {
1216 if ( best < alpha) {
1217 TCcount = 0; ExtraTime += 9*TCleft;
1225 return (Tscore[ply - 1]);
1229 /******************************************************************************************/
1231 mv = (node->f << 8) | node->t;
1236 if (debuglevel & 2560)
1240 if (debuglevel & 512 && (tracen > 0 && traceflag))
1243 for (j=1;tracelog[j];j++){
1244 algbr(tracelog[j]>>8,tracelog[j]&0xff,0);
1245 strcat(traceline," ");
1246 strcat(traceline,mvstr[0]);
1249 printf("Ply %d alpha %d beta %d score %d %s\n", ply, alpha, beta, score,traceline);
1250 if(debuglevel & 2048){
1251 for (j = ply; j < ply + 1; j++)
1255 for (idb = TrPnt[j]; idb < TrPnt[j + 1]; idb++)
1257 algbr(Tree[idb].f, Tree[idb].t, Tree[idb].flags);
1258 printf("level 512 %d-->%d %s %d %d %x\n", ply, idb, mvstr[0], Tree[idb].score, Tree[idb].width, Tree[idb].flags);
1268 * we have a move so put it in local table - if it's already there
1269 * done else if not there or needs to be updated also put it in
1273 if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
1276 algbr(node->f,node->t,0);
1277 printf("IN-> %lx %lx %d %d %s\n",hashkey,hashbd,depth,side,mvstr[0]);
1279 if (use_ttable && PutInTTable (side, best, depth, ply, alpha, beta, mv)
1281 && hashfile && (depth > HashDepth) && (GameCnt < HashMoveLimit))
1284 printf("FT %d %d %d %x\n",side,best,depth,mv);
1286 PutInFTable (side, best, depth, ply, alpha, beta, node->f, node->t);
1290 #endif /* HASHFILE */
1298 if (history[x=hindex(side,h)] < HISTORYLIM)
1299 history[x] += (unsigned short) 1<<depth;
1301 if (node->t != (short)(GameList[GameCnt].gmove & 0xFF))
1304 else if (mv != killr1[ply])
1306 killr2[ply] = killr1[ply];
1309 killr0[ply] = ((best > SCORE_LIMIT) ? mv : 0);
1316 UpdatePieceList (short int side, short int sq, UpdatePieceList_mode iop)
1319 * Update the PieceList and Pindex arrays when a piece is captured or when a
1320 * capture is unmade.
1326 if (iop == REMOVE_PIECE)
1329 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1331 PieceList[side][i] = PieceList[side][i + 1];
1332 Pindex[PieceList[side][i]] = i;
1336 if ( board[sq] == king )
1337 { /* king must have index 0 */
1338 for (i = PieceCnt[side]; i >= 0; i--)
1340 PieceList[side][i + 1] = PieceList[side][i];
1341 Pindex[PieceList[side][i + 1]] = i + 1;
1344 PieceList[side][0] = sq;
1350 PieceList[side][PieceCnt[side]] = sq;
1351 Pindex[sq] = PieceCnt[side];
1357 drop (short int side, short int piece, short int f, short int t, short int iop)
1359 /* Make or Unmake drop move. */
1366 #if !defined SAVE_SVALUE
1369 n = Captured[side][piece]--;
1373 UpdateDropHashbd (side, piece, n);
1374 UpdateHashbd (side, piece, -1, t);
1375 UpdatePieceList (side, t, ADD_PIECE);
1376 if ( piece == pawn )
1378 ++PawnCnt[side][column(t)];
1381 HasPiece[side][piece]++;
1385 board[t] = no_piece;
1387 n = ++Captured[side][piece];
1391 UpdateDropHashbd (side, piece, n);
1392 UpdateHashbd (side, piece, -1, t);
1393 UpdatePieceList (side, t, REMOVE_PIECE);
1394 if ( piece == pawn )
1396 --PawnCnt[side][column(t)];
1399 HasPiece[side][piece]--;
1408 { unsigned long chashkey, chashbd;
1410 chashbd = chashkey = 0;
1411 for (sq = 0; sq < NO_SQUARES; sq++)
1413 if (color[sq] != neutral)
1415 chashbd ^= (*hashcode)[color[sq]][board[sq]][sq].bd;
1416 chashkey ^= (*hashcode)[color[sq]][board[sq]][sq].key;
1418 /* hashcodes for initial board are 0 ! */
1419 if ( Stcolor[sq] != neutral )
1421 chashbd ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].bd;
1422 chashkey ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].key;
1425 for ( side = 0; side <= 1; side++ ) {
1427 for ( piece = 0; piece < NO_PIECES; piece++ ) {
1428 short n = Captured[side][piece];
1430 assert(n==0 || piece>0);
1434 for ( i = 1; i <= n; i++ )
1436 chashbd ^= (*drop_hashcode)[side][piece][i].bd;
1437 chashkey ^= (*drop_hashcode)[side][piece][i].key;
1442 if ( chashbd != hashbd )
1443 printf("chashbd %lu != hashbd %lu\n",chashbd,hashbd);
1444 if ( chashkey != hashkey )
1445 printf("chashkey %lu != hashkey %lu\n",chashkey,hashkey);
1446 if ( chashbd != hashbd || chashkey != hashkey ) {
1454 MakeMove (short int side,
1455 struct leaf far *node,
1456 short int *tempb, /* piece at to square */
1457 short int *tempc, /* color of to square */
1458 short int *tempsf, /* static value of piece on from */
1459 short int *tempst, /* static value of piece on to */
1460 short int *INCscore) /* score increment */
1463 * Update Arrays board[], color[], and Pindex[] to reflect the new board
1464 * position obtained after making the move pointed to by node. Also update
1465 * miscellaneous stuff that changes when a move is made.
1469 register short f, t, xside, ct, cf;
1470 register struct GameRec far *g;
1471 register short int fromb,fromc;
1474 g = &GameList[++GameCnt];
1475 g->hashkey = hashkey;
1477 FROMsquare = f = node->f;
1478 TOsquare = t = (node->t & 0x7f);
1479 *INCscore = (short int)node->INCscore;
1481 g->gmove = (f << 8) | node->t;
1482 g->flags = node->flags;
1485 if ( CheckHashKey () ) {
1487 algbr(f,t,node->flags);
1488 printf("error before MakeMove: %s\n", mvstr[0]);
1489 UpdateDisplay (0, 0, 1, 0);
1490 for ( i=1; i<=GameCnt; i++ ) {
1491 movealgbr(GameList[i].gmove,mvstr[0]);
1492 printf("%d: %s\n", i, mvstr[0]);
1498 rpthash[side][hashkey & 0xFF]++, ISZERO++;
1501 assert(f != NO_SQUARES);
1504 if (f > NO_SQUARES )
1508 piece = f - NO_SQUARES;
1509 if ( side == white ) piece -= NO_PIECES;
1510 assert(node->flags & dropmask);
1511 assert((node->flags & pmask) == piece);
1513 g->fpiece = (node->flags & pmask);
1514 g->piece = *tempb = no_piece;
1515 g->color = *tempc = neutral;
1516 #if !defined SAVE_SVALUE
1518 *tempst = svalue[t];
1520 (void) drop (side, g->fpiece, f, t, 1);
1525 #if !defined SAVE_SVALUE
1526 *tempsf = svalue[f];
1527 *tempst = svalue[t];
1529 g->fpiece = board[f];
1530 g->piece = *tempb = board[t];
1531 g->color = *tempc = color[t];
1534 if (*tempc != neutral)
1535 { /* Capture a piece */
1536 UpdatePieceList (*tempc, t, REMOVE_PIECE);
1537 /* if capture decrement pawn count */
1540 --PawnCnt[*tempc][column (t)];
1542 mtl[xside] -= (*value)[stage][*tempb];
1543 HasPiece[xside][*tempb]--;
1544 { short n, upiece = unpromoted[*tempb];
1545 /* add "upiece" captured by "side" */
1546 n = ++Captured[side][upiece];
1550 UpdateDropHashbd (side, upiece, n);
1551 mtl[side] += (*value)[stage][upiece];
1553 /* remove "*tempb" of "xside" from board[t] */
1554 UpdateHashbd (xside, *tempb, -1, t);
1555 #if !defined SAVE_SVALUE
1556 *INCscore += *tempst; /* add value of catched piece to own score */
1561 #if !defined SAVE_SVALUE
1562 svalue[t] = svalue[f];
1565 Pindex[t] = Pindex[f];
1566 PieceList[side][Pindex[t]] = t;
1568 board[f] = no_piece;
1569 if (node->flags & promote)
1571 board[t] = tob = promoted[fromb];
1572 /* remove unpromoted piece from board[f] */
1573 UpdateHashbd (side, fromb, f, -1);
1574 /* add promoted piece to board[t] */
1575 UpdateHashbd (side, tob, -1, t);
1576 mtl[side] += value[stage][tob] - value[stage][fromb];
1577 if ( fromb == pawn )
1578 { --PawnCnt[side][column(f)];
1580 HasPiece[side][fromb]--;
1581 HasPiece[side][tob]++;
1582 #if !defined SAVE_SVALUE
1583 *INCscore -= *tempsf;
1589 /* remove piece from board[f] and add it to board[t] */
1590 UpdateHashbd (side, fromb, f, t);
1595 algbr(f,t,node->flags);
1596 if ( CheckHashKey () ) {
1597 printf("error in MakeMove: %s\n", mvstr[0]);
1602 assert(Captured[black][0]==0 && Captured[white][0]==0);
1607 UnmakeMove (short int side,
1608 struct leaf far *node,
1619 register short f, t, xside;
1624 Game50 = GameList[GameCnt].Game50;
1627 assert(f != NO_SQUARES);
1629 if (f > NO_SQUARES )
1631 piece = f - NO_SQUARES;
1632 if ( piece >= NO_PIECES ) piece -= NO_PIECES;
1633 assert(node->flags & dropmask);
1634 assert((node->flags & pmask) == piece);
1638 if (node->flags & dropmask)
1640 (void) drop (side, (node->flags & pmask), f, t, 2);
1641 #if !defined SAVE_SVALUE
1642 svalue[t] = *tempst;
1647 color[f] = color[t];
1648 board[f] = tob = fromb = board[t];
1649 #if !defined SAVE_SVALUE
1650 svalue[f] = *tempsf;
1652 Pindex[f] = Pindex[t];
1653 PieceList[side][Pindex[f]] = f;
1656 #if !defined SAVE_SVALUE
1657 svalue[t] = *tempst;
1660 if (node->flags & promote)
1662 board[f] = fromb = unpromoted[tob];
1663 mtl[side] += value[stage][fromb] - value[stage][tob];
1664 if ( fromb == pawn )
1666 ++PawnCnt[side][column (f)];
1668 HasPiece[side][fromb]++;
1669 HasPiece[side][tob]--;
1670 /* add unpromoted piece to board[f] */
1671 UpdateHashbd (side, fromb, f, -1);
1672 /* remove promoted piece from board[t] */
1673 UpdateHashbd (side, tob, -1, t);
1677 if ( fromb == pawn )
1679 --PawnCnt[side][column (t)];
1680 ++PawnCnt[side][column (f)];
1682 /* remove piece from board[t] and add it to board[f] */
1683 UpdateHashbd (side, fromb, f, t);
1686 if (*tempc != neutral)
1687 { short n, upiece = unpromoted[*tempb];
1688 UpdatePieceList (*tempc, t, ADD_PIECE);
1691 ++PawnCnt[*tempc][column (t)];
1693 mtl[xside] += (*value)[stage][*tempb];
1694 HasPiece[xside][*tempb]++;
1695 mtl[side] -= (*value)[stage][upiece];
1696 /* remove "upiece" captured by "side" */
1697 n = Captured[side][upiece]--;
1701 UpdateDropHashbd (side, upiece, n);
1702 /* replace captured piece on board[t] */
1703 UpdateHashbd (xside, *tempb, -1, t);
1709 rpthash[side][hashkey & 0xFF]--, ISZERO--;
1711 algbr(f,t,node->flags);
1712 if ( CheckHashKey () ) {
1713 printf("error in UnmakeMove: %s\n", mvstr[0]);
1718 assert(Captured[black][0]==0 && Captured[white][0]==0);
1724 InitializeStats (void)
1727 * Scan thru the board seeing what's on each square. If a piece is found,
1728 * update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1729 * determine the material for each side and set the hashkey and hashbd
1730 * variables to represent the current board position. Array
1731 * PieceList[side][indx] contains the location of all the pieces of either
1732 * side. Array Pindex[sq] contains the indx into PieceList for a given
1737 register short i, sq;
1739 for (i = 0; i < NO_COLS; i++)
1741 PawnCnt[black][i] = PawnCnt[white][i] = 0;
1743 mtl[black] = mtl[white] = 0;
1744 PieceCnt[black] = PieceCnt[white] = 0;
1745 hashbd = hashkey = 0;
1746 for (sq = 0; sq < NO_SQUARES; sq++)
1748 if (color[sq] != neutral)
1750 mtl[color[sq]] += (*value)[stage][board[sq]];
1751 if (board[sq] == pawn)
1753 ++PawnCnt[color[sq]][column(sq)];
1755 Pindex[sq] = ((board[sq] == king) ? 0 : ++PieceCnt[color[sq]]);
1757 PieceList[color[sq]][Pindex[sq]] = sq;
1758 UpdateHashbd(color[sq],board[sq],sq,-1);
1760 /* hashcodes for initial board are 0 ! */
1761 if ( Stcolor[sq] != neutral )
1762 UpdateHashbd(Stcolor[sq],Stboard[sq],sq,-1);
1765 for ( side = 0; side <= 1; side++ ) {
1767 for ( piece = 0; piece < NO_PIECES; piece++ ) {
1768 short n = Captured[side][piece];
1770 Captured[side][piece] = 0;
1771 for ( i = 1; i <= n; i++ ) {
1772 ++Captured[side][piece];
1773 UpdateDropHashbd(side,piece,i);
1774 mtl[side] += (*value)[stage][piece];
1781 if ( CheckHashKey () ) {
1782 printf("error in InitializeStats\n");