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 * ----------------------------------------------------------------------
36 #if !defined OLDTIME && defined HAVE_GETTIMEOFDAY
37 double pow(double x, double y);
41 static short DepthBeyond;
42 unsigned short PrVar[MAXDEPTH];
43 extern short recycle, ISZERO;
44 extern void FlagString(unsigned short flags, char *s);
47 short null; /* Null-move already made or not */
48 short PVari; /* Is this the PV */
55 /* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
60 * Check for draw by fourfold repetition
61 * (same side, same captures, same board).
62 * WARNING: this is not save (sp? safe?) yet due to possible hash collisions.
73 if (GameCnt > Game50 + 6)
75 for (i = GameCnt - 1; i >= Game50; i -= 2)
79 if (g->hashkey == hashkey && g->hashbd == hashbd)
90 int plyscore, globalscore;
94 * Find the best move in the tree between indexes p1 and p2. Swap the best
95 * move into the p1 element.
99 pick(short p1, short p2)
101 struct leaf *p, *q, *r, *k;
109 for (r = p + 1; r <= q; r++)
129 int bookflag = false;
139 * Select a move by calling function search() at progressively deeper ply
140 * until time is up or a mate or draw is reached. An alpha-beta window of
141 * -Awindow to +Bwindow points is set around the score returned from the
142 * previous iteration. If Sdepth != 0 then the program has correctly
143 * predicted the opponents move and the search will start at a depth of
144 * Sdepth + 1 rather than a depth of 1.
148 SelectMove(short side, SelectMove_mode iop)
150 static short i, tempb, tempc, tempsf, tempst, xside, rpt;
151 static short alpha, beta, score;
152 static struct GameRec *g;
153 short sqking, in_check, blockable;
156 printf("hashbd = %ld (hashkey >> 16)|side = %d\n",
157 hashbd, (hashkey >> 16)|side);
160 flag.timeout = false;
162 flag.musttimeout = false;
167 recycle = (GameCnt % rehash) - rehash;
170 ExaminePosition(side);
172 /* if background mode set to infinite */
173 if (iop == BACKGROUND_MODE)
176 /* if background mode set response time to infinite */
177 ResponseTime = 9999999;
181 background = false; /* [HGM] with ponder on we did not switch back to foreground mode??? */
183 SetResponseTime(side);
186 #ifdef QUIETBACKGROUND
188 #endif /* QUIETBACKGROUND */
193 score = ScorePosition(side);
195 #ifdef QUIETBACKGROUND
197 #endif /* QUIETBACKGROUND */
200 #ifdef QUIETBACKGROUND
202 #endif /* QUIETBACKGROUND */
203 SearchStartStuff(side);
206 array_zero(history, sizeof_history);
209 FROMsquare = TOsquare = -1;
212 if (iop == FOREGROUND_MODE)
216 * If the last move was the hint, select the computed answer to the
217 * hint as first move to examine.
223 SwagHt = (GameList[GameCnt].gmove == PrVar[2]) ? PrVar[3] : 0;
230 for (i = 0; i < MAXDEPTH; i++)
231 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
233 /* set initial window for search */
237 alpha = -(SCORE_LIMIT + 999);
238 beta = SCORE_LIMIT + 999;
242 alpha = score - ((computer == white) ? BAwindow : WAwindow);
243 beta = score + ((computer == white) ? BBwindow : WBwindow);
250 sqking = PieceList[side][0];
251 in_check = (board[sqking] == king)
252 ? SqAttacked(sqking, side^1, &blockable)
255 MoveList(side, 1, in_check, blockable);
257 for (i = TrPnt[1]; i < TrPnt[2]; i++)
259 if (!pick(i, TrPnt[2] - 1))
263 /* Can I get a book move? */
265 if (flag.regularstart && Book)
267 flag.timeout = bookflag = OpeningBook(&hint, side);
270 ResponseTime += ResponseTime;
273 /* Zero stats for hash table. */
275 reminus = replus = 0;
276 GenCnt = NodeCnt = ETnodes = EvalNodes = HashCnt
277 = FHashAdd = HashAdd = FHashCnt = THashCol = HashCol = 0;
279 globalscore = plyscore = score;
284 /********************* main loop ********************************/
286 Sdepth = (MaxSearchDepth < (MINDEPTH - 1))
290 while (!flag.timeout)
292 /* go down a level at a time */
300 /* terminate search at DepthBeyond ply past goal depth */
302 DepthBeyond = Sdepth;
305 DepthBeyond = Sdepth + ((Sdepth == 1) ? 3 : 5);
307 DepthBeyond = Sdepth + ((Sdepth == 1) ? 7 : 11);
310 # ifdef QUIETBACKGROUND
312 #endif /* QUIETBACKGROUND */
315 /* search at this level returns score of PV */
316 score = search(side, 1, Sdepth, alpha, beta, PrVar, &rpt);
318 /* save PV as killer */
319 for (i = 1; i <= Sdepth; i++)
320 killr0[i] = PrVar[i];
322 /* low search failure re-search with (-inf, score) limits */
326 #ifdef QUIETBACKGROUND
328 #endif /* QUIETBACKGROUND */
331 if (TCflag && TCcount < MAXTCCOUNTR)
334 ExtraTime += (MAXTCCOUNTR - TCcount) * TCleft;
336 ExtraTime += (8 * TCleft);
338 TCcount = MAXTCCOUNTR - 1;
341 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
342 (SCORE_LIMIT + 999), PrVar, &rpt);
344 /* high search failure re-search with (score, +inf) limits */
345 else if (score > beta && !(root->flags & exact))
348 #ifdef QUIETBACKGROUND
350 #endif /* QUIETBACKGROUND */
353 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
354 (SCORE_LIMIT + 999), PrVar, &rpt);
357 /**************** out of search ***********************************/
358 CheckForTimeout(score, globalscore, Jscore, zwndw);
360 /************************ time control ****************************/
362 /* save PV as killer */
363 for (i = 1; i <= Sdepth + 1; i++)
364 killr0[i] = PrVar[i];
369 /* if (!flag.timeout) */
371 for (i = TrPnt[1] + 1; i < TrPnt[2]; i++)
372 if (!pick (i, TrPnt[2] - 1))
376 /* if done or nothing good to look at quit */
377 if ((root->flags & exact) || (score < -SCORE_LIMIT))
380 /* find the next best move put below root */
384 #if !defined NODYNALPHA
385 Jscore = (plyscore + score) >> 1;
387 zwndw = 20 + abs(Jscore / 12);
390 /* recompute search window */
391 beta = score + ((computer == white) ? BBwindow : WBwindow);
392 #if !defined NODYNALPHA
393 alpha = ((Jscore < score) ? Jscore : score)
394 - ((computer == white) ? BAwindow : WAwindow)
397 alpha = score - ((computer == white) ? BAwindow : WAwindow);
401 #ifdef QUIETBACKGROUND
403 #endif /* QUIETBACKGROUND */
404 ShowResults(score, PrVar, '.');
407 /********************** end of main loop ***************************/
409 /* background mode */
410 if (iop == BACKGROUND_MODE)
416 DRAW = CP[101]; /* Repetition */
421 * If there are no moves and we're not in check (stalemate) then
422 * it's mate in shogi (whereas it's a draw in chess).
425 if (GameCnt == MAXMOVES)
428 DRAW = CP[80]; /* Max Moves */
432 /* not in book so set hint to guessed move for other side */
434 hint = ((PrVar[1]) ? PrVar[2] : 0);
436 /* if not mate or draw make move and output it */
437 if (((score > -(SCORE_LIMIT + 999))
438 && (rpt <= 3)) || (root->flags & draw))
440 MakeMove(side, &Tree[0], &tempb, &tempc,
441 &tempsf, &tempst, &INCscore);
442 algbr(root->f, root->t, (short) root->flags);
446 algbr(0, 0, 0); /* Zero move string when mate. */
447 root->score = score; /* When mate, ignore distinctions!
451 g = &GameList[GameCnt];
453 if ((g->flags & capture) && (g->piece == king))
454 flag.mate = flag.illegal = true;
456 /* If Time Control get the elapsed time */
458 ElapsedTime(COMPUTE_AND_INIT_MODE);
460 /* update time control info */
463 /* if mate set flag */
464 if ((score == -(SCORE_LIMIT + 999) || score == (SCORE_LIMIT + 998)))
467 /* add move to game list */
470 g->time = (et +50)/100;
471 /* g->time = TCcount; */
474 /* update time control info */
477 TimeControl.clock[side] -= (et + OperatorTime);
478 timecomp[compptr] = (et + OperatorTime);
480 /* finished our required moves - setup the next set */
481 --TimeControl.moves[side];
484 /* check for end conditions */
485 if ((root->flags & draw) /* && flag.bothsides */)
489 else if (GameCnt == MAXMOVES)
493 /* out of move store, you lose */
496 /* switch to other side */
500 /* if mate clear hint */
510 * Perform an alpha-beta search to determine the score for the current
511 * board position. If depth <= 0 only capturing moves and responses to
512 * check are generated and searched, otherwise all moves are processed. The
513 * search depth is modified for check evasions, certain re-captures and
514 * threats. Extensions may continue for up to 11 ply beyond the nominal
524 unsigned short *bstline,
528 short tempb, tempc, tempsf, tempst;
529 short xside, pbst, score, rcnt, in_check, blockable;
530 unsigned short mv, nxtline[MAXDEPTH];
531 struct leaf *node, tmp;
532 short best = -(SCORE_LIMIT + 3000);
535 static struct pollfd pollfds[1] = { /* [0] = */ { /* .fd = */ STDIN_FILENO,
536 /* .events = */ POLLIN } };
545 /* look every ZNODE nodes for a timeout */
550 if (NodeCnt > ETnodes)
552 ElapsedTime(COMPUTE_MODE);
555 int cnt = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 0);
557 perror("polling standard input");
560 if (cnt) { /* if anything to read, or error occured */
562 flag.back = true; /* previous: flag.timeout = true; */
563 flag.bothsides = false;
571 flag.musttimeout = false;
573 else if (TCflag || MaxResponseTime)
575 if ((et >= (ResponseTime + ExtraTime))
576 && (Sdepth > MINDEPTH))
578 /* try to extend to finish ply */
579 if (flag.back || (TCflag && TCcount < MAXTCCOUNTX))
582 flag.musttimeout = true;
590 flag.musttimeout = false;
598 flag.musttimeout = false;
601 #ifdef QUIETBACKGROUND
606 else if (!TCflag && flag.musttimeout && Sdepth > MINDEPTH)
609 flag.musttimeout = false;
616 score = evaluate(side, ply, alpha, beta,
617 INCscore, &in_check, &blockable);
620 * check for possible repitition if so call repitition - rpt is
624 if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
629 * repeat position >3 don't need to return score it's taken
646 /* score > SCORE_LIMIT its a draw or mate */
647 if (score > SCORE_LIMIT)
653 /* Do we need to add depth because of special conditions */
654 /* if in check or in capture sequence search deeper */
656 /***************** depth extensions *****************/
660 /* Allow opponent a chance to check again */
667 && (score > alpha) && (score < beta)
669 && CptrFlag[ply - 1] && CptrFlag[ply - 2])
688 timeout = flag.timeout;
692 || ((!timeout && (hung[side] > 1))
693 && (ply == Sdepth + 1))))
697 else if ((score <= beta)
698 && (((ply < Sdepth + 4) && (ply > 4))
701 && (ChkFlag[ply - 2] != ChkFlag[ply - 4])))
707 /***************************************************/
708 /* try the local transition table if it's there */
711 if (/* depth > 0 && */ flag.hash && ply > 1)
714 && ProbeTTable(side, depth, ply, &alpha, &beta, &score) == true)
717 bstline[ply + 1] = 0;
719 if (beta == -((SCORE_LIMIT + 1000) * 2))
727 /* ok try the transition file if its there */
729 && (depth > HashDepth)
730 && (GameCnt < HashMoveLimit)
731 && (ProbeFTable(side, depth, ply, &alpha, &beta, &score)
734 PutInTTable(side, score, depth, ply, alpha, beta, PV);
736 bstline[ply + 1] = 0;
738 if (beta == -((SCORE_LIMIT + 1000) * 2))
746 #endif /* HASHFILE */
750 if (TrPnt[ply] > (TREE - 300))
756 * If more then DepthBeyond ply past goal depth or at goal depth and
757 * score > beta quit - means we are out of the window.
760 if (mustcut || (ply > DepthBeyond) || ((depth < 1) && (score > beta)))
764 * If below first ply and not at goal depth generate all moves else
765 * only capture moves.
770 if ((depth > 0) || (ply < (SDEPTHLIM))
771 || (background && (ply < Sdepth + 2)))
772 MoveList(side, ply, in_check, blockable);
774 CaptureList(side, ply, in_check, blockable);
777 /* no moves return what we have */
780 * normally a search will continue til past goal and no more capture
784 /* unless it hits DepthBeyond */
785 if (TrPnt[ply] == TrPnt[ply + 1])
788 /* if not at goal set best = -inf else current score */
789 best = (depth > 0) ? -(SCORE_LIMIT + 3000) : score;
795 /* CHECKME: is the & really an && here? */
796 if (!null && /* no previous null-move */
797 !PVari && /* no null-move during the PV */
798 (ply > 2) & /* not at ply 1 */
801 !in_check) /* no check */
802 /* enough material such that zugzwang is unlikely
803 * but who knows which value is suitable? */
806 OK, we make a null move, i.e. this means we have nothing to do
807 but we have to keep the some arrays up to date otherwise gnushogi
808 gets confused. Maybe somebody knows exactly which information is
809 important and which isn't.
811 Another idea is that we try the null-move first and generate the
812 moves later. This may save time but we have to take care that
813 PV and other variables contain the right value so that the move
814 ordering works right.
819 nxtline[ply + 1] = 0;
826 g = &GameList[++GameCnt];
827 g->hashkey = hashkey;
829 FROMsquare = TOsquare = -1;
836 best = -search(xside, ply + 1, depth - 2,
837 -beta - 1, -beta, nxtline, &rcnt);
844 best = -(SCORE_LIMIT + 3000);
846 else if (best > beta)
852 best = -(SCORE_LIMIT + 3000);
857 /* if best so far is better than alpha set alpha to best */
861 /********************** main loop ****************************/
863 /* look at each move until no more or beta cutoff */
864 for (pnt = pbst = TrPnt[ply];
865 (pnt < TrPnt[ply + 1]) && (best <= beta);
868 /* find the most interesting looking of the remaining moves */
870 pick(pnt, TrPnt[ply + 1] - 1);
873 PVari = PVarisave && (pnt == TrPnt[ply]); /* Is this the PV? */
878 /* is this a forbidden move */
879 if (/* ply == 1 && */ node->score <= DONTUSE)
882 nxtline[ply + 1] = 0;
884 /* if at top level */
888 /* at the top update search status */
891 #ifdef QUIETBACKGROUND
893 #endif /* QUIETBACKGROUND */
894 ShowCurrentMove(pnt, node->f, node->t);
899 if (!(node->flags & exact))
901 /* make the move and go deeper */
903 MakeMove(side, node, &tempb, &tempc, &tempsf,
905 CptrFlag[ply] = ((node->flags & capture) != 0);
906 TesujiFlag[ply] = (node->flags & tesuji)
907 && (node->flags & dropmask);
908 Tscore[ply] = node->score;
911 node->score = -search(xside, ply + 1,
912 (depth > 0) ? (depth - 1) : 0,
918 * node->score = score;
921 node->width = ((ply % 2) == 1)
922 ? (TrPnt[ply + 2] - TrPnt[ply + 1])
925 if ((node->score > SCORE_LIMIT) || (node->score < -SCORE_LIMIT) )
926 node->flags |= exact;
931 || ((node->score == (SCORE_LIMIT + 999) - ply)
934 node->flags |= (draw | exact);
935 DRAW = CP[58]; /* Draw */
936 node->score = ((side == computer) ? contempt : -contempt);
939 node->reply = nxtline[ply + 1];
941 /* reset to try next move */
942 UnmakeMove(side, node, &tempb, &tempc, &tempsf, &tempst);
945 /* if best move so far */
946 /* CHECKME: flag.timeout isn't valid if no hard time limit */
948 && ((node->score > best)
949 || ((node->score == best) && (node->width > bestwidth))))
952 * All things being equal pick the denser part of the
955 bestwidth = node->width;
958 * If not at goal depth and better than alpha and not
959 * an exact score increment by depth.
962 if ((depth > 0) && (node->score > alpha)
963 && !(node->flags & exact))
965 node->score += depth;
974 /* update best line */
975 for (j = ply + 1; nxtline[j] > 0; j++)
976 bstline[j] = nxtline[j];
979 bstline[ply] = (node->f << 8) | node->t;
985 * If it's better than the root score make it the root.
987 if ((best > root->score)
988 || ((best == root->score)
989 && (bestwidth > root->width)))
993 for (j = pnt - 1; j >= 0; j--)
994 Tree[j + 1] = Tree[j];
1000 #ifdef QUIETBACKGROUND
1003 #endif /* QUIETBACKGROUND */
1008 ShowResults(best, bstline, '+');
1010 else if (best < alpha)
1012 ShowResults(best, bstline, '-');
1016 ShowResults (best, bstline, '&');
1019 #ifdef QUIETBACKGROUND
1026 return Tscore[ply - 1];
1029 /******************************************************/
1032 mv = (node->f << 8) | node->t;
1039 * We have a move so put it in local table - if it's already there
1040 * done else if not there or needs to be updated also put it in
1045 if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
1047 # ifdef HASHFILE /* MCV: warning: this confuses the formatter. */
1049 && PutInTTable(side, best, depth, ply, alpha, beta, mv)
1051 && (depth > HashDepth)
1052 && (GameCnt < HashMoveLimit))
1055 && PutInTTable(side, best, depth, ply, alpha, beta, mv))
1058 PutInFTable(side, best, depth, ply,
1059 alpha, beta, node->f, node->t);
1067 unsigned short h, x;
1070 if (history[x = hindex(side, h)] < HISTORYLIM)
1071 history[x] += (unsigned short) 1 << depth;
1074 if (node->t != (short)(GameList[GameCnt].gmove & 0xFF))
1080 else if (mv != killr1[ply])
1082 killr2[ply] = killr1[ply];
1087 killr0[ply] = ((best > SCORE_LIMIT) ? mv : 0);
1096 * Update the PieceList and Pindex arrays when a piece is captured or when a
1097 * capture is unmade.
1101 UpdatePieceList(short side, short sq, UpdatePieceList_mode iop)
1105 if (iop == REMOVE_PIECE)
1109 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1111 PieceList[side][i] = PieceList[side][i + 1];
1112 Pindex[PieceList[side][i]] = i;
1115 else if (board[sq] == king)
1117 /* king must have index 0 */
1118 for (i = PieceCnt[side]; i >= 0; i--)
1120 PieceList[side][i + 1] = PieceList[side][i];
1121 Pindex[PieceList[side][i + 1]] = i + 1;
1125 PieceList[side][0] = sq;
1131 PieceList[side][PieceCnt[side]] = sq;
1132 Pindex[sq] = PieceCnt[side];
1138 /* Make or Unmake drop move. */
1141 drop(short side, short piece, short f, short t, short iop)
1149 #if !defined SAVE_SVALUE
1153 n = Captured[side][piece]--;
1155 UpdateDropHashbd(side, piece, n);
1156 UpdateHashbd(side, piece, -1, t);
1157 UpdatePieceList(side, t, ADD_PIECE);
1161 ++PawnCnt[side][column(t)];
1165 HasPiece[side][piece]++;
1170 board[t] = no_piece;
1172 n = ++Captured[side][piece];
1174 UpdateDropHashbd(side, piece, n);
1175 UpdateHashbd(side, piece, -1, t);
1176 UpdatePieceList(side, t, REMOVE_PIECE);
1179 --PawnCnt[side][column(t)];
1182 HasPiece[side][piece]--;
1191 unsigned long chashkey, chashbd;
1193 chashbd = chashkey = 0;
1195 for (sq = 0; sq < NO_SQUARES; sq++)
1197 if (color[sq] != neutral)
1199 chashbd ^= (*hashcode)[color[sq]][board[sq]][sq].bd;
1200 chashkey ^= (*hashcode)[color[sq]][board[sq]][sq].key;
1203 /* hashcodes for initial board are 0 ! */
1204 if (Stcolor[sq] != neutral)
1206 chashbd ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].bd;
1207 chashkey ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].key;
1211 for (side = 0; side <= 1; side++)
1215 for (piece = 0; piece < NO_PIECES; piece++)
1217 short n = Captured[side][piece];
1223 for (i = 1; i <= n; i++)
1225 chashbd ^= (*drop_hashcode)[side][piece][i].bd;
1226 chashkey ^= (*drop_hashcode)[side][piece][i].key;
1232 if (chashbd != hashbd)
1233 printf("chashbd %lu != hashbd %lu\n", chashbd, hashbd);
1235 if (chashkey != hashkey)
1236 printf("chashkey %lu != hashkey %lu\n", chashkey, hashkey);
1238 if (chashbd != hashbd || chashkey != hashkey)
1249 * Update Arrays board[], color[], and Pindex[] to reflect the new board
1250 * position obtained after making the move pointed to by node. Also update
1251 * miscellaneous stuff that changes when a move is made.
1255 MakeMove(short side,
1257 short *tempb, /* piece at to square */
1258 short *tempc, /* color of to square */
1259 short *tempsf, /* static value of piece on from */
1260 short *tempst, /* static value of piece on to */
1261 short *INCscore) /* score increment */
1268 g = &GameList[++GameCnt];
1269 g->hashkey = hashkey;
1271 FROMsquare = f = node->f;
1272 TOsquare = t = (node->t & 0x7f);
1273 *INCscore = (short)node->INCscore;
1275 g->gmove = (f << 8) | node->t;
1276 g->flags = node->flags;
1282 algbr(f, t, node->flags);
1283 printf("error before MakeMove: %s\n", mvstr[0]);
1284 UpdateDisplay(0, 0, 1, 0);
1286 for (i = 1; i <= GameCnt; i++)
1288 movealgbr(GameList[i].gmove, mvstr[0]);
1289 printf("%d: %s\n", i, mvstr[0]);
1296 rpthash[side][hashkey & 0xFF]++, ISZERO++;
1300 g->fpiece = (node->flags & pmask);
1301 g->piece = *tempb = no_piece;
1302 g->color = *tempc = neutral;
1304 #if !defined SAVE_SVALUE
1306 *tempst = svalue[t];
1309 (void)drop(side, g->fpiece, f, t, 1);
1313 #if !defined SAVE_SVALUE
1314 *tempsf = svalue[f];
1315 *tempst = svalue[t];
1318 g->fpiece = board[f];
1319 g->piece = *tempb = board[t];
1320 g->color = *tempc = color[t];
1324 if (*tempc != neutral)
1326 /* Capture a piece */
1327 UpdatePieceList(*tempc, t, REMOVE_PIECE);
1329 /* if capture decrement pawn count */
1331 --PawnCnt[*tempc][column(t)];
1333 mtl[xside] -= (*value)[stage][*tempb];
1334 HasPiece[xside][*tempb]--;
1337 short n, upiece = unpromoted[*tempb];
1339 /* add "upiece" captured by "side" */
1340 n = ++Captured[side][upiece];
1342 UpdateDropHashbd(side, upiece, n);
1343 mtl[side] += (*value)[stage][upiece];
1346 /* remove "*tempb" of "xside" from board[t] */
1347 UpdateHashbd(xside, *tempb, -1, t);
1349 #if !defined SAVE_SVALUE
1350 *INCscore += *tempst; /* add value of catched piece
1359 #if !defined SAVE_SVALUE
1360 svalue[t] = svalue[f];
1364 Pindex[t] = Pindex[f];
1365 PieceList[side][Pindex[t]] = t;
1367 board[f] = no_piece;
1369 if (node->flags & promote)
1373 board[t] = tob = promoted[fromb];
1375 /* remove unpromoted piece from board[f] */
1376 UpdateHashbd(side, fromb, f, -1);
1378 /* add promoted piece to board[t] */
1379 UpdateHashbd(side, tob, -1, t);
1380 mtl[side] += value[stage][tob] - value[stage][fromb];
1383 --PawnCnt[side][column(f)];
1385 HasPiece[side][fromb]--;
1386 HasPiece[side][tob]++;
1388 #if !defined SAVE_SVALUE
1389 *INCscore -= *tempsf;
1395 /* remove piece from board[f] and add it to board[t] */
1396 UpdateHashbd(side, fromb, f, t);
1403 algbr(f, t, node->flags);
1407 printf("error in MakeMove: %s\n", mvstr[0]);
1421 UnmakeMove(short side,
1433 Game50 = GameList[GameCnt].Game50;
1435 if (node->flags & dropmask)
1437 (void)drop(side, (node->flags & pmask), f, t, 2);
1439 #if !defined SAVE_SVALUE
1440 svalue[t] = *tempst;
1447 color[f] = color[t];
1448 board[f] = tob = fromb = board[t];
1450 #if !defined SAVE_SVALUE
1451 svalue[f] = *tempsf;
1454 Pindex[f] = Pindex[t];
1455 PieceList[side][Pindex[f]] = f;
1459 #if !defined SAVE_SVALUE
1460 svalue[t] = *tempst;
1464 if (node->flags & promote)
1466 board[f] = fromb = unpromoted[tob];
1467 mtl[side] += value[stage][fromb] - value[stage][tob];
1470 ++PawnCnt[side][column(f)];
1472 HasPiece[side][fromb]++;
1473 HasPiece[side][tob]--;
1475 /* add unpromoted piece to board[f] */
1476 UpdateHashbd(side, fromb, f, -1);
1478 /* remove promoted piece from board[t] */
1479 UpdateHashbd(side, tob, -1, t);
1485 --PawnCnt[side][column(t)];
1486 ++PawnCnt[side][column(f)];
1489 /* remove piece from board[t] and add it to board[f] */
1490 UpdateHashbd(side, fromb, f, t);
1494 if (*tempc != neutral)
1496 short n, upiece = unpromoted[*tempb];
1498 UpdatePieceList(*tempc, t, ADD_PIECE);
1501 ++PawnCnt[*tempc][column(t)];
1503 mtl[xside] += (*value)[stage][*tempb];
1504 HasPiece[xside][*tempb]++;
1505 mtl[side] -= (*value)[stage][upiece];
1507 /* remove "upiece" captured by "side" */
1508 n = Captured[side][upiece]--;
1510 UpdateDropHashbd(side, upiece, n);
1512 /* replace captured piece on board[t] */
1513 UpdateHashbd(xside, *tempb, -1, t);
1521 rpthash[side][hashkey & 0xFF]--, ISZERO--;
1524 algbr(f, t, node->flags);
1528 printf("error in UnmakeMove: %s\n", mvstr[0]);
1537 * Scan thru the board seeing what's on each square. If a piece is found,
1538 * update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1539 * determine the material for each side and set the hashkey and hashbd
1540 * variables to represent the current board position. Array
1541 * PieceList[side][indx] contains the location of all the pieces of either
1542 * side. Array Pindex[sq] contains the indx into PieceList for a given
1547 InitializeStats(void)
1551 for (i = 0; i < NO_COLS; i++)
1552 PawnCnt[black][i] = PawnCnt[white][i] = 0;
1554 mtl[black] = mtl[white] = 0;
1555 PieceCnt[black] = PieceCnt[white] = 0;
1556 hashbd = hashkey = 0;
1558 for (sq = 0; sq < NO_SQUARES; sq++)
1560 if (color[sq] != neutral)
1562 mtl[color[sq]] += (*value)[stage][board[sq]];
1564 if (board[sq] == pawn)
1565 ++PawnCnt[color[sq]][column(sq)];
1567 Pindex[sq] = ((board[sq] == king) ? 0 : ++PieceCnt[color[sq]]);
1568 PieceList[color[sq]][Pindex[sq]] = sq;
1569 UpdateHashbd(color[sq], board[sq], sq, -1);
1572 /* hashcodes for initial board are 0 ! */
1573 if (Stcolor[sq] != neutral)
1574 UpdateHashbd(Stcolor[sq], Stboard[sq], sq, -1);
1580 for (side = 0; side <= 1; side++)
1584 for (piece = 0; piece < NO_PIECES; piece++)
1586 short n = Captured[side][piece];
1590 Captured[side][piece] = 0;
1592 for (i = 1; i <= n; i++)
1594 ++Captured[side][piece];
1595 UpdateDropHashbd(side, piece, i);
1596 mtl[side] += (*value)[stage][piece];
1606 printf("error in InitializeStats\n");