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 (background) /* originally: 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 */
455 ElapsedTime(COMPUTE_AND_INIT_MODE);
456 if(xboard) /* In XBoard increment is added after move */
457 TimeControl.clock[side] += TCadd;
459 /* update time control info */
462 /* if mate set flag */
463 if ((score == -(SCORE_LIMIT + 999) || score == (SCORE_LIMIT + 998)))
466 /* add move to game list */
469 g->time = (et +50)/100;
470 /* g->time = TCcount; */
473 /* update time control info */
476 TimeControl.clock[side] -= (et + OperatorTime);
477 timecomp[compptr] = (et + OperatorTime);
479 /* finished our required moves - setup the next set */
480 --TimeControl.moves[side];
483 /* check for end conditions */
484 if ((root->flags & draw) /* && flag.bothsides */)
488 else if (GameCnt == MAXMOVES)
492 /* out of move store, you lose */
495 /* switch to other side */
499 /* if mate clear hint */
509 * Perform an alpha-beta search to determine the score for the current
510 * board position. If depth <= 0 only capturing moves and responses to
511 * check are generated and searched, otherwise all moves are processed. The
512 * search depth is modified for check evasions, certain re-captures and
513 * threats. Extensions may continue for up to 11 ply beyond the nominal
523 unsigned short *bstline,
527 short tempb, tempc, tempsf, tempst;
528 short xside, pbst, score, rcnt, in_check, blockable;
529 unsigned short mv, nxtline[MAXDEPTH];
530 struct leaf *node, tmp;
531 short best = -(SCORE_LIMIT + 3000);
542 /* look every ZNODE nodes for a timeout */
547 if (NodeCnt > ETnodes)
549 ElapsedTime(COMPUTE_MODE);
555 flag.musttimeout = false;
557 else if (TCflag || MaxResponseTime)
559 if ((et >= (ResponseTime + ExtraTime))
560 && (Sdepth > MINDEPTH))
562 /* try to extend to finish ply */
563 if (flag.back || (TCflag && TCcount < MAXTCCOUNTX))
566 flag.musttimeout = true;
574 flag.musttimeout = false;
582 flag.musttimeout = false;
585 #ifdef QUIETBACKGROUND
588 dsp->ShowResponseTime();
590 else if (!TCflag && flag.musttimeout && Sdepth > MINDEPTH)
593 flag.musttimeout = false;
600 score = evaluate(side, ply, alpha, beta,
601 INCscore, &in_check, &blockable);
604 * check for possible repitition if so call repitition - rpt is
608 if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
613 * repeat position >3 don't need to return score it's taken
630 /* score > SCORE_LIMIT its a draw or mate */
631 if (score > SCORE_LIMIT)
637 /* Do we need to add depth because of special conditions */
638 /* if in check or in capture sequence search deeper */
640 /***************** depth extensions *****************/
644 /* Allow opponent a chance to check again */
651 && (score > alpha) && (score < beta)
653 && CptrFlag[ply - 1] && CptrFlag[ply - 2])
672 timeout = flag.timeout;
676 || ((!timeout && (hung[side] > 1))
677 && (ply == Sdepth + 1))))
681 else if ((score <= beta)
682 && (((ply < Sdepth + 4) && (ply > 4))
685 && (ChkFlag[ply - 2] != ChkFlag[ply - 4])))
691 /***************************************************/
692 /* try the local transition table if it's there */
695 if (/* depth > 0 && */ flag.hash && ply > 1)
698 && ProbeTTable(side, depth, ply, &alpha, &beta, &score) == true)
701 bstline[ply + 1] = 0;
703 if (beta == -((SCORE_LIMIT + 1000) * 2))
711 /* ok try the transition file if its there */
713 && (depth > HashDepth)
714 && (GameCnt < HashMoveLimit)
715 && (ProbeFTable(side, depth, ply, &alpha, &beta, &score)
718 PutInTTable(side, score, depth, ply, beta, PV);
720 bstline[ply + 1] = 0;
722 if (beta == -((SCORE_LIMIT + 1000) * 2))
730 #endif /* HASHFILE */
734 if (TrPnt[ply] > (TREE - 300))
740 * If more then DepthBeyond ply past goal depth or at goal depth and
741 * score > beta quit - means we are out of the window.
744 if (mustcut || (ply > DepthBeyond) || ((depth < 1) && (score > beta)))
748 * If below first ply and not at goal depth generate all moves else
749 * only capture moves.
754 if ((depth > 0) || (ply < (SDEPTHLIM))
755 || (background && (ply < Sdepth + 2)))
756 MoveList(side, ply, in_check, blockable);
758 CaptureList(side, ply, in_check, blockable);
761 /* no moves return what we have */
764 * normally a search will continue til past goal and no more capture
768 /* unless it hits DepthBeyond */
769 if (TrPnt[ply] == TrPnt[ply + 1])
772 /* if not at goal set best = -inf else current score */
773 best = (depth > 0) ? -(SCORE_LIMIT + 3000) : score;
779 /* CHECKME: is the & really an && here? */
780 if (!null && /* no previous null-move */
781 !PVari && /* no null-move during the PV */
782 (ply > 2) & /* not at ply 1 */
785 !in_check) /* no check */
786 /* enough material such that zugzwang is unlikely
787 * but who knows which value is suitable? */
790 OK, we make a null move, i.e. this means we have nothing to do
791 but we have to keep the some arrays up to date otherwise gnushogi
792 gets confused. Maybe somebody knows exactly which information is
793 important and which isn't.
795 Another idea is that we try the null-move first and generate the
796 moves later. This may save time but we have to take care that
797 PV and other variables contain the right value so that the move
798 ordering works right.
803 nxtline[ply + 1] = 0;
810 g = &GameList[++GameCnt];
811 g->hashkey = hashkey;
813 FROMsquare = TOsquare = -1;
820 best = -search(xside, ply + 1, depth - 2,
821 -beta - 1, -beta, nxtline, &rcnt);
828 best = -(SCORE_LIMIT + 3000);
830 else if (best > beta)
836 best = -(SCORE_LIMIT + 3000);
841 /* if best so far is better than alpha set alpha to best */
845 /********************** main loop ****************************/
847 /* look at each move until no more or beta cutoff */
848 for (pnt = pbst = TrPnt[ply];
849 (pnt < TrPnt[ply + 1]) && (best <= beta);
852 /* find the most interesting looking of the remaining moves */
854 pick(pnt, TrPnt[ply + 1] - 1);
857 PVari = PVarisave && (pnt == TrPnt[ply]); /* Is this the PV? */
862 /* is this a forbidden move */
863 if (/* ply == 1 && */ node->score <= DONTUSE)
866 nxtline[ply + 1] = 0;
868 /* if at top level */
871 /* at the top update search status */
874 #ifdef QUIETBACKGROUND
876 #endif /* QUIETBACKGROUND */
877 dsp->ShowCurrentMove(pnt, node->f, node->t);
879 movesLeft = TrPnt[2] - pnt; /* to report with XBoard periodic updates */
880 currentMove = node->f << 8 | node->t;
883 if (!(node->flags & exact))
885 /* make the move and go deeper */
887 MakeMove(side, node, &tempb, &tempc, &tempsf,
889 CptrFlag[ply] = ((node->flags & capture) != 0);
890 TesujiFlag[ply] = (node->flags & tesuji)
891 && (node->flags & dropmask);
892 Tscore[ply] = node->score;
895 node->score = -search(xside, ply + 1,
896 (depth > 0) ? (depth - 1) : 0,
902 * node->score = score;
905 node->width = ((ply % 2) == 1)
906 ? (TrPnt[ply + 2] - TrPnt[ply + 1])
909 if ((node->score > SCORE_LIMIT) || (node->score < -SCORE_LIMIT) )
910 node->flags |= exact;
915 || ((node->score == (SCORE_LIMIT + 999) - ply)
918 node->flags |= (draw | exact);
919 DRAW = DRAW_JUSTDRAW;
920 node->score = ((side == computer) ? contempt : -contempt);
923 node->reply = nxtline[ply + 1];
925 /* reset to try next move */
926 UnmakeMove(side, node, &tempb, &tempc, &tempsf, &tempst);
929 /* if best move so far */
930 /* CHECKME: flag.timeout isn't valid if no hard time limit */
932 && ((node->score > best)
933 || ((node->score == best) && (node->width > bestwidth))))
936 * All things being equal pick the denser part of the
939 bestwidth = node->width;
942 * If not at goal depth and better than alpha and not
943 * an exact score increment by depth.
946 if ((depth > 0) && (node->score > alpha)
947 && !(node->flags & exact))
949 node->score += depth;
958 /* update best line */
959 for (j = ply + 1; nxtline[j] > 0; j++)
960 bstline[j] = nxtline[j];
963 bstline[ply] = (node->f << 8) | node->t;
969 * If it's better than the root score make it the root.
971 if ((best > root->score)
972 || ((best == root->score)
973 && (bestwidth > root->width)))
977 for (j = pnt - 1; j >= 0; j--)
978 Tree[j + 1] = Tree[j];
984 #ifdef QUIETBACKGROUND
987 #endif /* QUIETBACKGROUND */
992 dsp->ShowResults(best, bstline, '+');
994 else if (best < alpha)
996 dsp->ShowResults(best, bstline, '-');
1000 dsp->ShowResults(best, bstline, '&');
1003 #ifdef QUIETBACKGROUND
1010 return Tscore[ply - 1];
1013 /******************************************************/
1016 mv = (node->f << 8) | node->t;
1023 * We have a move so put it in local table - if it's already there
1024 * done else if not there or needs to be updated also put it in
1029 if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
1031 # ifdef HASHFILE /* MCV: warning: this confuses the formatter. */
1033 && PutInTTable(side, best, depth, ply, beta, mv)
1035 && (depth > HashDepth)
1036 && (GameCnt < HashMoveLimit))
1039 && PutInTTable(side, best, depth, ply, beta, mv))
1042 PutInFTable(side, best, depth, ply,
1043 alpha, beta, node->f, node->t);
1051 unsigned short h, x;
1054 if (history[x = hindex(side, h)] < HISTORYLIM)
1055 history[x] += (unsigned short) 1 << depth;
1058 if (node->t != (short)(GameList[GameCnt].gmove & 0xFF))
1064 else if (mv != killr1[ply])
1066 killr2[ply] = killr1[ply];
1071 killr0[ply] = ((best > SCORE_LIMIT) ? mv : 0);
1080 * Update the PieceList and Pindex arrays when a piece is captured or when a
1081 * capture is unmade.
1085 UpdatePieceList(short side, short sq, UpdatePieceList_mode iop)
1089 if (iop == REMOVE_PIECE)
1093 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1095 PieceList[side][i] = PieceList[side][i + 1];
1096 Pindex[PieceList[side][i]] = i;
1099 else if (board[sq] == king)
1101 /* king must have index 0 */
1102 for (i = PieceCnt[side]; i >= 0; i--)
1104 PieceList[side][i + 1] = PieceList[side][i];
1105 Pindex[PieceList[side][i + 1]] = i + 1;
1109 PieceList[side][0] = sq;
1115 PieceList[side][PieceCnt[side]] = sq;
1116 Pindex[sq] = PieceCnt[side];
1122 /* Make or Unmake drop move. */
1125 drop(short side, short piece, short t, short iop)
1133 #if !defined SAVE_SVALUE
1137 n = Captured[side][piece]--;
1139 UpdateDropHashbd(side, piece, n);
1140 UpdateHashbd(side, piece, -1, t);
1141 UpdatePieceList(side, t, ADD_PIECE);
1145 ++PawnCnt[side][column(t)];
1149 HasPiece[side][piece]++;
1154 board[t] = no_piece;
1156 n = ++Captured[side][piece];
1158 UpdateDropHashbd(side, piece, n);
1159 UpdateHashbd(side, piece, -1, t);
1160 UpdatePieceList(side, t, REMOVE_PIECE);
1163 --PawnCnt[side][column(t)];
1166 HasPiece[side][piece]--;
1175 unsigned long chashkey, chashbd;
1177 chashbd = chashkey = 0;
1179 for (sq = 0; sq < NO_SQUARES; sq++)
1181 if (color[sq] != neutral)
1183 chashbd ^= (*hashcode)[color[sq]][board[sq]][sq].bd;
1184 chashkey ^= (*hashcode)[color[sq]][board[sq]][sq].key;
1187 /* hashcodes for initial board are 0 ! */
1188 if (Stcolor[sq] != neutral)
1190 chashbd ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].bd;
1191 chashkey ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].key;
1195 for (side = 0; side <= 1; side++)
1199 for (piece = 0; piece < NO_PIECES; piece++)
1201 short n = Captured[side][piece];
1207 for (i = 1; i <= n; i++)
1209 chashbd ^= (*drop_hashcode)[side][piece][i].bd;
1210 chashkey ^= (*drop_hashcode)[side][piece][i].key;
1216 if (chashbd != hashbd)
1217 printf("chashbd %lu != hashbd %lu\n", chashbd, hashbd);
1219 if (chashkey != hashkey)
1220 printf("chashkey %lu != hashkey %lu\n", chashkey, hashkey);
1222 if (chashbd != hashbd || chashkey != hashkey)
1233 * Update Arrays board[], color[], and Pindex[] to reflect the new board
1234 * position obtained after making the move pointed to by node. Also update
1235 * miscellaneous stuff that changes when a move is made.
1239 MakeMove(short side,
1241 short *tempb, /* piece at to square */
1242 short *tempc, /* color of to square */
1243 short *tempsf, /* static value of piece on from */
1244 short *tempst, /* static value of piece on to */
1245 short *INCscore) /* score increment */
1252 g = &GameList[++GameCnt];
1253 g->hashkey = hashkey;
1255 FROMsquare = f = node->f;
1256 TOsquare = t = (node->t & 0x7f);
1257 *INCscore = (short)node->INCscore;
1259 g->gmove = (f << 8) | node->t;
1260 g->flags = node->flags;
1266 algbr(f, t, node->flags);
1267 printf("error before MakeMove: %s\n", mvstr[0]);
1268 UpdateDisplay(0, 0, 1, 0);
1270 for (i = 1; i <= GameCnt; i++)
1272 movealgbr(GameList[i].gmove, mvstr[0]);
1273 printf("%d: %s\n", i, mvstr[0]);
1280 rpthash[side][hashkey & 0xFF]++, ISZERO++;
1284 g->fpiece = (node->flags & pmask);
1285 g->piece = *tempb = no_piece;
1286 g->color = *tempc = neutral;
1288 #if !defined SAVE_SVALUE
1290 *tempst = svalue[t];
1293 (void)drop(side, g->fpiece, t, 1);
1297 #if !defined SAVE_SVALUE
1298 *tempsf = svalue[f];
1299 *tempst = svalue[t];
1302 g->fpiece = board[f];
1303 g->piece = *tempb = board[t];
1304 g->color = *tempc = color[t];
1308 if (*tempc != neutral)
1310 /* Capture a piece */
1311 UpdatePieceList(*tempc, t, REMOVE_PIECE);
1313 /* if capture decrement pawn count */
1315 --PawnCnt[*tempc][column(t)];
1317 mtl[xside] -= (*value)[stage][*tempb];
1318 HasPiece[xside][*tempb]--;
1321 short n, upiece = unpromoted[*tempb];
1323 /* add "upiece" captured by "side" */
1324 n = ++Captured[side][upiece];
1326 UpdateDropHashbd(side, upiece, n);
1327 mtl[side] += (*value)[stage][upiece];
1330 /* remove "*tempb" of "xside" from board[t] */
1331 UpdateHashbd(xside, *tempb, -1, t);
1333 #if !defined SAVE_SVALUE
1334 *INCscore += *tempst; /* add value of catched piece
1343 #if !defined SAVE_SVALUE
1344 svalue[t] = svalue[f];
1348 Pindex[t] = Pindex[f];
1349 PieceList[side][Pindex[t]] = t;
1351 board[f] = no_piece;
1353 if (node->flags & promote)
1357 board[t] = tob = promoted[fromb];
1359 /* remove unpromoted piece from board[f] */
1360 UpdateHashbd(side, fromb, f, -1);
1362 /* add promoted piece to board[t] */
1363 UpdateHashbd(side, tob, -1, t);
1364 mtl[side] += value[stage][tob] - value[stage][fromb];
1367 --PawnCnt[side][column(f)];
1369 HasPiece[side][fromb]--;
1370 HasPiece[side][tob]++;
1372 #if !defined SAVE_SVALUE
1373 *INCscore -= *tempsf;
1379 /* remove piece from board[f] and add it to board[t] */
1380 UpdateHashbd(side, fromb, f, t);
1387 algbr(f, t, node->flags);
1391 printf("error in MakeMove: %s\n", mvstr[0]);
1405 UnmakeMove(short side,
1417 Game50 = GameList[GameCnt].Game50;
1419 if (node->flags & dropmask)
1421 (void)drop(side, (node->flags & pmask), t, 2);
1423 #if !defined SAVE_SVALUE
1424 svalue[t] = *tempst;
1431 color[f] = color[t];
1432 board[f] = tob = fromb = board[t];
1434 #if !defined SAVE_SVALUE
1435 svalue[f] = *tempsf;
1438 Pindex[f] = Pindex[t];
1439 PieceList[side][Pindex[f]] = f;
1443 #if !defined SAVE_SVALUE
1444 svalue[t] = *tempst;
1448 if (node->flags & promote)
1450 board[f] = fromb = unpromoted[tob];
1451 mtl[side] += value[stage][fromb] - value[stage][tob];
1454 ++PawnCnt[side][column(f)];
1456 HasPiece[side][fromb]++;
1457 HasPiece[side][tob]--;
1459 /* add unpromoted piece to board[f] */
1460 UpdateHashbd(side, fromb, f, -1);
1462 /* remove promoted piece from board[t] */
1463 UpdateHashbd(side, tob, -1, t);
1469 --PawnCnt[side][column(t)];
1470 ++PawnCnt[side][column(f)];
1473 /* remove piece from board[t] and add it to board[f] */
1474 UpdateHashbd(side, fromb, f, t);
1478 if (*tempc != neutral)
1480 short n, upiece = unpromoted[*tempb];
1482 UpdatePieceList(*tempc, t, ADD_PIECE);
1485 ++PawnCnt[*tempc][column(t)];
1487 mtl[xside] += (*value)[stage][*tempb];
1488 HasPiece[xside][*tempb]++;
1489 mtl[side] -= (*value)[stage][upiece];
1491 /* remove "upiece" captured by "side" */
1492 n = Captured[side][upiece]--;
1494 UpdateDropHashbd(side, upiece, n);
1496 /* replace captured piece on board[t] */
1497 UpdateHashbd(xside, *tempb, -1, t);
1505 rpthash[side][hashkey & 0xFF]--, ISZERO--;
1508 algbr(f, t, node->flags);
1512 printf("error in UnmakeMove: %s\n", mvstr[0]);
1521 * Scan thru the board seeing what's on each square. If a piece is found,
1522 * update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1523 * determine the material for each side and set the hashkey and hashbd
1524 * variables to represent the current board position. Array
1525 * PieceList[side][indx] contains the location of all the pieces of either
1526 * side. Array Pindex[sq] contains the indx into PieceList for a given
1531 InitializeStats(void)
1535 for (i = 0; i < NO_COLS; i++)
1536 PawnCnt[black][i] = PawnCnt[white][i] = 0;
1538 mtl[black] = mtl[white] = 0;
1539 PieceCnt[black] = PieceCnt[white] = 0;
1540 hashbd = hashkey = 0;
1542 for (sq = 0; sq < NO_SQUARES; sq++)
1544 if (color[sq] != neutral)
1546 mtl[color[sq]] += (*value)[stage][board[sq]];
1548 if (board[sq] == pawn)
1549 ++PawnCnt[color[sq]][column(sq)];
1551 Pindex[sq] = ((board[sq] == king) ? 0 : ++PieceCnt[color[sq]]);
1552 PieceList[color[sq]][Pindex[sq]] = sq;
1553 UpdateHashbd(color[sq], board[sq], sq, -1);
1556 /* hashcodes for initial board are 0 ! */
1557 if (Stcolor[sq] != neutral)
1558 UpdateHashbd(Stcolor[sq], Stboard[sq], sq, -1);
1564 for (side = 0; side <= 1; side++)
1568 for (piece = 0; piece < NO_PIECES; piece++)
1570 short n = Captured[side][piece];
1574 Captured[side][piece] = 0;
1576 for (i = 1; i <= n; i++)
1578 ++Captured[side][piece];
1579 UpdateDropHashbd(side, piece, i);
1580 mtl[side] += (*value)[stage][piece];
1590 printf("error in InitializeStats\n");