4 * ----------------------------------------------------------------------
5 * Copyright (c) 1993, 1994, 1995 Matthias Mutz
6 * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
7 * Copyright (c) 2008, 2013, 2014 Yann Dirson and the Free Software Foundation
9 * GNU SHOGI is based on GNU CHESS
11 * Copyright (c) 1988, 1989, 1990 John Stanback
12 * Copyright (c) 1992 Free Software Foundation
14 * This file is part of GNU SHOGI.
16 * GNU Shogi is free software; you can redistribute it and/or modify it
17 * under the terms of the GNU General Public License as published by the
18 * Free Software Foundation; either version 3 of the License,
19 * or (at your option) any later version.
21 * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
22 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with GNU Shogi; see the file COPYING. If not, see
28 * <http://www.gnu.org/licenses/>.
29 * ----------------------------------------------------------------------
36 static short DepthBeyond;
37 unsigned short PrVar[MAXDEPTH];
38 extern short recycle, ISZERO;
39 extern void FlagString(unsigned short flags, char *s);
42 short null; /* Null-move already made or not */
43 short PVari; /* Is this the PV */
47 short movesLeft, currentMove;
51 /* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
56 * Check for draw by fourfold repetition
57 * (same side, same captures, same board).
58 * WARNING: this is not save (sp? safe?) yet due to possible hash collisions.
69 if (GameCnt > Game50 + 6)
71 for (i = GameCnt - 1; i >= Game50; i -= 2)
75 if (g->hashkey == hashkey && g->hashbd == hashbd)
86 int plyscore, globalscore;
90 * Find the best move in the tree between indexes p1 and p2. Swap the best
91 * move into the p1 element.
95 pick(short p1, short p2)
97 struct leaf *p, *q, *r, *k;
105 for (r = p + 1; r <= q; r++)
125 int bookflag = false;
135 * Select a move by calling function search() at progressively deeper ply
136 * until time is up or a mate or draw is reached. An alpha-beta window of
137 * -Awindow to +Bwindow points is set around the score returned from the
138 * previous iteration. If Sdepth != 0 then the program has correctly
139 * predicted the opponents move and the search will start at a depth of
140 * Sdepth + 1 rather than a depth of 1.
144 SelectMove(short side, SelectMove_mode iop)
146 static short i, tempb, tempc, tempsf, tempst, xside, rpt;
147 static short alpha, beta, score;
148 static struct GameRec *g;
149 short sqking, in_check, blockable;
152 printf("hashbd = %ld (hashkey >> 16)|side = %d\n",
153 hashbd, (hashkey >> 16)|side);
156 flag.timeout = false;
158 flag.musttimeout = false;
163 recycle = (GameCnt % rehash) - rehash;
166 ExaminePosition(side);
168 /* if background mode set to infinite */
169 if (iop == BACKGROUND_MODE)
172 /* if background mode set response time to infinite */
173 ResponseTime = 9999999;
177 background = false; /* [HGM] with ponder on we did not switch back to foreground mode??? */
179 SetResponseTime(side);
182 #ifdef QUIETBACKGROUND
184 #endif /* QUIETBACKGROUND */
185 dsp->ShowResponseTime();
189 score = ScorePosition(side);
191 #ifdef QUIETBACKGROUND
193 #endif /* QUIETBACKGROUND */
194 dsp->ShowSidetoMove();
196 #ifdef QUIETBACKGROUND
198 #endif /* QUIETBACKGROUND */
199 dsp->SearchStartStuff(side);
202 array_zero(history, sizeof_history);
205 FROMsquare = TOsquare = -1;
208 if (iop == FOREGROUND_MODE)
212 * If the last move was the hint, select the computed answer to the
213 * hint as first move to examine.
219 SwagHt = (GameList[GameCnt].gmove == PrVar[2]) ? PrVar[3] : 0;
226 for (i = 0; i < MAXDEPTH; i++)
227 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
229 /* set initial window for search */
233 alpha = -(SCORE_LIMIT + 999);
234 beta = SCORE_LIMIT + 999;
238 alpha = score - ((computer == white) ? BAwindow : WAwindow);
239 beta = score + ((computer == white) ? BBwindow : WBwindow);
246 sqking = PieceList[side][0];
247 in_check = (board[sqking] == king)
248 ? SqAttacked(sqking, side^1, &blockable)
251 MoveList(side, 1, in_check, blockable);
253 for (i = TrPnt[1]; i < TrPnt[2]; i++)
255 if (!pick(i, TrPnt[2] - 1))
259 /* Can I get a book move? */
261 if (flag.regularstart && Book)
263 flag.timeout = bookflag = OpeningBook(&hint);
266 ResponseTime += ResponseTime;
269 /* Zero stats for hash table. */
271 reminus = replus = 0;
272 GenCnt = NodeCnt = ETnodes = EvalNodes = HashCnt
273 = FHashAdd = HashAdd = FHashCnt = THashCol = HashCol = 0;
275 globalscore = plyscore = score;
280 /********************* main loop ********************************/
282 Sdepth = (MaxSearchDepth < (MINDEPTH - 1))
286 while (!flag.timeout)
288 /* go down a level at a time */
296 /* terminate search at DepthBeyond ply past goal depth */
298 DepthBeyond = Sdepth;
301 DepthBeyond = Sdepth + ((Sdepth == 1) ? 3 : 5);
303 DepthBeyond = Sdepth + ((Sdepth == 1) ? 7 : 11);
306 # ifdef QUIETBACKGROUND
308 #endif /* QUIETBACKGROUND */
311 /* search at this level returns score of PV */
312 score = search(side, 1, Sdepth, alpha, beta, PrVar, &rpt);
314 /* save PV as killer */
315 for (i = 1; i <= Sdepth; i++)
316 killr0[i] = PrVar[i];
318 /* low search failure re-search with (-inf, score) limits */
322 #ifdef QUIETBACKGROUND
324 #endif /* QUIETBACKGROUND */
327 if (TCflag && TCcount < MAXTCCOUNTR)
330 ExtraTime += (MAXTCCOUNTR - TCcount) * TCleft;
332 ExtraTime += (8 * TCleft);
334 TCcount = MAXTCCOUNTR - 1;
337 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
338 (SCORE_LIMIT + 999), PrVar, &rpt);
340 /* high search failure re-search with (score, +inf) limits */
341 else if (score > beta && !(root->flags & exact))
344 #ifdef QUIETBACKGROUND
346 #endif /* QUIETBACKGROUND */
349 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
350 (SCORE_LIMIT + 999), PrVar, &rpt);
353 /**************** out of search ***********************************/
354 CheckForTimeout(score, globalscore, Jscore, zwndw);
356 /************************ time control ****************************/
358 /* save PV as killer */
359 for (i = 1; i <= Sdepth + 1; i++)
360 killr0[i] = PrVar[i];
365 /* if (!flag.timeout) */
367 for (i = TrPnt[1] + 1; i < TrPnt[2]; i++)
368 if (!pick (i, TrPnt[2] - 1))
372 /* if done or nothing good to look at quit */
373 if ((root->flags & exact) || (score < -SCORE_LIMIT))
376 /* find the next best move put below root */
380 #if !defined NODYNALPHA
381 Jscore = (plyscore + score) >> 1;
383 zwndw = 20 + abs(Jscore / 12);
386 /* recompute search window */
387 beta = score + ((computer == white) ? BBwindow : WBwindow);
388 #if !defined NODYNALPHA
389 alpha = ((Jscore < score) ? Jscore : score)
390 - ((computer == white) ? BAwindow : WAwindow)
393 alpha = score - ((computer == white) ? BAwindow : WAwindow);
397 #ifdef QUIETBACKGROUND
399 #endif /* QUIETBACKGROUND */
400 dsp->ShowResults(score, PrVar, '.');
403 /********************** end of main loop ***************************/
405 /* background mode */
406 if (iop == BACKGROUND_MODE)
412 DRAW = DRAW_REPETITION;
417 * If there are no moves and we're not in check (stalemate) then
418 * it's mate in shogi (whereas it's a draw in chess).
421 if (GameCnt == MAXMOVES)
424 DRAW = DRAW_MAXMOVES;
428 /* not in book so set hint to guessed move for other side */
430 hint = ((PrVar[1]) ? PrVar[2] : 0);
432 /* if not mate or draw make move and output it */
433 if (((score > -(SCORE_LIMIT + 999))
434 && (rpt <= 3)) || (root->flags & draw))
436 MakeMove(side, &Tree[0], &tempb, &tempc,
437 &tempsf, &tempst, &INCscore);
438 algbr(root->f, root->t, (short) root->flags);
442 algbr(0, 0, 0); /* Zero move string when mate. */
443 root->score = score; /* When mate, ignore distinctions!
447 g = &GameList[GameCnt];
449 if ((g->flags & capture) && (g->piece == king))
450 flag.mate = flag.illegal = true;
452 /* If Time Control get the elapsed time */
454 ElapsedTime(COMPUTE_AND_INIT_MODE);
456 /* update time control info */
459 /* if mate set flag */
460 if ((score == -(SCORE_LIMIT + 999) || score == (SCORE_LIMIT + 998)))
463 /* add move to game list */
466 g->time = (et +50)/100;
467 /* g->time = TCcount; */
470 /* update time control info */
473 TimeControl.clock[side] -= (et + OperatorTime);
474 timecomp[compptr] = (et + OperatorTime);
476 /* finished our required moves - setup the next set */
477 --TimeControl.moves[side];
480 /* check for end conditions */
481 if ((root->flags & draw) /* && flag.bothsides */)
485 else if (GameCnt == MAXMOVES)
489 /* out of move store, you lose */
492 /* switch to other side */
496 /* if mate clear hint */
506 * Perform an alpha-beta search to determine the score for the current
507 * board position. If depth <= 0 only capturing moves and responses to
508 * check are generated and searched, otherwise all moves are processed. The
509 * search depth is modified for check evasions, certain re-captures and
510 * threats. Extensions may continue for up to 11 ply beyond the nominal
520 unsigned short *bstline,
524 short tempb, tempc, tempsf, tempst;
525 short xside, pbst, score, rcnt, in_check, blockable;
526 unsigned short mv, nxtline[MAXDEPTH];
527 struct leaf *node, tmp;
528 short best = -(SCORE_LIMIT + 3000);
539 /* look every ZNODE nodes for a timeout */
544 if (NodeCnt > ETnodes)
546 ElapsedTime(COMPUTE_MODE);
552 flag.musttimeout = false;
554 else if (TCflag || MaxResponseTime)
556 if ((et >= (ResponseTime + ExtraTime))
557 && (Sdepth > MINDEPTH))
559 /* try to extend to finish ply */
560 if (flag.back || (TCflag && TCcount < MAXTCCOUNTX))
563 flag.musttimeout = true;
571 flag.musttimeout = false;
579 flag.musttimeout = false;
582 #ifdef QUIETBACKGROUND
585 dsp->ShowResponseTime();
587 else if (!TCflag && flag.musttimeout && Sdepth > MINDEPTH)
590 flag.musttimeout = false;
597 score = evaluate(side, ply, alpha, beta,
598 INCscore, &in_check, &blockable);
601 * check for possible repitition if so call repitition - rpt is
605 if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
610 * repeat position >3 don't need to return score it's taken
627 /* score > SCORE_LIMIT its a draw or mate */
628 if (score > SCORE_LIMIT)
634 /* Do we need to add depth because of special conditions */
635 /* if in check or in capture sequence search deeper */
637 /***************** depth extensions *****************/
641 /* Allow opponent a chance to check again */
648 && (score > alpha) && (score < beta)
650 && CptrFlag[ply - 1] && CptrFlag[ply - 2])
669 timeout = flag.timeout;
673 || ((!timeout && (hung[side] > 1))
674 && (ply == Sdepth + 1))))
678 else if ((score <= beta)
679 && (((ply < Sdepth + 4) && (ply > 4))
682 && (ChkFlag[ply - 2] != ChkFlag[ply - 4])))
688 /***************************************************/
689 /* try the local transition table if it's there */
692 if (/* depth > 0 && */ flag.hash && ply > 1)
695 && ProbeTTable(side, depth, ply, &alpha, &beta, &score) == true)
698 bstline[ply + 1] = 0;
700 if (beta == -((SCORE_LIMIT + 1000) * 2))
708 /* ok try the transition file if its there */
710 && (depth > HashDepth)
711 && (GameCnt < HashMoveLimit)
712 && (ProbeFTable(side, depth, ply, &alpha, &beta, &score)
715 PutInTTable(side, score, depth, ply, beta, PV);
717 bstline[ply + 1] = 0;
719 if (beta == -((SCORE_LIMIT + 1000) * 2))
727 #endif /* HASHFILE */
731 if (TrPnt[ply] > (TREE - 300))
737 * If more then DepthBeyond ply past goal depth or at goal depth and
738 * score > beta quit - means we are out of the window.
741 if (mustcut || (ply > DepthBeyond) || ((depth < 1) && (score > beta)))
745 * If below first ply and not at goal depth generate all moves else
746 * only capture moves.
751 if ((depth > 0) || (ply < (SDEPTHLIM))
752 || (background && (ply < Sdepth + 2)))
753 MoveList(side, ply, in_check, blockable);
755 CaptureList(side, ply, in_check, blockable);
758 /* no moves return what we have */
761 * normally a search will continue til past goal and no more capture
765 /* unless it hits DepthBeyond */
766 if (TrPnt[ply] == TrPnt[ply + 1])
769 /* if not at goal set best = -inf else current score */
770 best = (depth > 0) ? -(SCORE_LIMIT + 3000) : score;
776 /* CHECKME: is the & really an && here? */
777 if (!null && /* no previous null-move */
778 !PVari && /* no null-move during the PV */
779 (ply > 2) & /* not at ply 1 */
782 !in_check) /* no check */
783 /* enough material such that zugzwang is unlikely
784 * but who knows which value is suitable? */
787 OK, we make a null move, i.e. this means we have nothing to do
788 but we have to keep the some arrays up to date otherwise gnushogi
789 gets confused. Maybe somebody knows exactly which information is
790 important and which isn't.
792 Another idea is that we try the null-move first and generate the
793 moves later. This may save time but we have to take care that
794 PV and other variables contain the right value so that the move
795 ordering works right.
800 nxtline[ply + 1] = 0;
807 g = &GameList[++GameCnt];
808 g->hashkey = hashkey;
810 FROMsquare = TOsquare = -1;
817 best = -search(xside, ply + 1, depth - 2,
818 -beta - 1, -beta, nxtline, &rcnt);
825 best = -(SCORE_LIMIT + 3000);
827 else if (best > beta)
833 best = -(SCORE_LIMIT + 3000);
838 /* if best so far is better than alpha set alpha to best */
842 /********************** main loop ****************************/
844 /* look at each move until no more or beta cutoff */
845 for (pnt = pbst = TrPnt[ply];
846 (pnt < TrPnt[ply + 1]) && (best <= beta);
849 /* find the most interesting looking of the remaining moves */
851 pick(pnt, TrPnt[ply + 1] - 1);
854 PVari = PVarisave && (pnt == TrPnt[ply]); /* Is this the PV? */
859 /* is this a forbidden move */
860 if (/* ply == 1 && */ node->score <= DONTUSE)
863 nxtline[ply + 1] = 0;
865 /* if at top level */
868 /* at the top update search status */
871 #ifdef QUIETBACKGROUND
873 #endif /* QUIETBACKGROUND */
874 dsp->ShowCurrentMove(pnt, node->f, node->t);
876 movesLeft = TrPnt[2] - pnt; /* to report with XBoard periodic updates */
877 currentMove = node->f << 8 | node->t;
880 if (!(node->flags & exact))
882 /* make the move and go deeper */
884 MakeMove(side, node, &tempb, &tempc, &tempsf,
886 CptrFlag[ply] = ((node->flags & capture) != 0);
887 TesujiFlag[ply] = (node->flags & tesuji)
888 && (node->flags & dropmask);
889 Tscore[ply] = node->score;
892 node->score = -search(xside, ply + 1,
893 (depth > 0) ? (depth - 1) : 0,
899 * node->score = score;
902 node->width = ((ply % 2) == 1)
903 ? (TrPnt[ply + 2] - TrPnt[ply + 1])
906 if ((node->score > SCORE_LIMIT) || (node->score < -SCORE_LIMIT) )
907 node->flags |= exact;
912 || ((node->score == (SCORE_LIMIT + 999) - ply)
915 node->flags |= (draw | exact);
916 DRAW = DRAW_JUSTDRAW;
917 node->score = ((side == computer) ? contempt : -contempt);
920 node->reply = nxtline[ply + 1];
922 /* reset to try next move */
923 UnmakeMove(side, node, &tempb, &tempc, &tempsf, &tempst);
926 /* if best move so far */
927 /* CHECKME: flag.timeout isn't valid if no hard time limit */
929 && ((node->score > best)
930 || ((node->score == best) && (node->width > bestwidth))))
933 * All things being equal pick the denser part of the
936 bestwidth = node->width;
939 * If not at goal depth and better than alpha and not
940 * an exact score increment by depth.
943 if ((depth > 0) && (node->score > alpha)
944 && !(node->flags & exact))
946 node->score += depth;
955 /* update best line */
956 for (j = ply + 1; nxtline[j] > 0; j++)
957 bstline[j] = nxtline[j];
960 bstline[ply] = (node->f << 8) | node->t;
966 * If it's better than the root score make it the root.
968 if ((best > root->score)
969 || ((best == root->score)
970 && (bestwidth > root->width)))
974 for (j = pnt - 1; j >= 0; j--)
975 Tree[j + 1] = Tree[j];
981 #ifdef QUIETBACKGROUND
984 #endif /* QUIETBACKGROUND */
989 dsp->ShowResults(best, bstline, '+');
991 else if (best < alpha)
993 dsp->ShowResults(best, bstline, '-');
997 dsp->ShowResults(best, bstline, '&');
1000 #ifdef QUIETBACKGROUND
1007 return Tscore[ply - 1];
1010 /******************************************************/
1013 mv = (node->f << 8) | node->t;
1020 * We have a move so put it in local table - if it's already there
1021 * done else if not there or needs to be updated also put it in
1026 if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
1028 # ifdef HASHFILE /* MCV: warning: this confuses the formatter. */
1030 && PutInTTable(side, best, depth, ply, beta, mv)
1032 && (depth > HashDepth)
1033 && (GameCnt < HashMoveLimit))
1036 && PutInTTable(side, best, depth, ply, beta, mv))
1039 PutInFTable(side, best, depth, ply,
1040 alpha, beta, node->f, node->t);
1048 unsigned short h, x;
1051 if (history[x = hindex(side, h)] < HISTORYLIM)
1052 history[x] += (unsigned short) 1 << depth;
1055 if (node->t != (short)(GameList[GameCnt].gmove & 0xFF))
1061 else if (mv != killr1[ply])
1063 killr2[ply] = killr1[ply];
1068 killr0[ply] = ((best > SCORE_LIMIT) ? mv : 0);
1077 * Update the PieceList and Pindex arrays when a piece is captured or when a
1078 * capture is unmade.
1082 UpdatePieceList(short side, short sq, UpdatePieceList_mode iop)
1086 if (iop == REMOVE_PIECE)
1090 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1092 PieceList[side][i] = PieceList[side][i + 1];
1093 Pindex[PieceList[side][i]] = i;
1096 else if (board[sq] == king)
1098 /* king must have index 0 */
1099 for (i = PieceCnt[side]; i >= 0; i--)
1101 PieceList[side][i + 1] = PieceList[side][i];
1102 Pindex[PieceList[side][i + 1]] = i + 1;
1106 PieceList[side][0] = sq;
1112 PieceList[side][PieceCnt[side]] = sq;
1113 Pindex[sq] = PieceCnt[side];
1119 /* Make or Unmake drop move. */
1122 drop(short side, short piece, short t, short iop)
1130 #if !defined SAVE_SVALUE
1134 n = Captured[side][piece]--;
1136 UpdateDropHashbd(side, piece, n);
1137 UpdateHashbd(side, piece, -1, t);
1138 UpdatePieceList(side, t, ADD_PIECE);
1142 ++PawnCnt[side][column(t)];
1146 HasPiece[side][piece]++;
1151 board[t] = no_piece;
1153 n = ++Captured[side][piece];
1155 UpdateDropHashbd(side, piece, n);
1156 UpdateHashbd(side, piece, -1, t);
1157 UpdatePieceList(side, t, REMOVE_PIECE);
1160 --PawnCnt[side][column(t)];
1163 HasPiece[side][piece]--;
1172 unsigned long chashkey, chashbd;
1174 chashbd = chashkey = 0;
1176 for (sq = 0; sq < NO_SQUARES; sq++)
1178 if (color[sq] != neutral)
1180 chashbd ^= (*hashcode)[color[sq]][board[sq]][sq].bd;
1181 chashkey ^= (*hashcode)[color[sq]][board[sq]][sq].key;
1184 /* hashcodes for initial board are 0 ! */
1185 if (Stcolor[sq] != neutral)
1187 chashbd ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].bd;
1188 chashkey ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].key;
1192 for (side = 0; side <= 1; side++)
1196 for (piece = 0; piece < NO_PIECES; piece++)
1198 short n = Captured[side][piece];
1204 for (i = 1; i <= n; i++)
1206 chashbd ^= (*drop_hashcode)[side][piece][i].bd;
1207 chashkey ^= (*drop_hashcode)[side][piece][i].key;
1213 if (chashbd != hashbd)
1214 printf("chashbd %lu != hashbd %lu\n", chashbd, hashbd);
1216 if (chashkey != hashkey)
1217 printf("chashkey %lu != hashkey %lu\n", chashkey, hashkey);
1219 if (chashbd != hashbd || chashkey != hashkey)
1230 * Update Arrays board[], color[], and Pindex[] to reflect the new board
1231 * position obtained after making the move pointed to by node. Also update
1232 * miscellaneous stuff that changes when a move is made.
1236 MakeMove(short side,
1238 short *tempb, /* piece at to square */
1239 short *tempc, /* color of to square */
1240 short *tempsf, /* static value of piece on from */
1241 short *tempst, /* static value of piece on to */
1242 short *INCscore) /* score increment */
1249 g = &GameList[++GameCnt];
1250 g->hashkey = hashkey;
1252 FROMsquare = f = node->f;
1253 TOsquare = t = (node->t & 0x7f);
1254 *INCscore = (short)node->INCscore;
1256 g->gmove = (f << 8) | node->t;
1257 g->flags = node->flags;
1263 algbr(f, t, node->flags);
1264 printf("error before MakeMove: %s\n", mvstr[0]);
1265 UpdateDisplay(0, 0, 1, 0);
1267 for (i = 1; i <= GameCnt; i++)
1269 movealgbr(GameList[i].gmove, mvstr[0]);
1270 printf("%d: %s\n", i, mvstr[0]);
1277 rpthash[side][hashkey & 0xFF]++, ISZERO++;
1281 g->fpiece = (node->flags & pmask);
1282 g->piece = *tempb = no_piece;
1283 g->color = *tempc = neutral;
1285 #if !defined SAVE_SVALUE
1287 *tempst = svalue[t];
1290 (void)drop(side, g->fpiece, t, 1);
1294 #if !defined SAVE_SVALUE
1295 *tempsf = svalue[f];
1296 *tempst = svalue[t];
1299 g->fpiece = board[f];
1300 g->piece = *tempb = board[t];
1301 g->color = *tempc = color[t];
1305 if (*tempc != neutral)
1307 /* Capture a piece */
1308 UpdatePieceList(*tempc, t, REMOVE_PIECE);
1310 /* if capture decrement pawn count */
1312 --PawnCnt[*tempc][column(t)];
1314 mtl[xside] -= (*value)[stage][*tempb];
1315 HasPiece[xside][*tempb]--;
1318 short n, upiece = unpromoted[*tempb];
1320 /* add "upiece" captured by "side" */
1321 n = ++Captured[side][upiece];
1323 UpdateDropHashbd(side, upiece, n);
1324 mtl[side] += (*value)[stage][upiece];
1327 /* remove "*tempb" of "xside" from board[t] */
1328 UpdateHashbd(xside, *tempb, -1, t);
1330 #if !defined SAVE_SVALUE
1331 *INCscore += *tempst; /* add value of catched piece
1340 #if !defined SAVE_SVALUE
1341 svalue[t] = svalue[f];
1345 Pindex[t] = Pindex[f];
1346 PieceList[side][Pindex[t]] = t;
1348 board[f] = no_piece;
1350 if (node->flags & promote)
1354 board[t] = tob = promoted[fromb];
1356 /* remove unpromoted piece from board[f] */
1357 UpdateHashbd(side, fromb, f, -1);
1359 /* add promoted piece to board[t] */
1360 UpdateHashbd(side, tob, -1, t);
1361 mtl[side] += value[stage][tob] - value[stage][fromb];
1364 --PawnCnt[side][column(f)];
1366 HasPiece[side][fromb]--;
1367 HasPiece[side][tob]++;
1369 #if !defined SAVE_SVALUE
1370 *INCscore -= *tempsf;
1376 /* remove piece from board[f] and add it to board[t] */
1377 UpdateHashbd(side, fromb, f, t);
1384 algbr(f, t, node->flags);
1388 printf("error in MakeMove: %s\n", mvstr[0]);
1402 UnmakeMove(short side,
1414 Game50 = GameList[GameCnt].Game50;
1416 if (node->flags & dropmask)
1418 (void)drop(side, (node->flags & pmask), t, 2);
1420 #if !defined SAVE_SVALUE
1421 svalue[t] = *tempst;
1428 color[f] = color[t];
1429 board[f] = tob = fromb = board[t];
1431 #if !defined SAVE_SVALUE
1432 svalue[f] = *tempsf;
1435 Pindex[f] = Pindex[t];
1436 PieceList[side][Pindex[f]] = f;
1440 #if !defined SAVE_SVALUE
1441 svalue[t] = *tempst;
1445 if (node->flags & promote)
1447 board[f] = fromb = unpromoted[tob];
1448 mtl[side] += value[stage][fromb] - value[stage][tob];
1451 ++PawnCnt[side][column(f)];
1453 HasPiece[side][fromb]++;
1454 HasPiece[side][tob]--;
1456 /* add unpromoted piece to board[f] */
1457 UpdateHashbd(side, fromb, f, -1);
1459 /* remove promoted piece from board[t] */
1460 UpdateHashbd(side, tob, -1, t);
1466 --PawnCnt[side][column(t)];
1467 ++PawnCnt[side][column(f)];
1470 /* remove piece from board[t] and add it to board[f] */
1471 UpdateHashbd(side, fromb, f, t);
1475 if (*tempc != neutral)
1477 short n, upiece = unpromoted[*tempb];
1479 UpdatePieceList(*tempc, t, ADD_PIECE);
1482 ++PawnCnt[*tempc][column(t)];
1484 mtl[xside] += (*value)[stage][*tempb];
1485 HasPiece[xside][*tempb]++;
1486 mtl[side] -= (*value)[stage][upiece];
1488 /* remove "upiece" captured by "side" */
1489 n = Captured[side][upiece]--;
1491 UpdateDropHashbd(side, upiece, n);
1493 /* replace captured piece on board[t] */
1494 UpdateHashbd(xside, *tempb, -1, t);
1502 rpthash[side][hashkey & 0xFF]--, ISZERO--;
1505 algbr(f, t, node->flags);
1509 printf("error in UnmakeMove: %s\n", mvstr[0]);
1518 * Scan thru the board seeing what's on each square. If a piece is found,
1519 * update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1520 * determine the material for each side and set the hashkey and hashbd
1521 * variables to represent the current board position. Array
1522 * PieceList[side][indx] contains the location of all the pieces of either
1523 * side. Array Pindex[sq] contains the indx into PieceList for a given
1528 InitializeStats(void)
1532 for (i = 0; i < NO_COLS; i++)
1533 PawnCnt[black][i] = PawnCnt[white][i] = 0;
1535 mtl[black] = mtl[white] = 0;
1536 PieceCnt[black] = PieceCnt[white] = 0;
1537 hashbd = hashkey = 0;
1539 for (sq = 0; sq < NO_SQUARES; sq++)
1541 if (color[sq] != neutral)
1543 mtl[color[sq]] += (*value)[stage][board[sq]];
1545 if (board[sq] == pawn)
1546 ++PawnCnt[color[sq]][column(sq)];
1548 Pindex[sq] = ((board[sq] == king) ? 0 : ++PieceCnt[color[sq]]);
1549 PieceList[color[sq]][Pindex[sq]] = sq;
1550 UpdateHashbd(color[sq], board[sq], sq, -1);
1553 /* hashcodes for initial board are 0 ! */
1554 if (Stcolor[sq] != neutral)
1555 UpdateHashbd(Stcolor[sq], Stboard[sq], sq, -1);
1561 for (side = 0; side <= 1; side++)
1565 for (piece = 0; piece < NO_PIECES; piece++)
1567 short n = Captured[side][piece];
1571 Captured[side][piece] = 0;
1573 for (i = 1; i <= n; i++)
1575 ++Captured[side][piece];
1576 UpdateDropHashbd(side, piece, i);
1577 mtl[side] += (*value)[stage][piece];
1587 printf("error in InitializeStats\n");