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
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 * ----------------------------------------------------------------------
37 static short DepthBeyond;
38 unsigned short PrVar[MAXDEPTH];
39 extern short recycle, ISZERO;
40 extern void FlagString(unsigned short flags, char *s);
43 short null; /* Null-move already made or not */
44 short PVari; /* Is this the PV */
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 */
189 score = ScorePosition(side);
191 #ifdef QUIETBACKGROUND
193 #endif /* QUIETBACKGROUND */
196 #ifdef QUIETBACKGROUND
198 #endif /* QUIETBACKGROUND */
199 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, side);
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 ShowResults(score, PrVar, '.');
403 /********************** end of main loop ***************************/
405 /* background mode */
406 if (iop == BACKGROUND_MODE)
412 DRAW = CP[101]; /* 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 = CP[80]; /* Max Moves */
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);
531 static struct pollfd pollfds[1] = { /* [0] = */ { /* .fd = */ STDIN_FILENO,
532 /* .events = */ POLLIN } };
541 /* look every ZNODE nodes for a timeout */
546 if (NodeCnt > ETnodes)
548 ElapsedTime(COMPUTE_MODE);
551 int cnt = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 0);
553 perror("polling standard input");
556 if (cnt) { /* if anything to read, or error occured */
558 flag.back = true; /* previous: flag.timeout = true; */
559 flag.bothsides = false;
567 flag.musttimeout = false;
569 else if (TCflag || MaxResponseTime)
571 if ((et >= (ResponseTime + ExtraTime))
572 && (Sdepth > MINDEPTH))
574 /* try to extend to finish ply */
575 if (flag.back || (TCflag && TCcount < MAXTCCOUNTX))
578 flag.musttimeout = true;
586 flag.musttimeout = false;
594 flag.musttimeout = false;
597 #ifdef QUIETBACKGROUND
602 else if (!TCflag && flag.musttimeout && Sdepth > MINDEPTH)
605 flag.musttimeout = false;
612 score = evaluate(side, ply, alpha, beta,
613 INCscore, &in_check, &blockable);
616 * check for possible repitition if so call repitition - rpt is
620 if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
625 * repeat position >3 don't need to return score it's taken
642 /* score > SCORE_LIMIT its a draw or mate */
643 if (score > SCORE_LIMIT)
649 /* Do we need to add depth because of special conditions */
650 /* if in check or in capture sequence search deeper */
652 /***************** depth extensions *****************/
656 /* Allow opponent a chance to check again */
663 && (score > alpha) && (score < beta)
665 && CptrFlag[ply - 1] && CptrFlag[ply - 2])
684 timeout = flag.timeout;
688 || ((!timeout && (hung[side] > 1))
689 && (ply == Sdepth + 1))))
693 else if ((score <= beta)
694 && (((ply < Sdepth + 4) && (ply > 4))
697 && (ChkFlag[ply - 2] != ChkFlag[ply - 4])))
703 /***************************************************/
704 /* try the local transition table if it's there */
707 if (/* depth > 0 && */ flag.hash && ply > 1)
710 && ProbeTTable(side, depth, ply, &alpha, &beta, &score) == true)
713 bstline[ply + 1] = 0;
715 if (beta == -((SCORE_LIMIT + 1000) * 2))
723 /* ok try the transition file if its there */
725 && (depth > HashDepth)
726 && (GameCnt < HashMoveLimit)
727 && (ProbeFTable(side, depth, ply, &alpha, &beta, &score)
730 PutInTTable(side, score, depth, ply, alpha, beta, PV);
732 bstline[ply + 1] = 0;
734 if (beta == -((SCORE_LIMIT + 1000) * 2))
742 #endif /* HASHFILE */
746 if (TrPnt[ply] > (TREE - 300))
752 * If more then DepthBeyond ply past goal depth or at goal depth and
753 * score > beta quit - means we are out of the window.
756 if (mustcut || (ply > DepthBeyond) || ((depth < 1) && (score > beta)))
760 * If below first ply and not at goal depth generate all moves else
761 * only capture moves.
766 if ((depth > 0) || (ply < (SDEPTHLIM))
767 || (background && (ply < Sdepth + 2)))
768 MoveList(side, ply, in_check, blockable);
770 CaptureList(side, ply, in_check, blockable);
773 /* no moves return what we have */
776 * normally a search will continue til past goal and no more capture
780 /* unless it hits DepthBeyond */
781 if (TrPnt[ply] == TrPnt[ply + 1])
784 /* if not at goal set best = -inf else current score */
785 best = (depth > 0) ? -(SCORE_LIMIT + 3000) : score;
791 /* CHECKME: is the & really an && here? */
792 if (!null && /* no previous null-move */
793 !PVari && /* no null-move during the PV */
794 (ply > 2) & /* not at ply 1 */
797 !in_check) /* no check */
798 /* enough material such that zugzwang is unlikely
799 * but who knows which value is suitable? */
802 OK, we make a null move, i.e. this means we have nothing to do
803 but we have to keep the some arrays up to date otherwise gnushogi
804 gets confused. Maybe somebody knows exactly which information is
805 important and which isn't.
807 Another idea is that we try the null-move first and generate the
808 moves later. This may save time but we have to take care that
809 PV and other variables contain the right value so that the move
810 ordering works right.
815 nxtline[ply + 1] = 0;
822 g = &GameList[++GameCnt];
823 g->hashkey = hashkey;
825 FROMsquare = TOsquare = -1;
832 best = -search(xside, ply + 1, depth - 2,
833 -beta - 1, -beta, nxtline, &rcnt);
840 best = -(SCORE_LIMIT + 3000);
842 else if (best > beta)
848 best = -(SCORE_LIMIT + 3000);
853 /* if best so far is better than alpha set alpha to best */
857 /********************** main loop ****************************/
859 /* look at each move until no more or beta cutoff */
860 for (pnt = pbst = TrPnt[ply];
861 (pnt < TrPnt[ply + 1]) && (best <= beta);
864 /* find the most interesting looking of the remaining moves */
866 pick(pnt, TrPnt[ply + 1] - 1);
869 PVari = PVarisave && (pnt == TrPnt[ply]); /* Is this the PV? */
874 /* is this a forbidden move */
875 if (/* ply == 1 && */ node->score <= DONTUSE)
878 nxtline[ply + 1] = 0;
880 /* if at top level */
884 /* at the top update search status */
887 #ifdef QUIETBACKGROUND
889 #endif /* QUIETBACKGROUND */
890 ShowCurrentMove(pnt, node->f, node->t);
895 if (!(node->flags & exact))
897 /* make the move and go deeper */
899 MakeMove(side, node, &tempb, &tempc, &tempsf,
901 CptrFlag[ply] = ((node->flags & capture) != 0);
902 TesujiFlag[ply] = (node->flags & tesuji)
903 && (node->flags & dropmask);
904 Tscore[ply] = node->score;
907 node->score = -search(xside, ply + 1,
908 (depth > 0) ? (depth - 1) : 0,
914 * node->score = score;
917 node->width = ((ply % 2) == 1)
918 ? (TrPnt[ply + 2] - TrPnt[ply + 1])
921 if ((node->score > SCORE_LIMIT) || (node->score < -SCORE_LIMIT) )
922 node->flags |= exact;
927 || ((node->score == (SCORE_LIMIT + 999) - ply)
930 node->flags |= (draw | exact);
931 DRAW = CP[58]; /* Draw */
932 node->score = ((side == computer) ? contempt : -contempt);
935 node->reply = nxtline[ply + 1];
937 /* reset to try next move */
938 UnmakeMove(side, node, &tempb, &tempc, &tempsf, &tempst);
941 /* if best move so far */
942 /* CHECKME: flag.timeout isn't valid if no hard time limit */
944 && ((node->score > best)
945 || ((node->score == best) && (node->width > bestwidth))))
948 * All things being equal pick the denser part of the
951 bestwidth = node->width;
954 * If not at goal depth and better than alpha and not
955 * an exact score increment by depth.
958 if ((depth > 0) && (node->score > alpha)
959 && !(node->flags & exact))
961 node->score += depth;
970 /* update best line */
971 for (j = ply + 1; nxtline[j] > 0; j++)
972 bstline[j] = nxtline[j];
975 bstline[ply] = (node->f << 8) | node->t;
981 * If it's better than the root score make it the root.
983 if ((best > root->score)
984 || ((best == root->score)
985 && (bestwidth > root->width)))
989 for (j = pnt - 1; j >= 0; j--)
990 Tree[j + 1] = Tree[j];
996 #ifdef QUIETBACKGROUND
999 #endif /* QUIETBACKGROUND */
1004 ShowResults(best, bstline, '+');
1006 else if (best < alpha)
1008 ShowResults(best, bstline, '-');
1012 ShowResults (best, bstline, '&');
1015 #ifdef QUIETBACKGROUND
1022 return Tscore[ply - 1];
1025 /******************************************************/
1028 mv = (node->f << 8) | node->t;
1035 * We have a move so put it in local table - if it's already there
1036 * done else if not there or needs to be updated also put it in
1041 if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
1043 # ifdef HASHFILE /* MCV: warning: this confuses the formatter. */
1045 && PutInTTable(side, best, depth, ply, alpha, beta, mv)
1047 && (depth > HashDepth)
1048 && (GameCnt < HashMoveLimit))
1051 && PutInTTable(side, best, depth, ply, alpha, beta, mv))
1054 PutInFTable(side, best, depth, ply,
1055 alpha, beta, node->f, node->t);
1063 unsigned short h, x;
1066 if (history[x = hindex(side, h)] < HISTORYLIM)
1067 history[x] += (unsigned short) 1 << depth;
1070 if (node->t != (short)(GameList[GameCnt].gmove & 0xFF))
1076 else if (mv != killr1[ply])
1078 killr2[ply] = killr1[ply];
1083 killr0[ply] = ((best > SCORE_LIMIT) ? mv : 0);
1092 * Update the PieceList and Pindex arrays when a piece is captured or when a
1093 * capture is unmade.
1097 UpdatePieceList(short side, short sq, UpdatePieceList_mode iop)
1101 if (iop == REMOVE_PIECE)
1105 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1107 PieceList[side][i] = PieceList[side][i + 1];
1108 Pindex[PieceList[side][i]] = i;
1111 else if (board[sq] == king)
1113 /* king must have index 0 */
1114 for (i = PieceCnt[side]; i >= 0; i--)
1116 PieceList[side][i + 1] = PieceList[side][i];
1117 Pindex[PieceList[side][i + 1]] = i + 1;
1121 PieceList[side][0] = sq;
1127 PieceList[side][PieceCnt[side]] = sq;
1128 Pindex[sq] = PieceCnt[side];
1134 /* Make or Unmake drop move. */
1137 drop(short side, short piece, short f, short t, short iop)
1145 #if !defined SAVE_SVALUE
1149 n = Captured[side][piece]--;
1151 UpdateDropHashbd(side, piece, n);
1152 UpdateHashbd(side, piece, -1, t);
1153 UpdatePieceList(side, t, ADD_PIECE);
1157 ++PawnCnt[side][column(t)];
1161 HasPiece[side][piece]++;
1166 board[t] = no_piece;
1168 n = ++Captured[side][piece];
1170 UpdateDropHashbd(side, piece, n);
1171 UpdateHashbd(side, piece, -1, t);
1172 UpdatePieceList(side, t, REMOVE_PIECE);
1175 --PawnCnt[side][column(t)];
1178 HasPiece[side][piece]--;
1187 unsigned long chashkey, chashbd;
1189 chashbd = chashkey = 0;
1191 for (sq = 0; sq < NO_SQUARES; sq++)
1193 if (color[sq] != neutral)
1195 chashbd ^= (*hashcode)[color[sq]][board[sq]][sq].bd;
1196 chashkey ^= (*hashcode)[color[sq]][board[sq]][sq].key;
1199 /* hashcodes for initial board are 0 ! */
1200 if (Stcolor[sq] != neutral)
1202 chashbd ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].bd;
1203 chashkey ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].key;
1207 for (side = 0; side <= 1; side++)
1211 for (piece = 0; piece < NO_PIECES; piece++)
1213 short n = Captured[side][piece];
1219 for (i = 1; i <= n; i++)
1221 chashbd ^= (*drop_hashcode)[side][piece][i].bd;
1222 chashkey ^= (*drop_hashcode)[side][piece][i].key;
1228 if (chashbd != hashbd)
1229 printf("chashbd %lu != hashbd %lu\n", chashbd, hashbd);
1231 if (chashkey != hashkey)
1232 printf("chashkey %lu != hashkey %lu\n", chashkey, hashkey);
1234 if (chashbd != hashbd || chashkey != hashkey)
1245 * Update Arrays board[], color[], and Pindex[] to reflect the new board
1246 * position obtained after making the move pointed to by node. Also update
1247 * miscellaneous stuff that changes when a move is made.
1251 MakeMove(short side,
1253 short *tempb, /* piece at to square */
1254 short *tempc, /* color of to square */
1255 short *tempsf, /* static value of piece on from */
1256 short *tempst, /* static value of piece on to */
1257 short *INCscore) /* score increment */
1264 g = &GameList[++GameCnt];
1265 g->hashkey = hashkey;
1267 FROMsquare = f = node->f;
1268 TOsquare = t = (node->t & 0x7f);
1269 *INCscore = (short)node->INCscore;
1271 g->gmove = (f << 8) | node->t;
1272 g->flags = node->flags;
1278 algbr(f, t, node->flags);
1279 printf("error before MakeMove: %s\n", mvstr[0]);
1280 UpdateDisplay(0, 0, 1, 0);
1282 for (i = 1; i <= GameCnt; i++)
1284 movealgbr(GameList[i].gmove, mvstr[0]);
1285 printf("%d: %s\n", i, mvstr[0]);
1292 rpthash[side][hashkey & 0xFF]++, ISZERO++;
1296 g->fpiece = (node->flags & pmask);
1297 g->piece = *tempb = no_piece;
1298 g->color = *tempc = neutral;
1300 #if !defined SAVE_SVALUE
1302 *tempst = svalue[t];
1305 (void)drop(side, g->fpiece, f, t, 1);
1309 #if !defined SAVE_SVALUE
1310 *tempsf = svalue[f];
1311 *tempst = svalue[t];
1314 g->fpiece = board[f];
1315 g->piece = *tempb = board[t];
1316 g->color = *tempc = color[t];
1320 if (*tempc != neutral)
1322 /* Capture a piece */
1323 UpdatePieceList(*tempc, t, REMOVE_PIECE);
1325 /* if capture decrement pawn count */
1327 --PawnCnt[*tempc][column(t)];
1329 mtl[xside] -= (*value)[stage][*tempb];
1330 HasPiece[xside][*tempb]--;
1333 short n, upiece = unpromoted[*tempb];
1335 /* add "upiece" captured by "side" */
1336 n = ++Captured[side][upiece];
1338 UpdateDropHashbd(side, upiece, n);
1339 mtl[side] += (*value)[stage][upiece];
1342 /* remove "*tempb" of "xside" from board[t] */
1343 UpdateHashbd(xside, *tempb, -1, t);
1345 #if !defined SAVE_SVALUE
1346 *INCscore += *tempst; /* add value of catched piece
1355 #if !defined SAVE_SVALUE
1356 svalue[t] = svalue[f];
1360 Pindex[t] = Pindex[f];
1361 PieceList[side][Pindex[t]] = t;
1363 board[f] = no_piece;
1365 if (node->flags & promote)
1369 board[t] = tob = promoted[fromb];
1371 /* remove unpromoted piece from board[f] */
1372 UpdateHashbd(side, fromb, f, -1);
1374 /* add promoted piece to board[t] */
1375 UpdateHashbd(side, tob, -1, t);
1376 mtl[side] += value[stage][tob] - value[stage][fromb];
1379 --PawnCnt[side][column(f)];
1381 HasPiece[side][fromb]--;
1382 HasPiece[side][tob]++;
1384 #if !defined SAVE_SVALUE
1385 *INCscore -= *tempsf;
1391 /* remove piece from board[f] and add it to board[t] */
1392 UpdateHashbd(side, fromb, f, t);
1399 algbr(f, t, node->flags);
1403 printf("error in MakeMove: %s\n", mvstr[0]);
1417 UnmakeMove(short side,
1429 Game50 = GameList[GameCnt].Game50;
1431 if (node->flags & dropmask)
1433 (void)drop(side, (node->flags & pmask), f, t, 2);
1435 #if !defined SAVE_SVALUE
1436 svalue[t] = *tempst;
1443 color[f] = color[t];
1444 board[f] = tob = fromb = board[t];
1446 #if !defined SAVE_SVALUE
1447 svalue[f] = *tempsf;
1450 Pindex[f] = Pindex[t];
1451 PieceList[side][Pindex[f]] = f;
1455 #if !defined SAVE_SVALUE
1456 svalue[t] = *tempst;
1460 if (node->flags & promote)
1462 board[f] = fromb = unpromoted[tob];
1463 mtl[side] += value[stage][fromb] - value[stage][tob];
1466 ++PawnCnt[side][column(f)];
1468 HasPiece[side][fromb]++;
1469 HasPiece[side][tob]--;
1471 /* add unpromoted piece to board[f] */
1472 UpdateHashbd(side, fromb, f, -1);
1474 /* remove promoted piece from board[t] */
1475 UpdateHashbd(side, tob, -1, t);
1481 --PawnCnt[side][column(t)];
1482 ++PawnCnt[side][column(f)];
1485 /* remove piece from board[t] and add it to board[f] */
1486 UpdateHashbd(side, fromb, f, t);
1490 if (*tempc != neutral)
1492 short n, upiece = unpromoted[*tempb];
1494 UpdatePieceList(*tempc, t, ADD_PIECE);
1497 ++PawnCnt[*tempc][column(t)];
1499 mtl[xside] += (*value)[stage][*tempb];
1500 HasPiece[xside][*tempb]++;
1501 mtl[side] -= (*value)[stage][upiece];
1503 /* remove "upiece" captured by "side" */
1504 n = Captured[side][upiece]--;
1506 UpdateDropHashbd(side, upiece, n);
1508 /* replace captured piece on board[t] */
1509 UpdateHashbd(xside, *tempb, -1, t);
1517 rpthash[side][hashkey & 0xFF]--, ISZERO--;
1520 algbr(f, t, node->flags);
1524 printf("error in UnmakeMove: %s\n", mvstr[0]);
1533 * Scan thru the board seeing what's on each square. If a piece is found,
1534 * update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1535 * determine the material for each side and set the hashkey and hashbd
1536 * variables to represent the current board position. Array
1537 * PieceList[side][indx] contains the location of all the pieces of either
1538 * side. Array Pindex[sq] contains the indx into PieceList for a given
1543 InitializeStats(void)
1547 for (i = 0; i < NO_COLS; i++)
1548 PawnCnt[black][i] = PawnCnt[white][i] = 0;
1550 mtl[black] = mtl[white] = 0;
1551 PieceCnt[black] = PieceCnt[white] = 0;
1552 hashbd = hashkey = 0;
1554 for (sq = 0; sq < NO_SQUARES; sq++)
1556 if (color[sq] != neutral)
1558 mtl[color[sq]] += (*value)[stage][board[sq]];
1560 if (board[sq] == pawn)
1561 ++PawnCnt[color[sq]][column(sq)];
1563 Pindex[sq] = ((board[sq] == king) ? 0 : ++PieceCnt[color[sq]]);
1564 PieceList[color[sq]][Pindex[sq]] = sq;
1565 UpdateHashbd(color[sq], board[sq], sq, -1);
1568 /* hashcodes for initial board are 0 ! */
1569 if (Stcolor[sq] != neutral)
1570 UpdateHashbd(Stcolor[sq], Stboard[sq], sq, -1);
1576 for (side = 0; side <= 1; side++)
1580 for (piece = 0; piece < NO_PIECES; piece++)
1582 short n = Captured[side][piece];
1586 Captured[side][piece] = 0;
1588 for (i = 1; i <= n; i++)
1590 ++Captured[side][piece];
1591 UpdateDropHashbd(side, piece, i);
1592 mtl[side] += (*value)[stage][piece];
1602 printf("error in InitializeStats\n");