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 * ----------------------------------------------------------------------
34 #if !defined OLDTIME && defined HAVE_GETTIMEOFDAY
35 double pow(double x, double y);
39 static short DepthBeyond;
40 unsigned short PrVar[MAXDEPTH];
41 extern short recycle, ISZERO;
42 extern void FlagString(unsigned short flags, char *s);
45 short null; /* Null-move already made or not */
46 short PVari; /* Is this the PV */
53 /* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
58 * Check for draw by fourfold repetition
59 * (same side, same captures, same board).
60 * WARNING: this is not save (sp? safe?) yet due to possible hash collisions.
71 if (GameCnt > Game50 + 6)
73 for (i = GameCnt - 1; i >= Game50; i -= 2)
77 if (g->hashkey == hashkey && g->hashbd == hashbd)
88 int plyscore, globalscore;
92 * Find the best move in the tree between indexes p1 and p2. Swap the best
93 * move into the p1 element.
97 pick(short p1, short p2)
99 struct leaf *p, *q, *r, *k;
107 for (r = p + 1; r <= q; r++)
127 int bookflag = false;
137 * Select a move by calling function search() at progressively deeper ply
138 * until time is up or a mate or draw is reached. An alpha-beta window of
139 * -Awindow to +Bwindow points is set around the score returned from the
140 * previous iteration. If Sdepth != 0 then the program has correctly
141 * predicted the opponents move and the search will start at a depth of
142 * Sdepth + 1 rather than a depth of 1.
146 SelectMove(short side, SelectMove_mode iop)
148 static short i, tempb, tempc, tempsf, tempst, xside, rpt;
149 static short alpha, beta, score;
150 static struct GameRec *g;
151 short sqking, in_check, blockable;
154 printf("hashbd = %ld (hashkey >> 16)|side = %d\n",
155 hashbd, (hashkey >> 16)|side);
158 flag.timeout = false;
160 flag.musttimeout = false;
165 recycle = (GameCnt % rehash) - rehash;
168 ExaminePosition(side);
170 /* if background mode set to infinite */
171 if (iop == BACKGROUND_MODE)
174 /* if background mode set response time to infinite */
175 ResponseTime = 9999999;
180 SetResponseTime(side);
183 #ifdef QUIETBACKGROUND
185 #endif /* QUIETBACKGROUND */
190 score = ScorePosition(side);
192 #ifdef QUIETBACKGROUND
194 #endif /* QUIETBACKGROUND */
197 #ifdef QUIETBACKGROUND
199 #endif /* QUIETBACKGROUND */
200 SearchStartStuff(side);
203 array_zero(history, sizeof_history);
206 FROMsquare = TOsquare = -1;
209 if (iop == FOREGROUND_MODE)
213 * If the last move was the hint, select the computed answer to the
214 * hint as first move to examine.
220 SwagHt = (GameList[GameCnt].gmove == PrVar[2]) ? PrVar[3] : 0;
227 for (i = 0; i < MAXDEPTH; i++)
228 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
230 /* set initial window for search */
234 alpha = -(SCORE_LIMIT + 999);
235 beta = SCORE_LIMIT + 999;
239 alpha = score - ((computer == white) ? BAwindow : WAwindow);
240 beta = score + ((computer == white) ? BBwindow : WBwindow);
247 sqking = PieceList[side][0];
248 in_check = (board[sqking] == king)
249 ? SqAttacked(sqking, side^1, &blockable)
252 MoveList(side, 1, in_check, blockable);
254 for (i = TrPnt[1]; i < TrPnt[2]; i++)
256 if (!pick(i, TrPnt[2] - 1))
260 /* Can I get a book move? */
262 if (flag.regularstart && Book)
264 flag.timeout = bookflag = OpeningBook(&hint, side);
267 ResponseTime += ResponseTime;
270 /* Zero stats for hash table. */
272 reminus = replus = 0;
273 GenCnt = NodeCnt = ETnodes = EvalNodes = HashCnt
274 = FHashAdd = HashAdd = FHashCnt = THashCol = HashCol = 0;
276 globalscore = plyscore = score;
281 /********************* main loop ********************************/
283 Sdepth = (MaxSearchDepth < (MINDEPTH - 1))
287 while (!flag.timeout)
289 /* go down a level at a time */
297 /* terminate search at DepthBeyond ply past goal depth */
299 DepthBeyond = Sdepth;
302 DepthBeyond = Sdepth + ((Sdepth == 1) ? 3 : 5);
304 DepthBeyond = Sdepth + ((Sdepth == 1) ? 7 : 11);
307 # ifdef QUIETBACKGROUND
309 #endif /* QUIETBACKGROUND */
312 /* search at this level returns score of PV */
313 score = search(side, 1, Sdepth, alpha, beta, PrVar, &rpt);
315 /* save PV as killer */
316 for (i = 1; i <= Sdepth; i++)
317 killr0[i] = PrVar[i];
319 /* low search failure re-search with (-inf, score) limits */
323 #ifdef QUIETBACKGROUND
325 #endif /* QUIETBACKGROUND */
328 if (TCflag && TCcount < MAXTCCOUNTR)
331 ExtraTime += (MAXTCCOUNTR - TCcount) * TCleft;
333 ExtraTime += (8 * TCleft);
335 TCcount = MAXTCCOUNTR - 1;
338 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
339 (SCORE_LIMIT + 999), PrVar, &rpt);
341 /* high search failure re-search with (score, +inf) limits */
342 else if (score > beta && !(root->flags & exact))
345 #ifdef QUIETBACKGROUND
347 #endif /* QUIETBACKGROUND */
350 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
351 (SCORE_LIMIT + 999), PrVar, &rpt);
354 /**************** out of search ***********************************/
355 CheckForTimeout(score, globalscore, Jscore, zwndw);
357 /************************ time control ****************************/
359 /* save PV as killer */
360 for (i = 1; i <= Sdepth + 1; i++)
361 killr0[i] = PrVar[i];
366 /* if (!flag.timeout) */
368 for (i = TrPnt[1] + 1; i < TrPnt[2]; i++)
369 if (!pick (i, TrPnt[2] - 1))
373 /* if done or nothing good to look at quit */
374 if ((root->flags & exact) || (score < -SCORE_LIMIT))
377 /* find the next best move put below root */
381 #if !defined NODYNALPHA
382 Jscore = (plyscore + score) >> 1;
384 zwndw = 20 + abs(Jscore / 12);
387 /* recompute search window */
388 beta = score + ((computer == white) ? BBwindow : WBwindow);
389 #if !defined NODYNALPHA
390 alpha = ((Jscore < score) ? Jscore : score)
391 - ((computer == white) ? BAwindow : WAwindow)
394 alpha = score - ((computer == white) ? BAwindow : WAwindow);
398 #ifdef QUIETBACKGROUND
400 #endif /* QUIETBACKGROUND */
401 ShowResults(score, PrVar, '.');
404 /********************** end of main loop ***************************/
406 /* background mode */
407 if (iop == BACKGROUND_MODE)
413 DRAW = CP[101]; /* Repetition */
418 * If there are no moves and we're not in check (stalemate) then
419 * it's mate in shogi (whereas it's a draw in chess).
422 if (GameCnt == MAXMOVES)
425 DRAW = CP[80]; /* Max Moves */
429 /* not in book so set hint to guessed move for other side */
431 hint = ((PrVar[1]) ? PrVar[2] : 0);
433 /* if not mate or draw make move and output it */
434 if (((score > -(SCORE_LIMIT + 999))
435 && (rpt <= 3)) || (root->flags & draw))
437 MakeMove(side, &Tree[0], &tempb, &tempc,
438 &tempsf, &tempst, &INCscore);
439 algbr(root->f, root->t, (short) root->flags);
443 algbr(0, 0, 0); /* Zero move string when mate. */
444 root->score = score; /* When mate, ignore distinctions!
448 g = &GameList[GameCnt];
450 if ((g->flags & capture) && (g->piece == king))
451 flag.mate = flag.illegal = true;
453 /* If Time Control get the elapsed time */
455 ElapsedTime(COMPUTE_AND_INIT_MODE);
457 /* update time control info */
460 /* if mate set flag */
461 if ((score == -(SCORE_LIMIT + 999) || score == (SCORE_LIMIT + 998)))
464 /* add move to game list */
467 g->time = (et +50)/100;
468 /* g->time = TCcount; */
471 /* update time control info */
474 TimeControl.clock[side] -= (et + OperatorTime);
475 timecomp[compptr] = (et + OperatorTime);
477 /* finished our required moves - setup the next set */
478 --TimeControl.moves[side];
481 /* check for end conditions */
482 if ((root->flags & draw) /* && flag.bothsides */)
486 else if (GameCnt == MAXMOVES)
490 /* out of move store, you lose */
493 /* switch to other side */
497 /* if mate clear hint */
507 * Perform an alpha-beta search to determine the score for the current
508 * board position. If depth <= 0 only capturing moves and responses to
509 * check are generated and searched, otherwise all moves are processed. The
510 * search depth is modified for check evasions, certain re-captures and
511 * threats. Extensions may continue for up to 11 ply beyond the nominal
521 unsigned short *bstline,
525 short tempb, tempc, tempsf, tempst;
526 short xside, pbst, score, rcnt, in_check, blockable;
527 unsigned short mv, nxtline[MAXDEPTH];
528 struct leaf *node, tmp;
529 short best = -(SCORE_LIMIT + 3000);
540 /* look every ZNODE nodes for a timeout */
545 if (NodeCnt > ETnodes)
547 ElapsedTime(COMPUTE_MODE);
553 flag.musttimeout = false;
555 else if (TCflag || MaxResponseTime)
557 if ((et >= (ResponseTime + ExtraTime))
558 && (Sdepth > MINDEPTH))
560 /* try to extend to finish ply */
561 if (flag.back || (TCflag && TCcount < MAXTCCOUNTX))
564 flag.musttimeout = true;
572 flag.musttimeout = false;
580 flag.musttimeout = false;
583 #ifdef QUIETBACKGROUND
588 else if (!TCflag && flag.musttimeout && Sdepth > MINDEPTH)
591 flag.musttimeout = false;
598 score = evaluate(side, ply, alpha, beta,
599 INCscore, &in_check, &blockable);
602 * check for possible repitition if so call repitition - rpt is
606 if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
611 * repeat position >3 don't need to return score it's taken
628 /* score > SCORE_LIMIT its a draw or mate */
629 if (score > SCORE_LIMIT)
635 /* Do we need to add depth because of special conditions */
636 /* if in check or in capture sequence search deeper */
638 /***************** depth extensions *****************/
642 /* Allow opponent a chance to check again */
649 && (score > alpha) && (score < beta)
651 && CptrFlag[ply - 1] && CptrFlag[ply - 2])
670 timeout = flag.timeout;
674 || ((!timeout && (hung[side] > 1))
675 && (ply == Sdepth + 1))))
679 else if ((score <= beta)
680 && (((ply < Sdepth + 4) && (ply > 4))
683 && (ChkFlag[ply - 2] != ChkFlag[ply - 4])))
689 /***************************************************/
690 /* try the local transition table if it's there */
693 if (/* depth > 0 && */ flag.hash && ply > 1)
696 && ProbeTTable(side, depth, ply, &alpha, &beta, &score) == true)
699 bstline[ply + 1] = 0;
701 if (beta == -((SCORE_LIMIT + 1000) * 2))
709 /* ok try the transition file if its there */
711 && (depth > HashDepth)
712 && (GameCnt < HashMoveLimit)
713 && (ProbeFTable(side, depth, ply, &alpha, &beta, &score)
716 PutInTTable(side, score, depth, ply, alpha, beta, PV);
718 bstline[ply + 1] = 0;
720 if (beta == -((SCORE_LIMIT + 1000) * 2))
728 #endif /* HASHFILE */
732 if (TrPnt[ply] > (TREE - 300))
738 * If more then DepthBeyond ply past goal depth or at goal depth and
739 * score > beta quit - means we are out of the window.
742 if (mustcut || (ply > DepthBeyond) || ((depth < 1) && (score > beta)))
746 * If below first ply and not at goal depth generate all moves else
747 * only capture moves.
752 if ((depth > 0) || (ply < (SDEPTHLIM))
753 || (background && (ply < Sdepth + 2)))
754 MoveList(side, ply, in_check, blockable);
756 CaptureList(side, ply, in_check, blockable);
759 /* no moves return what we have */
762 * normally a search will continue til past goal and no more capture
766 /* unless it hits DepthBeyond */
767 if (TrPnt[ply] == TrPnt[ply + 1])
770 /* if not at goal set best = -inf else current score */
771 best = (depth > 0) ? -(SCORE_LIMIT + 3000) : score;
777 /* CHECKME: is the & really an && here? */
778 if (!null && /* no previous null-move */
779 !PVari && /* no null-move during the PV */
780 (ply > 2) & /* not at ply 1 */
783 !in_check) /* no check */
784 /* enough material such that zugzwang is unlikely
785 * but who knows which value is suitable? */
788 OK, we make a null move, i.e. this means we have nothing to do
789 but we have to keep the some arrays up to date otherwise gnushogi
790 gets confused. Maybe somebody knows exactly which information is
791 important and which isn't.
793 Another idea is that we try the null-move first and generate the
794 moves later. This may save time but we have to take care that
795 PV and other variables contain the right value so that the move
796 ordering works right.
801 nxtline[ply + 1] = 0;
808 g = &GameList[++GameCnt];
809 g->hashkey = hashkey;
811 FROMsquare = TOsquare = -1;
818 best = -search(xside, ply + 1, depth - 2,
819 -beta - 1, -beta, nxtline, &rcnt);
826 best = -(SCORE_LIMIT + 3000);
828 else if (best > beta)
834 best = -(SCORE_LIMIT + 3000);
839 /* if best so far is better than alpha set alpha to best */
843 /********************** main loop ****************************/
845 /* look at each move until no more or beta cutoff */
846 for (pnt = pbst = TrPnt[ply];
847 (pnt < TrPnt[ply + 1]) && (best <= beta);
850 /* find the most interesting looking of the remaining moves */
852 pick(pnt, TrPnt[ply + 1] - 1);
855 PVari = PVarisave && (pnt == TrPnt[ply]); /* Is this the PV? */
860 /* is this a forbidden move */
861 if (/* ply == 1 && */ node->score <= DONTUSE)
864 nxtline[ply + 1] = 0;
866 /* if at top level */
870 /* at the top update search status */
873 #ifdef QUIETBACKGROUND
875 #endif /* QUIETBACKGROUND */
876 ShowCurrentMove(pnt, node->f, node->t);
881 if (!(node->flags & exact))
883 /* make the move and go deeper */
885 MakeMove(side, node, &tempb, &tempc, &tempsf,
887 CptrFlag[ply] = ((node->flags & capture) != 0);
888 TesujiFlag[ply] = (node->flags & tesuji)
889 && (node->flags & dropmask);
890 Tscore[ply] = node->score;
893 node->score = -search(xside, ply + 1,
894 (depth > 0) ? (depth - 1) : 0,
900 * node->score = score;
903 node->width = ((ply % 2) == 1)
904 ? (TrPnt[ply + 2] - TrPnt[ply + 1])
907 if ((node->score > SCORE_LIMIT) || (node->score < -SCORE_LIMIT) )
908 node->flags |= exact;
913 || ((node->score == (SCORE_LIMIT + 999) - ply)
916 node->flags |= (draw | exact);
917 DRAW = CP[58]; /* Draw */
918 node->score = ((side == computer) ? contempt : -contempt);
921 node->reply = nxtline[ply + 1];
923 /* reset to try next move */
924 UnmakeMove(side, node, &tempb, &tempc, &tempsf, &tempst);
927 /* if best move so far */
928 /* CHECKME: flag.timeout isn't valid if no hard time limit */
930 && ((node->score > best)
931 || ((node->score == best) && (node->width > bestwidth))))
934 * All things being equal pick the denser part of the
937 bestwidth = node->width;
940 * If not at goal depth and better than alpha and not
941 * an exact score increment by depth.
944 if ((depth > 0) && (node->score > alpha)
945 && !(node->flags & exact))
947 node->score += depth;
956 /* update best line */
957 for (j = ply + 1; nxtline[j] > 0; j++)
958 bstline[j] = nxtline[j];
961 bstline[ply] = (node->f << 8) | node->t;
967 * If it's better than the root score make it the root.
969 if ((best > root->score)
970 || ((best == root->score)
971 && (bestwidth > root->width)))
975 for (j = pnt - 1; j >= 0; j--)
976 Tree[j + 1] = Tree[j];
982 #ifdef QUIETBACKGROUND
985 #endif /* QUIETBACKGROUND */
990 ShowResults(best, bstline, '+');
992 else if (best < alpha)
994 ShowResults(best, bstline, '-');
998 ShowResults (best, bstline, '&');
1001 #ifdef QUIETBACKGROUND
1008 return Tscore[ply - 1];
1011 /******************************************************/
1014 mv = (node->f << 8) | node->t;
1021 * We have a move so put it in local table - if it's already there
1022 * done else if not there or needs to be updated also put it in
1027 if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
1029 # ifdef HASHFILE /* MCV: warning: this confuses the formatter. */
1031 && PutInTTable(side, best, depth, ply, alpha, beta, mv)
1033 && (depth > HashDepth)
1034 && (GameCnt < HashMoveLimit))
1037 && PutInTTable(side, best, depth, ply, alpha, beta, mv))
1040 PutInFTable(side, best, depth, ply,
1041 alpha, beta, node->f, node->t);
1049 unsigned short h, x;
1052 if (history[x = hindex(side, h)] < HISTORYLIM)
1053 history[x] += (unsigned short) 1 << depth;
1056 if (node->t != (short)(GameList[GameCnt].gmove & 0xFF))
1062 else if (mv != killr1[ply])
1064 killr2[ply] = killr1[ply];
1069 killr0[ply] = ((best > SCORE_LIMIT) ? mv : 0);
1078 * Update the PieceList and Pindex arrays when a piece is captured or when a
1079 * capture is unmade.
1083 UpdatePieceList(short side, short sq, UpdatePieceList_mode iop)
1087 if (iop == REMOVE_PIECE)
1091 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1093 PieceList[side][i] = PieceList[side][i + 1];
1094 Pindex[PieceList[side][i]] = i;
1097 else if (board[sq] == king)
1099 /* king must have index 0 */
1100 for (i = PieceCnt[side]; i >= 0; i--)
1102 PieceList[side][i + 1] = PieceList[side][i];
1103 Pindex[PieceList[side][i + 1]] = i + 1;
1107 PieceList[side][0] = sq;
1113 PieceList[side][PieceCnt[side]] = sq;
1114 Pindex[sq] = PieceCnt[side];
1120 /* Make or Unmake drop move. */
1123 drop(short side, short piece, short f, short t, short iop)
1131 #if !defined SAVE_SVALUE
1135 n = Captured[side][piece]--;
1137 UpdateDropHashbd(side, piece, n);
1138 UpdateHashbd(side, piece, -1, t);
1139 UpdatePieceList(side, t, ADD_PIECE);
1143 ++PawnCnt[side][column(t)];
1147 HasPiece[side][piece]++;
1152 board[t] = no_piece;
1154 n = ++Captured[side][piece];
1156 UpdateDropHashbd(side, piece, n);
1157 UpdateHashbd(side, piece, -1, t);
1158 UpdatePieceList(side, t, REMOVE_PIECE);
1161 --PawnCnt[side][column(t)];
1164 HasPiece[side][piece]--;
1173 unsigned long chashkey, chashbd;
1175 chashbd = chashkey = 0;
1177 for (sq = 0; sq < NO_SQUARES; sq++)
1179 if (color[sq] != neutral)
1181 chashbd ^= (*hashcode)[color[sq]][board[sq]][sq].bd;
1182 chashkey ^= (*hashcode)[color[sq]][board[sq]][sq].key;
1185 /* hashcodes for initial board are 0 ! */
1186 if (Stcolor[sq] != neutral)
1188 chashbd ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].bd;
1189 chashkey ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].key;
1193 for (side = 0; side <= 1; side++)
1197 for (piece = 0; piece < NO_PIECES; piece++)
1199 short n = Captured[side][piece];
1205 for (i = 1; i <= n; i++)
1207 chashbd ^= (*drop_hashcode)[side][piece][i].bd;
1208 chashkey ^= (*drop_hashcode)[side][piece][i].key;
1214 if (chashbd != hashbd)
1215 printf("chashbd %lu != hashbd %lu\n", chashbd, hashbd);
1217 if (chashkey != hashkey)
1218 printf("chashkey %lu != hashkey %lu\n", chashkey, hashkey);
1220 if (chashbd != hashbd || chashkey != hashkey)
1231 * Update Arrays board[], color[], and Pindex[] to reflect the new board
1232 * position obtained after making the move pointed to by node. Also update
1233 * miscellaneous stuff that changes when a move is made.
1237 MakeMove(short side,
1239 short *tempb, /* piece at to square */
1240 short *tempc, /* color of to square */
1241 short *tempsf, /* static value of piece on from */
1242 short *tempst, /* static value of piece on to */
1243 short *INCscore) /* score increment */
1250 g = &GameList[++GameCnt];
1251 g->hashkey = hashkey;
1253 FROMsquare = f = node->f;
1254 TOsquare = t = (node->t & 0x7f);
1255 *INCscore = (short)node->INCscore;
1257 g->gmove = (f << 8) | node->t;
1258 g->flags = node->flags;
1264 algbr(f, t, node->flags);
1265 printf("error before MakeMove: %s\n", mvstr[0]);
1266 UpdateDisplay(0, 0, 1, 0);
1268 for (i = 1; i <= GameCnt; i++)
1270 movealgbr(GameList[i].gmove, mvstr[0]);
1271 printf("%d: %s\n", i, mvstr[0]);
1278 rpthash[side][hashkey & 0xFF]++, ISZERO++;
1282 g->fpiece = (node->flags & pmask);
1283 g->piece = *tempb = no_piece;
1284 g->color = *tempc = neutral;
1286 #if !defined SAVE_SVALUE
1288 *tempst = svalue[t];
1291 (void)drop(side, g->fpiece, f, t, 1);
1295 #if !defined SAVE_SVALUE
1296 *tempsf = svalue[f];
1297 *tempst = svalue[t];
1300 g->fpiece = board[f];
1301 g->piece = *tempb = board[t];
1302 g->color = *tempc = color[t];
1306 if (*tempc != neutral)
1308 /* Capture a piece */
1309 UpdatePieceList(*tempc, t, REMOVE_PIECE);
1311 /* if capture decrement pawn count */
1313 --PawnCnt[*tempc][column(t)];
1315 mtl[xside] -= (*value)[stage][*tempb];
1316 HasPiece[xside][*tempb]--;
1319 short n, upiece = unpromoted[*tempb];
1321 /* add "upiece" captured by "side" */
1322 n = ++Captured[side][upiece];
1324 UpdateDropHashbd(side, upiece, n);
1325 mtl[side] += (*value)[stage][upiece];
1328 /* remove "*tempb" of "xside" from board[t] */
1329 UpdateHashbd(xside, *tempb, -1, t);
1331 #if !defined SAVE_SVALUE
1332 *INCscore += *tempst; /* add value of catched piece
1341 #if !defined SAVE_SVALUE
1342 svalue[t] = svalue[f];
1346 Pindex[t] = Pindex[f];
1347 PieceList[side][Pindex[t]] = t;
1349 board[f] = no_piece;
1351 if (node->flags & promote)
1355 board[t] = tob = promoted[fromb];
1357 /* remove unpromoted piece from board[f] */
1358 UpdateHashbd(side, fromb, f, -1);
1360 /* add promoted piece to board[t] */
1361 UpdateHashbd(side, tob, -1, t);
1362 mtl[side] += value[stage][tob] - value[stage][fromb];
1365 --PawnCnt[side][column(f)];
1367 HasPiece[side][fromb]--;
1368 HasPiece[side][tob]++;
1370 #if !defined SAVE_SVALUE
1371 *INCscore -= *tempsf;
1377 /* remove piece from board[f] and add it to board[t] */
1378 UpdateHashbd(side, fromb, f, t);
1385 algbr(f, t, node->flags);
1389 printf("error in MakeMove: %s\n", mvstr[0]);
1403 UnmakeMove(short side,
1415 Game50 = GameList[GameCnt].Game50;
1417 if (node->flags & dropmask)
1419 (void)drop(side, (node->flags & pmask), f, t, 2);
1421 #if !defined SAVE_SVALUE
1422 svalue[t] = *tempst;
1429 color[f] = color[t];
1430 board[f] = tob = fromb = board[t];
1432 #if !defined SAVE_SVALUE
1433 svalue[f] = *tempsf;
1436 Pindex[f] = Pindex[t];
1437 PieceList[side][Pindex[f]] = f;
1441 #if !defined SAVE_SVALUE
1442 svalue[t] = *tempst;
1446 if (node->flags & promote)
1448 board[f] = fromb = unpromoted[tob];
1449 mtl[side] += value[stage][fromb] - value[stage][tob];
1452 ++PawnCnt[side][column(f)];
1454 HasPiece[side][fromb]++;
1455 HasPiece[side][tob]--;
1457 /* add unpromoted piece to board[f] */
1458 UpdateHashbd(side, fromb, f, -1);
1460 /* remove promoted piece from board[t] */
1461 UpdateHashbd(side, tob, -1, t);
1467 --PawnCnt[side][column(t)];
1468 ++PawnCnt[side][column(f)];
1471 /* remove piece from board[t] and add it to board[f] */
1472 UpdateHashbd(side, fromb, f, t);
1476 if (*tempc != neutral)
1478 short n, upiece = unpromoted[*tempb];
1480 UpdatePieceList(*tempc, t, ADD_PIECE);
1483 ++PawnCnt[*tempc][column(t)];
1485 mtl[xside] += (*value)[stage][*tempb];
1486 HasPiece[xside][*tempb]++;
1487 mtl[side] -= (*value)[stage][upiece];
1489 /* remove "upiece" captured by "side" */
1490 n = Captured[side][upiece]--;
1492 UpdateDropHashbd(side, upiece, n);
1494 /* replace captured piece on board[t] */
1495 UpdateHashbd(xside, *tempb, -1, t);
1503 rpthash[side][hashkey & 0xFF]--, ISZERO--;
1506 algbr(f, t, node->flags);
1510 printf("error in UnmakeMove: %s\n", mvstr[0]);
1519 * Scan thru the board seeing what's on each square. If a piece is found,
1520 * update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1521 * determine the material for each side and set the hashkey and hashbd
1522 * variables to represent the current board position. Array
1523 * PieceList[side][indx] contains the location of all the pieces of either
1524 * side. Array Pindex[sq] contains the indx into PieceList for a given
1529 InitializeStats(void)
1533 for (i = 0; i < NO_COLS; i++)
1534 PawnCnt[black][i] = PawnCnt[white][i] = 0;
1536 mtl[black] = mtl[white] = 0;
1537 PieceCnt[black] = PieceCnt[white] = 0;
1538 hashbd = hashkey = 0;
1540 for (sq = 0; sq < NO_SQUARES; sq++)
1542 if (color[sq] != neutral)
1544 mtl[color[sq]] += (*value)[stage][board[sq]];
1546 if (board[sq] == pawn)
1547 ++PawnCnt[color[sq]][column(sq)];
1549 Pindex[sq] = ((board[sq] == king) ? 0 : ++PieceCnt[color[sq]]);
1550 PieceList[color[sq]][Pindex[sq]] = sq;
1551 UpdateHashbd(color[sq], board[sq], sq, -1);
1554 /* hashcodes for initial board are 0 ! */
1555 if (Stcolor[sq] != neutral)
1556 UpdateHashbd(Stcolor[sq], Stboard[sq], sq, -1);
1562 for (side = 0; side <= 1; side++)
1566 for (piece = 0; piece < NO_PIECES; piece++)
1568 short n = Captured[side][piece];
1572 Captured[side][piece] = 0;
1574 for (i = 1; i <= n; i++)
1576 ++Captured[side][piece];
1577 UpdateDropHashbd(side, piece, i);
1578 mtl[side] += (*value)[stage][piece];
1588 printf("error in InitializeStats\n");