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 */
50 /* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
55 * Check for draw by fourfold repetition
56 * (same side, same captures, same board).
57 * WARNING: this is not save (sp? safe?) yet due to possible hash collisions.
68 if (GameCnt > Game50 + 6)
70 for (i = GameCnt - 1; i >= Game50; i -= 2)
74 if (g->hashkey == hashkey && g->hashbd == hashbd)
85 int plyscore, globalscore;
89 * Find the best move in the tree between indexes p1 and p2. Swap the best
90 * move into the p1 element.
94 pick(short p1, short p2)
96 struct leaf *p, *q, *r, *k;
104 for (r = p + 1; r <= q; r++)
124 int bookflag = false;
134 * Select a move by calling function search() at progressively deeper ply
135 * until time is up or a mate or draw is reached. An alpha-beta window of
136 * -Awindow to +Bwindow points is set around the score returned from the
137 * previous iteration. If Sdepth != 0 then the program has correctly
138 * predicted the opponents move and the search will start at a depth of
139 * Sdepth + 1 rather than a depth of 1.
143 SelectMove(short side, SelectMove_mode iop)
145 static short i, tempb, tempc, tempsf, tempst, xside, rpt;
146 static short alpha, beta, score;
147 static struct GameRec *g;
148 short sqking, in_check, blockable;
151 printf("hashbd = %ld (hashkey >> 16)|side = %d\n",
152 hashbd, (hashkey >> 16)|side);
155 flag.timeout = false;
157 flag.musttimeout = false;
162 recycle = (GameCnt % rehash) - rehash;
165 ExaminePosition(side);
167 /* if background mode set to infinite */
168 if (iop == BACKGROUND_MODE)
171 /* if background mode set response time to infinite */
172 ResponseTime = 9999999;
176 background = false; /* [HGM] with ponder on we did not switch back to foreground mode??? */
178 SetResponseTime(side);
181 #ifdef QUIETBACKGROUND
183 #endif /* QUIETBACKGROUND */
184 dsp->ShowResponseTime();
188 score = ScorePosition(side);
190 #ifdef QUIETBACKGROUND
192 #endif /* QUIETBACKGROUND */
193 dsp->ShowSidetoMove();
195 #ifdef QUIETBACKGROUND
197 #endif /* QUIETBACKGROUND */
198 dsp->SearchStartStuff(side);
201 array_zero(history, sizeof_history);
204 FROMsquare = TOsquare = -1;
207 if (iop == FOREGROUND_MODE)
211 * If the last move was the hint, select the computed answer to the
212 * hint as first move to examine.
218 SwagHt = (GameList[GameCnt].gmove == PrVar[2]) ? PrVar[3] : 0;
225 for (i = 0; i < MAXDEPTH; i++)
226 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
228 /* set initial window for search */
232 alpha = -(SCORE_LIMIT + 999);
233 beta = SCORE_LIMIT + 999;
237 alpha = score - ((computer == white) ? BAwindow : WAwindow);
238 beta = score + ((computer == white) ? BBwindow : WBwindow);
245 sqking = PieceList[side][0];
246 in_check = (board[sqking] == king)
247 ? SqAttacked(sqking, side^1, &blockable)
250 MoveList(side, 1, in_check, blockable);
252 for (i = TrPnt[1]; i < TrPnt[2]; i++)
254 if (!pick(i, TrPnt[2] - 1))
258 /* Can I get a book move? */
260 if (flag.regularstart && Book)
262 flag.timeout = bookflag = OpeningBook(&hint);
265 ResponseTime += ResponseTime;
268 /* Zero stats for hash table. */
270 reminus = replus = 0;
271 GenCnt = NodeCnt = ETnodes = EvalNodes = HashCnt
272 = FHashAdd = HashAdd = FHashCnt = THashCol = HashCol = 0;
274 globalscore = plyscore = score;
279 /********************* main loop ********************************/
281 Sdepth = (MaxSearchDepth < (MINDEPTH - 1))
285 while (!flag.timeout)
287 /* go down a level at a time */
295 /* terminate search at DepthBeyond ply past goal depth */
297 DepthBeyond = Sdepth;
300 DepthBeyond = Sdepth + ((Sdepth == 1) ? 3 : 5);
302 DepthBeyond = Sdepth + ((Sdepth == 1) ? 7 : 11);
305 # ifdef QUIETBACKGROUND
307 #endif /* QUIETBACKGROUND */
310 /* search at this level returns score of PV */
311 score = search(side, 1, Sdepth, alpha, beta, PrVar, &rpt);
313 /* save PV as killer */
314 for (i = 1; i <= Sdepth; i++)
315 killr0[i] = PrVar[i];
317 /* low search failure re-search with (-inf, score) limits */
321 #ifdef QUIETBACKGROUND
323 #endif /* QUIETBACKGROUND */
326 if (TCflag && TCcount < MAXTCCOUNTR)
329 ExtraTime += (MAXTCCOUNTR - TCcount) * TCleft;
331 ExtraTime += (8 * TCleft);
333 TCcount = MAXTCCOUNTR - 1;
336 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
337 (SCORE_LIMIT + 999), PrVar, &rpt);
339 /* high search failure re-search with (score, +inf) limits */
340 else if (score > beta && !(root->flags & exact))
343 #ifdef QUIETBACKGROUND
345 #endif /* QUIETBACKGROUND */
348 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
349 (SCORE_LIMIT + 999), PrVar, &rpt);
352 /**************** out of search ***********************************/
353 CheckForTimeout(score, globalscore, Jscore, zwndw);
355 /************************ time control ****************************/
357 /* save PV as killer */
358 for (i = 1; i <= Sdepth + 1; i++)
359 killr0[i] = PrVar[i];
364 /* if (!flag.timeout) */
366 for (i = TrPnt[1] + 1; i < TrPnt[2]; i++)
367 if (!pick (i, TrPnt[2] - 1))
371 /* if done or nothing good to look at quit */
372 if ((root->flags & exact) || (score < -SCORE_LIMIT))
375 /* find the next best move put below root */
379 #if !defined NODYNALPHA
380 Jscore = (plyscore + score) >> 1;
382 zwndw = 20 + abs(Jscore / 12);
385 /* recompute search window */
386 beta = score + ((computer == white) ? BBwindow : WBwindow);
387 #if !defined NODYNALPHA
388 alpha = ((Jscore < score) ? Jscore : score)
389 - ((computer == white) ? BAwindow : WAwindow)
392 alpha = score - ((computer == white) ? BAwindow : WAwindow);
396 #ifdef QUIETBACKGROUND
398 #endif /* QUIETBACKGROUND */
399 dsp->ShowResults(score, PrVar, '.');
402 /********************** end of main loop ***************************/
404 /* background mode */
405 if (iop == BACKGROUND_MODE)
411 DRAW = DRAW_REPETITION;
416 * If there are no moves and we're not in check (stalemate) then
417 * it's mate in shogi (whereas it's a draw in chess).
420 if (GameCnt == MAXMOVES)
423 DRAW = DRAW_MAXMOVES;
427 /* not in book so set hint to guessed move for other side */
429 hint = ((PrVar[1]) ? PrVar[2] : 0);
431 /* if not mate or draw make move and output it */
432 if (((score > -(SCORE_LIMIT + 999))
433 && (rpt <= 3)) || (root->flags & draw))
435 MakeMove(side, &Tree[0], &tempb, &tempc,
436 &tempsf, &tempst, &INCscore);
437 algbr(root->f, root->t, (short) root->flags);
441 algbr(0, 0, 0); /* Zero move string when mate. */
442 root->score = score; /* When mate, ignore distinctions!
446 g = &GameList[GameCnt];
448 if ((g->flags & capture) && (g->piece == king))
449 flag.mate = flag.illegal = true;
451 /* If Time Control get the elapsed time */
453 ElapsedTime(COMPUTE_AND_INIT_MODE);
455 /* update time control info */
458 /* if mate set flag */
459 if ((score == -(SCORE_LIMIT + 999) || score == (SCORE_LIMIT + 998)))
462 /* add move to game list */
465 g->time = (et +50)/100;
466 /* g->time = TCcount; */
469 /* update time control info */
472 TimeControl.clock[side] -= (et + OperatorTime);
473 timecomp[compptr] = (et + OperatorTime);
475 /* finished our required moves - setup the next set */
476 --TimeControl.moves[side];
479 /* check for end conditions */
480 if ((root->flags & draw) /* && flag.bothsides */)
484 else if (GameCnt == MAXMOVES)
488 /* out of move store, you lose */
491 /* switch to other side */
495 /* if mate clear hint */
505 * Perform an alpha-beta search to determine the score for the current
506 * board position. If depth <= 0 only capturing moves and responses to
507 * check are generated and searched, otherwise all moves are processed. The
508 * search depth is modified for check evasions, certain re-captures and
509 * threats. Extensions may continue for up to 11 ply beyond the nominal
519 unsigned short *bstline,
523 short tempb, tempc, tempsf, tempst;
524 short xside, pbst, score, rcnt, in_check, blockable;
525 unsigned short mv, nxtline[MAXDEPTH];
526 struct leaf *node, tmp;
527 short best = -(SCORE_LIMIT + 3000);
538 /* look every ZNODE nodes for a timeout */
543 if (NodeCnt > ETnodes)
545 ElapsedTime(COMPUTE_MODE);
551 flag.musttimeout = false;
553 else if (TCflag || MaxResponseTime)
555 if ((et >= (ResponseTime + ExtraTime))
556 && (Sdepth > MINDEPTH))
558 /* try to extend to finish ply */
559 if (flag.back || (TCflag && TCcount < MAXTCCOUNTX))
562 flag.musttimeout = true;
570 flag.musttimeout = false;
578 flag.musttimeout = false;
581 #ifdef QUIETBACKGROUND
584 dsp->ShowResponseTime();
586 else if (!TCflag && flag.musttimeout && Sdepth > MINDEPTH)
589 flag.musttimeout = false;
596 score = evaluate(side, ply, alpha, beta,
597 INCscore, &in_check, &blockable);
600 * check for possible repitition if so call repitition - rpt is
604 if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
609 * repeat position >3 don't need to return score it's taken
626 /* score > SCORE_LIMIT its a draw or mate */
627 if (score > SCORE_LIMIT)
633 /* Do we need to add depth because of special conditions */
634 /* if in check or in capture sequence search deeper */
636 /***************** depth extensions *****************/
640 /* Allow opponent a chance to check again */
647 && (score > alpha) && (score < beta)
649 && CptrFlag[ply - 1] && CptrFlag[ply - 2])
668 timeout = flag.timeout;
672 || ((!timeout && (hung[side] > 1))
673 && (ply == Sdepth + 1))))
677 else if ((score <= beta)
678 && (((ply < Sdepth + 4) && (ply > 4))
681 && (ChkFlag[ply - 2] != ChkFlag[ply - 4])))
687 /***************************************************/
688 /* try the local transition table if it's there */
691 if (/* depth > 0 && */ flag.hash && ply > 1)
694 && ProbeTTable(side, depth, ply, &alpha, &beta, &score) == true)
697 bstline[ply + 1] = 0;
699 if (beta == -((SCORE_LIMIT + 1000) * 2))
707 /* ok try the transition file if its there */
709 && (depth > HashDepth)
710 && (GameCnt < HashMoveLimit)
711 && (ProbeFTable(side, depth, ply, &alpha, &beta, &score)
714 PutInTTable(side, score, depth, ply, beta, PV);
716 bstline[ply + 1] = 0;
718 if (beta == -((SCORE_LIMIT + 1000) * 2))
726 #endif /* HASHFILE */
730 if (TrPnt[ply] > (TREE - 300))
736 * If more then DepthBeyond ply past goal depth or at goal depth and
737 * score > beta quit - means we are out of the window.
740 if (mustcut || (ply > DepthBeyond) || ((depth < 1) && (score > beta)))
744 * If below first ply and not at goal depth generate all moves else
745 * only capture moves.
750 if ((depth > 0) || (ply < (SDEPTHLIM))
751 || (background && (ply < Sdepth + 2)))
752 MoveList(side, ply, in_check, blockable);
754 CaptureList(side, ply, in_check, blockable);
757 /* no moves return what we have */
760 * normally a search will continue til past goal and no more capture
764 /* unless it hits DepthBeyond */
765 if (TrPnt[ply] == TrPnt[ply + 1])
768 /* if not at goal set best = -inf else current score */
769 best = (depth > 0) ? -(SCORE_LIMIT + 3000) : score;
775 /* CHECKME: is the & really an && here? */
776 if (!null && /* no previous null-move */
777 !PVari && /* no null-move during the PV */
778 (ply > 2) & /* not at ply 1 */
781 !in_check) /* no check */
782 /* enough material such that zugzwang is unlikely
783 * but who knows which value is suitable? */
786 OK, we make a null move, i.e. this means we have nothing to do
787 but we have to keep the some arrays up to date otherwise gnushogi
788 gets confused. Maybe somebody knows exactly which information is
789 important and which isn't.
791 Another idea is that we try the null-move first and generate the
792 moves later. This may save time but we have to take care that
793 PV and other variables contain the right value so that the move
794 ordering works right.
799 nxtline[ply + 1] = 0;
806 g = &GameList[++GameCnt];
807 g->hashkey = hashkey;
809 FROMsquare = TOsquare = -1;
816 best = -search(xside, ply + 1, depth - 2,
817 -beta - 1, -beta, nxtline, &rcnt);
824 best = -(SCORE_LIMIT + 3000);
826 else if (best > beta)
832 best = -(SCORE_LIMIT + 3000);
837 /* if best so far is better than alpha set alpha to best */
841 /********************** main loop ****************************/
843 /* look at each move until no more or beta cutoff */
844 for (pnt = pbst = TrPnt[ply];
845 (pnt < TrPnt[ply + 1]) && (best <= beta);
848 /* find the most interesting looking of the remaining moves */
850 pick(pnt, TrPnt[ply + 1] - 1);
853 PVari = PVarisave && (pnt == TrPnt[ply]); /* Is this the PV? */
858 /* is this a forbidden move */
859 if (/* ply == 1 && */ node->score <= DONTUSE)
862 nxtline[ply + 1] = 0;
864 /* if at top level */
867 /* at the top update search status */
870 #ifdef QUIETBACKGROUND
872 #endif /* QUIETBACKGROUND */
873 dsp->ShowCurrentMove(pnt, node->f, node->t);
877 if (!(node->flags & exact))
879 /* make the move and go deeper */
881 MakeMove(side, node, &tempb, &tempc, &tempsf,
883 CptrFlag[ply] = ((node->flags & capture) != 0);
884 TesujiFlag[ply] = (node->flags & tesuji)
885 && (node->flags & dropmask);
886 Tscore[ply] = node->score;
889 node->score = -search(xside, ply + 1,
890 (depth > 0) ? (depth - 1) : 0,
896 * node->score = score;
899 node->width = ((ply % 2) == 1)
900 ? (TrPnt[ply + 2] - TrPnt[ply + 1])
903 if ((node->score > SCORE_LIMIT) || (node->score < -SCORE_LIMIT) )
904 node->flags |= exact;
909 || ((node->score == (SCORE_LIMIT + 999) - ply)
912 node->flags |= (draw | exact);
913 DRAW = DRAW_JUSTDRAW;
914 node->score = ((side == computer) ? contempt : -contempt);
917 node->reply = nxtline[ply + 1];
919 /* reset to try next move */
920 UnmakeMove(side, node, &tempb, &tempc, &tempsf, &tempst);
923 /* if best move so far */
924 /* CHECKME: flag.timeout isn't valid if no hard time limit */
926 && ((node->score > best)
927 || ((node->score == best) && (node->width > bestwidth))))
930 * All things being equal pick the denser part of the
933 bestwidth = node->width;
936 * If not at goal depth and better than alpha and not
937 * an exact score increment by depth.
940 if ((depth > 0) && (node->score > alpha)
941 && !(node->flags & exact))
943 node->score += depth;
952 /* update best line */
953 for (j = ply + 1; nxtline[j] > 0; j++)
954 bstline[j] = nxtline[j];
957 bstline[ply] = (node->f << 8) | node->t;
963 * If it's better than the root score make it the root.
965 if ((best > root->score)
966 || ((best == root->score)
967 && (bestwidth > root->width)))
971 for (j = pnt - 1; j >= 0; j--)
972 Tree[j + 1] = Tree[j];
978 #ifdef QUIETBACKGROUND
981 #endif /* QUIETBACKGROUND */
986 dsp->ShowResults(best, bstline, '+');
988 else if (best < alpha)
990 dsp->ShowResults(best, bstline, '-');
994 dsp->ShowResults(best, bstline, '&');
997 #ifdef QUIETBACKGROUND
1004 return Tscore[ply - 1];
1007 /******************************************************/
1010 mv = (node->f << 8) | node->t;
1017 * We have a move so put it in local table - if it's already there
1018 * done else if not there or needs to be updated also put it in
1023 if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
1025 # ifdef HASHFILE /* MCV: warning: this confuses the formatter. */
1027 && PutInTTable(side, best, depth, ply, beta, mv)
1029 && (depth > HashDepth)
1030 && (GameCnt < HashMoveLimit))
1033 && PutInTTable(side, best, depth, ply, beta, mv))
1036 PutInFTable(side, best, depth, ply,
1037 alpha, beta, node->f, node->t);
1045 unsigned short h, x;
1048 if (history[x = hindex(side, h)] < HISTORYLIM)
1049 history[x] += (unsigned short) 1 << depth;
1052 if (node->t != (short)(GameList[GameCnt].gmove & 0xFF))
1058 else if (mv != killr1[ply])
1060 killr2[ply] = killr1[ply];
1065 killr0[ply] = ((best > SCORE_LIMIT) ? mv : 0);
1074 * Update the PieceList and Pindex arrays when a piece is captured or when a
1075 * capture is unmade.
1079 UpdatePieceList(short side, short sq, UpdatePieceList_mode iop)
1083 if (iop == REMOVE_PIECE)
1087 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1089 PieceList[side][i] = PieceList[side][i + 1];
1090 Pindex[PieceList[side][i]] = i;
1093 else if (board[sq] == king)
1095 /* king must have index 0 */
1096 for (i = PieceCnt[side]; i >= 0; i--)
1098 PieceList[side][i + 1] = PieceList[side][i];
1099 Pindex[PieceList[side][i + 1]] = i + 1;
1103 PieceList[side][0] = sq;
1109 PieceList[side][PieceCnt[side]] = sq;
1110 Pindex[sq] = PieceCnt[side];
1116 /* Make or Unmake drop move. */
1119 drop(short side, short piece, short t, short iop)
1127 #if !defined SAVE_SVALUE
1131 n = Captured[side][piece]--;
1133 UpdateDropHashbd(side, piece, n);
1134 UpdateHashbd(side, piece, -1, t);
1135 UpdatePieceList(side, t, ADD_PIECE);
1139 ++PawnCnt[side][column(t)];
1143 HasPiece[side][piece]++;
1148 board[t] = no_piece;
1150 n = ++Captured[side][piece];
1152 UpdateDropHashbd(side, piece, n);
1153 UpdateHashbd(side, piece, -1, t);
1154 UpdatePieceList(side, t, REMOVE_PIECE);
1157 --PawnCnt[side][column(t)];
1160 HasPiece[side][piece]--;
1169 unsigned long chashkey, chashbd;
1171 chashbd = chashkey = 0;
1173 for (sq = 0; sq < NO_SQUARES; sq++)
1175 if (color[sq] != neutral)
1177 chashbd ^= (*hashcode)[color[sq]][board[sq]][sq].bd;
1178 chashkey ^= (*hashcode)[color[sq]][board[sq]][sq].key;
1181 /* hashcodes for initial board are 0 ! */
1182 if (Stcolor[sq] != neutral)
1184 chashbd ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].bd;
1185 chashkey ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].key;
1189 for (side = 0; side <= 1; side++)
1193 for (piece = 0; piece < NO_PIECES; piece++)
1195 short n = Captured[side][piece];
1201 for (i = 1; i <= n; i++)
1203 chashbd ^= (*drop_hashcode)[side][piece][i].bd;
1204 chashkey ^= (*drop_hashcode)[side][piece][i].key;
1210 if (chashbd != hashbd)
1211 printf("chashbd %lu != hashbd %lu\n", chashbd, hashbd);
1213 if (chashkey != hashkey)
1214 printf("chashkey %lu != hashkey %lu\n", chashkey, hashkey);
1216 if (chashbd != hashbd || chashkey != hashkey)
1227 * Update Arrays board[], color[], and Pindex[] to reflect the new board
1228 * position obtained after making the move pointed to by node. Also update
1229 * miscellaneous stuff that changes when a move is made.
1233 MakeMove(short side,
1235 short *tempb, /* piece at to square */
1236 short *tempc, /* color of to square */
1237 short *tempsf, /* static value of piece on from */
1238 short *tempst, /* static value of piece on to */
1239 short *INCscore) /* score increment */
1246 g = &GameList[++GameCnt];
1247 g->hashkey = hashkey;
1249 FROMsquare = f = node->f;
1250 TOsquare = t = (node->t & 0x7f);
1251 *INCscore = (short)node->INCscore;
1253 g->gmove = (f << 8) | node->t;
1254 g->flags = node->flags;
1260 algbr(f, t, node->flags);
1261 printf("error before MakeMove: %s\n", mvstr[0]);
1262 UpdateDisplay(0, 0, 1, 0);
1264 for (i = 1; i <= GameCnt; i++)
1266 movealgbr(GameList[i].gmove, mvstr[0]);
1267 printf("%d: %s\n", i, mvstr[0]);
1274 rpthash[side][hashkey & 0xFF]++, ISZERO++;
1278 g->fpiece = (node->flags & pmask);
1279 g->piece = *tempb = no_piece;
1280 g->color = *tempc = neutral;
1282 #if !defined SAVE_SVALUE
1284 *tempst = svalue[t];
1287 (void)drop(side, g->fpiece, t, 1);
1291 #if !defined SAVE_SVALUE
1292 *tempsf = svalue[f];
1293 *tempst = svalue[t];
1296 g->fpiece = board[f];
1297 g->piece = *tempb = board[t];
1298 g->color = *tempc = color[t];
1302 if (*tempc != neutral)
1304 /* Capture a piece */
1305 UpdatePieceList(*tempc, t, REMOVE_PIECE);
1307 /* if capture decrement pawn count */
1309 --PawnCnt[*tempc][column(t)];
1311 mtl[xside] -= (*value)[stage][*tempb];
1312 HasPiece[xside][*tempb]--;
1315 short n, upiece = unpromoted[*tempb];
1317 /* add "upiece" captured by "side" */
1318 n = ++Captured[side][upiece];
1320 UpdateDropHashbd(side, upiece, n);
1321 mtl[side] += (*value)[stage][upiece];
1324 /* remove "*tempb" of "xside" from board[t] */
1325 UpdateHashbd(xside, *tempb, -1, t);
1327 #if !defined SAVE_SVALUE
1328 *INCscore += *tempst; /* add value of catched piece
1337 #if !defined SAVE_SVALUE
1338 svalue[t] = svalue[f];
1342 Pindex[t] = Pindex[f];
1343 PieceList[side][Pindex[t]] = t;
1345 board[f] = no_piece;
1347 if (node->flags & promote)
1351 board[t] = tob = promoted[fromb];
1353 /* remove unpromoted piece from board[f] */
1354 UpdateHashbd(side, fromb, f, -1);
1356 /* add promoted piece to board[t] */
1357 UpdateHashbd(side, tob, -1, t);
1358 mtl[side] += value[stage][tob] - value[stage][fromb];
1361 --PawnCnt[side][column(f)];
1363 HasPiece[side][fromb]--;
1364 HasPiece[side][tob]++;
1366 #if !defined SAVE_SVALUE
1367 *INCscore -= *tempsf;
1373 /* remove piece from board[f] and add it to board[t] */
1374 UpdateHashbd(side, fromb, f, t);
1381 algbr(f, t, node->flags);
1385 printf("error in MakeMove: %s\n", mvstr[0]);
1399 UnmakeMove(short side,
1411 Game50 = GameList[GameCnt].Game50;
1413 if (node->flags & dropmask)
1415 (void)drop(side, (node->flags & pmask), t, 2);
1417 #if !defined SAVE_SVALUE
1418 svalue[t] = *tempst;
1425 color[f] = color[t];
1426 board[f] = tob = fromb = board[t];
1428 #if !defined SAVE_SVALUE
1429 svalue[f] = *tempsf;
1432 Pindex[f] = Pindex[t];
1433 PieceList[side][Pindex[f]] = f;
1437 #if !defined SAVE_SVALUE
1438 svalue[t] = *tempst;
1442 if (node->flags & promote)
1444 board[f] = fromb = unpromoted[tob];
1445 mtl[side] += value[stage][fromb] - value[stage][tob];
1448 ++PawnCnt[side][column(f)];
1450 HasPiece[side][fromb]++;
1451 HasPiece[side][tob]--;
1453 /* add unpromoted piece to board[f] */
1454 UpdateHashbd(side, fromb, f, -1);
1456 /* remove promoted piece from board[t] */
1457 UpdateHashbd(side, tob, -1, t);
1463 --PawnCnt[side][column(t)];
1464 ++PawnCnt[side][column(f)];
1467 /* remove piece from board[t] and add it to board[f] */
1468 UpdateHashbd(side, fromb, f, t);
1472 if (*tempc != neutral)
1474 short n, upiece = unpromoted[*tempb];
1476 UpdatePieceList(*tempc, t, ADD_PIECE);
1479 ++PawnCnt[*tempc][column(t)];
1481 mtl[xside] += (*value)[stage][*tempb];
1482 HasPiece[xside][*tempb]++;
1483 mtl[side] -= (*value)[stage][upiece];
1485 /* remove "upiece" captured by "side" */
1486 n = Captured[side][upiece]--;
1488 UpdateDropHashbd(side, upiece, n);
1490 /* replace captured piece on board[t] */
1491 UpdateHashbd(xside, *tempb, -1, t);
1499 rpthash[side][hashkey & 0xFF]--, ISZERO--;
1502 algbr(f, t, node->flags);
1506 printf("error in UnmakeMove: %s\n", mvstr[0]);
1515 * Scan thru the board seeing what's on each square. If a piece is found,
1516 * update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1517 * determine the material for each side and set the hashkey and hashbd
1518 * variables to represent the current board position. Array
1519 * PieceList[side][indx] contains the location of all the pieces of either
1520 * side. Array Pindex[sq] contains the indx into PieceList for a given
1525 InitializeStats(void)
1529 for (i = 0; i < NO_COLS; i++)
1530 PawnCnt[black][i] = PawnCnt[white][i] = 0;
1532 mtl[black] = mtl[white] = 0;
1533 PieceCnt[black] = PieceCnt[white] = 0;
1534 hashbd = hashkey = 0;
1536 for (sq = 0; sq < NO_SQUARES; sq++)
1538 if (color[sq] != neutral)
1540 mtl[color[sq]] += (*value)[stage][board[sq]];
1542 if (board[sq] == pawn)
1543 ++PawnCnt[color[sq]][column(sq)];
1545 Pindex[sq] = ((board[sq] == king) ? 0 : ++PieceCnt[color[sq]]);
1546 PieceList[color[sq]][Pindex[sq]] = sq;
1547 UpdateHashbd(color[sq], board[sq], sq, -1);
1550 /* hashcodes for initial board are 0 ! */
1551 if (Stcolor[sq] != neutral)
1552 UpdateHashbd(Stcolor[sq], Stboard[sq], sq, -1);
1558 for (side = 0; side <= 1; side++)
1562 for (piece = 0; piece < NO_PIECES; piece++)
1564 short n = Captured[side][piece];
1568 Captured[side][piece] = 0;
1570 for (i = 1; i <= n; i++)
1572 ++Captured[side][piece];
1573 UpdateDropHashbd(side, piece, i);
1574 mtl[side] += (*value)[stage][piece];
1584 printf("error in InitializeStats\n");