4 * ----------------------------------------------------------------------
6 * Copyright (c) 2012 Free Software Foundation
8 * GNU SHOGI is based on GNU CHESS
10 * This file is part of GNU SHOGI.
12 * GNU Shogi is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 3 of the License,
15 * or (at your option) any later version.
17 * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * You should have received a copy of the GNU General Public License along
23 * with GNU Shogi; see the file COPYING. If not, see
24 * <http://www.gnu.org/licenses/>.
25 * ----------------------------------------------------------------------
31 #if !defined OLDTIME && defined HAVE_GETTIMEOFDAY
32 double pow(double x, double y);
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;
177 SetResponseTime(side);
180 #ifdef QUIETBACKGROUND
182 #endif /* QUIETBACKGROUND */
187 score = ScorePosition(side);
189 #ifdef QUIETBACKGROUND
191 #endif /* QUIETBACKGROUND */
194 #ifdef QUIETBACKGROUND
196 #endif /* QUIETBACKGROUND */
197 SearchStartStuff(side);
200 array_zero(history, sizeof_history);
203 FROMsquare = TOsquare = -1;
206 if (iop == FOREGROUND_MODE)
210 * If the last move was the hint, select the computed answer to the
211 * hint as first move to examine.
217 SwagHt = (GameList[GameCnt].gmove == PrVar[2]) ? PrVar[3] : 0;
224 for (i = 0; i < MAXDEPTH; i++)
225 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
227 /* set initial window for search */
231 alpha = -(SCORE_LIMIT + 999);
232 beta = SCORE_LIMIT + 999;
236 alpha = score - ((computer == white) ? BAwindow : WAwindow);
237 beta = score + ((computer == white) ? BBwindow : WBwindow);
244 sqking = PieceList[side][0];
245 in_check = (board[sqking] == king)
246 ? SqAttacked(sqking, side^1, &blockable)
249 MoveList(side, 1, in_check, blockable);
251 for (i = TrPnt[1]; i < TrPnt[2]; i++)
253 if (!pick(i, TrPnt[2] - 1))
257 /* Can I get a book move? */
259 if (flag.regularstart && Book)
261 flag.timeout = bookflag = OpeningBook(&hint, side);
264 ResponseTime += ResponseTime;
267 /* Zero stats for hash table. */
269 reminus = replus = 0;
270 GenCnt = NodeCnt = ETnodes = EvalNodes = HashCnt
271 = FHashAdd = HashAdd = FHashCnt = THashCol = HashCol = 0;
273 globalscore = plyscore = score;
278 /********************* main loop ********************************/
280 Sdepth = (MaxSearchDepth < (MINDEPTH - 1))
284 while (!flag.timeout)
286 /* go down a level at a time */
294 /* terminate search at DepthBeyond ply past goal depth */
296 DepthBeyond = Sdepth;
299 DepthBeyond = Sdepth + ((Sdepth == 1) ? 3 : 5);
301 DepthBeyond = Sdepth + ((Sdepth == 1) ? 7 : 11);
304 # ifdef QUIETBACKGROUND
306 #endif /* QUIETBACKGROUND */
309 /* search at this level returns score of PV */
310 score = search(side, 1, Sdepth, alpha, beta, PrVar, &rpt);
312 /* save PV as killer */
313 for (i = 1; i <= Sdepth; i++)
314 killr0[i] = PrVar[i];
316 /* low search failure re-search with (-inf, score) limits */
320 #ifdef QUIETBACKGROUND
322 #endif /* QUIETBACKGROUND */
325 if (TCflag && TCcount < MAXTCCOUNTR)
328 ExtraTime += (MAXTCCOUNTR - TCcount) * TCleft;
330 ExtraTime += (8 * TCleft);
332 TCcount = MAXTCCOUNTR - 1;
335 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
336 (SCORE_LIMIT + 999), PrVar, &rpt);
338 /* high search failure re-search with (score, +inf) limits */
339 else if (score > beta && !(root->flags & exact))
342 #ifdef QUIETBACKGROUND
344 #endif /* QUIETBACKGROUND */
347 score = search(side, 1, Sdepth, -(SCORE_LIMIT + 999),
348 (SCORE_LIMIT + 999), PrVar, &rpt);
351 /**************** out of search ***********************************/
352 CheckForTimeout(score, globalscore, Jscore, zwndw);
354 /************************ time control ****************************/
356 /* save PV as killer */
357 for (i = 1; i <= Sdepth + 1; i++)
358 killr0[i] = PrVar[i];
363 /* if (!flag.timeout) */
365 for (i = TrPnt[1] + 1; i < TrPnt[2]; i++)
366 if (!pick (i, TrPnt[2] - 1))
370 /* if done or nothing good to look at quit */
371 if ((root->flags & exact) || (score < -SCORE_LIMIT))
374 /* find the next best move put below root */
378 #if !defined NODYNALPHA
379 Jscore = (plyscore + score) >> 1;
381 zwndw = 20 + abs(Jscore / 12);
384 /* recompute search window */
385 beta = score + ((computer == white) ? BBwindow : WBwindow);
386 #if !defined NODYNALPHA
387 alpha = ((Jscore < score) ? Jscore : score)
388 - ((computer == white) ? BAwindow : WAwindow)
391 alpha = score - ((computer == white) ? BAwindow : WAwindow);
395 #ifdef QUIETBACKGROUND
397 #endif /* QUIETBACKGROUND */
398 ShowResults(score, PrVar, '.');
401 /********************** end of main loop ***************************/
403 /* background mode */
404 if (iop == BACKGROUND_MODE)
410 DRAW = CP[101]; /* Repetition */
415 * If there are no moves and we're not in check (stalemate) then
416 * it's mate in shogi (whereas it's a draw in chess).
419 if (GameCnt == MAXMOVES)
422 DRAW = CP[80]; /* Max Moves */
426 /* not in book so set hint to guessed move for other side */
428 hint = ((PrVar[1]) ? PrVar[2] : 0);
430 /* if not mate or draw make move and output it */
431 if (((score > -(SCORE_LIMIT + 999))
432 && (rpt <= 3)) || (root->flags & draw))
434 MakeMove(side, &Tree[0], &tempb, &tempc,
435 &tempsf, &tempst, &INCscore);
436 algbr(root->f, root->t, (short) root->flags);
440 algbr(0, 0, 0); /* Zero move string when mate. */
441 root->score = score; /* When mate, ignore distinctions!
445 g = &GameList[GameCnt];
447 if ((g->flags & capture) && (g->piece == king))
448 flag.mate = flag.illegal = true;
450 /* If Time Control get the elapsed time */
452 ElapsedTime(COMPUTE_AND_INIT_MODE);
454 /* update time control info */
457 /* if mate set flag */
458 if ((score == -(SCORE_LIMIT + 999) || score == (SCORE_LIMIT + 998)))
461 /* add move to game list */
464 g->time = (et +50)/100;
465 /* g->time = TCcount; */
468 /* update time control info */
471 TimeControl.clock[side] -= (et + OperatorTime);
472 timecomp[compptr] = (et + OperatorTime);
474 /* finished our required moves - setup the next set */
475 --TimeControl.moves[side];
478 /* check for end conditions */
479 if ((root->flags & draw) /* && flag.bothsides */)
483 else if (GameCnt == MAXMOVES)
487 /* out of move store, you lose */
490 /* switch to other side */
494 /* if mate clear hint */
504 * Perform an alpha-beta search to determine the score for the current
505 * board position. If depth <= 0 only capturing moves and responses to
506 * check are generated and searched, otherwise all moves are processed. The
507 * search depth is modified for check evasions, certain re-captures and
508 * threats. Extensions may continue for up to 11 ply beyond the nominal
518 unsigned short *bstline,
522 short tempb, tempc, tempsf, tempst;
523 short xside, pbst, score, rcnt, in_check, blockable;
524 unsigned short mv, nxtline[MAXDEPTH];
525 struct leaf *node, tmp;
526 short best = -(SCORE_LIMIT + 3000);
537 /* look every ZNODE nodes for a timeout */
542 if (NodeCnt > ETnodes)
544 ElapsedTime(COMPUTE_MODE);
550 flag.musttimeout = false;
552 else if (TCflag || MaxResponseTime)
554 if ((et >= (ResponseTime + ExtraTime))
555 && (Sdepth > MINDEPTH))
557 /* try to extend to finish ply */
558 if (flag.back || (TCflag && TCcount < MAXTCCOUNTX))
561 flag.musttimeout = true;
569 flag.musttimeout = false;
577 flag.musttimeout = false;
580 #ifdef QUIETBACKGROUND
585 else if (!TCflag && flag.musttimeout && Sdepth > MINDEPTH)
588 flag.musttimeout = false;
595 score = evaluate(side, ply, alpha, beta,
596 INCscore, &in_check, &blockable);
599 * check for possible repitition if so call repitition - rpt is
603 if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
608 * repeat position >3 don't need to return score it's taken
625 /* score > SCORE_LIMIT its a draw or mate */
626 if (score > SCORE_LIMIT)
632 /* Do we need to add depth because of special conditions */
633 /* if in check or in capture sequence search deeper */
635 /***************** depth extensions *****************/
639 /* Allow opponent a chance to check again */
646 && (score > alpha) && (score < beta)
648 && CptrFlag[ply - 1] && CptrFlag[ply - 2])
667 timeout = flag.timeout;
671 || ((!timeout && (hung[side] > 1))
672 && (ply == Sdepth + 1))))
676 else if ((score <= beta)
677 && (((ply < Sdepth + 4) && (ply > 4))
680 && (ChkFlag[ply - 2] != ChkFlag[ply - 4])))
686 /***************************************************/
687 /* try the local transition table if it's there */
690 if (/* depth > 0 && */ flag.hash && ply > 1)
693 && ProbeTTable(side, depth, ply, &alpha, &beta, &score) == true)
696 bstline[ply + 1] = 0;
698 if (beta == -((SCORE_LIMIT + 1000) * 2))
706 /* ok try the transition file if its there */
708 && (depth > HashDepth)
709 && (GameCnt < HashMoveLimit)
710 && (ProbeFTable(side, depth, ply, &alpha, &beta, &score)
713 PutInTTable(side, score, depth, ply, alpha, beta, PV);
715 bstline[ply + 1] = 0;
717 if (beta == -((SCORE_LIMIT + 1000) * 2))
725 #endif /* HASHFILE */
729 if (TrPnt[ply] > (TREE - 300))
735 * If more then DepthBeyond ply past goal depth or at goal depth and
736 * score > beta quit - means we are out of the window.
739 if (mustcut || (ply > DepthBeyond) || ((depth < 1) && (score > beta)))
743 * If below first ply and not at goal depth generate all moves else
744 * only capture moves.
749 if ((depth > 0) || (ply < (SDEPTHLIM))
750 || (background && (ply < Sdepth + 2)))
751 MoveList(side, ply, in_check, blockable);
753 CaptureList(side, ply, in_check, blockable);
756 /* no moves return what we have */
759 * normally a search will continue til past goal and no more capture
763 /* unless it hits DepthBeyond */
764 if (TrPnt[ply] == TrPnt[ply + 1])
767 /* if not at goal set best = -inf else current score */
768 best = (depth > 0) ? -(SCORE_LIMIT + 3000) : score;
774 /* CHECKME: is the & really an && here? */
775 if (!null && /* no previous null-move */
776 !PVari && /* no null-move during the PV */
777 (ply > 2) & /* not at ply 1 */
780 !in_check) /* no check */
781 /* enough material such that zugzwang is unlikely
782 * but who knows which value is suitable? */
785 OK, we make a null move, i.e. this means we have nothing to do
786 but we have to keep the some arrays up to date otherwise gnushogi
787 gets confused. Maybe somebody knows exactly which information is
788 important and which isn't.
790 Another idea is that we try the null-move first and generate the
791 moves later. This may save time but we have to take care that
792 PV and other variables contain the right value so that the move
793 ordering works right.
798 nxtline[ply + 1] = 0;
805 g = &GameList[++GameCnt];
806 g->hashkey = hashkey;
808 FROMsquare = TOsquare = -1;
815 best = -search(xside, ply + 1, depth - 2,
816 -beta - 1, -beta, nxtline, &rcnt);
823 best = -(SCORE_LIMIT + 3000);
825 else if (best > beta)
831 best = -(SCORE_LIMIT + 3000);
836 /* if best so far is better than alpha set alpha to best */
840 /********************** main loop ****************************/
842 /* look at each move until no more or beta cutoff */
843 for (pnt = pbst = TrPnt[ply];
844 (pnt < TrPnt[ply + 1]) && (best <= beta);
847 /* find the most interesting looking of the remaining moves */
849 pick(pnt, TrPnt[ply + 1] - 1);
852 PVari = PVarisave && (pnt == TrPnt[ply]); /* Is this the PV? */
857 /* is this a forbidden move */
858 if (/* ply == 1 && */ node->score <= DONTUSE)
861 nxtline[ply + 1] = 0;
863 /* if at top level */
867 /* at the top update search status */
870 #ifdef QUIETBACKGROUND
872 #endif /* QUIETBACKGROUND */
873 ShowCurrentMove(pnt, node->f, node->t);
878 if (!(node->flags & exact))
880 /* make the move and go deeper */
882 MakeMove(side, node, &tempb, &tempc, &tempsf,
884 CptrFlag[ply] = ((node->flags & capture) != 0);
885 TesujiFlag[ply] = (node->flags & tesuji)
886 && (node->flags & dropmask);
887 Tscore[ply] = node->score;
890 node->score = -search(xside, ply + 1,
891 (depth > 0) ? (depth - 1) : 0,
897 * node->score = score;
900 node->width = ((ply % 2) == 1)
901 ? (TrPnt[ply + 2] - TrPnt[ply + 1])
904 if ((node->score > SCORE_LIMIT) || (node->score < -SCORE_LIMIT) )
905 node->flags |= exact;
910 || ((node->score == (SCORE_LIMIT + 999) - ply)
913 node->flags |= (draw | exact);
914 DRAW = CP[58]; /* Draw */
915 node->score = ((side == computer) ? contempt : -contempt);
918 node->reply = nxtline[ply + 1];
920 /* reset to try next move */
921 UnmakeMove(side, node, &tempb, &tempc, &tempsf, &tempst);
924 /* if best move so far */
925 /* CHECKME: flag.timeout isn't valid if no hard time limit */
927 && ((node->score > best)
928 || ((node->score == best) && (node->width > bestwidth))))
931 * All things being equal pick the denser part of the
934 bestwidth = node->width;
937 * If not at goal depth and better than alpha and not
938 * an exact score increment by depth.
941 if ((depth > 0) && (node->score > alpha)
942 && !(node->flags & exact))
944 node->score += depth;
953 /* update best line */
954 for (j = ply + 1; nxtline[j] > 0; j++)
955 bstline[j] = nxtline[j];
958 bstline[ply] = (node->f << 8) | node->t;
964 * If it's better than the root score make it the root.
966 if ((best > root->score)
967 || ((best == root->score)
968 && (bestwidth > root->width)))
972 for (j = pnt - 1; j >= 0; j--)
973 Tree[j + 1] = Tree[j];
979 #ifdef QUIETBACKGROUND
982 #endif /* QUIETBACKGROUND */
987 ShowResults(best, bstline, '+');
989 else if (best < alpha)
991 ShowResults(best, bstline, '-');
995 ShowResults (best, bstline, '&');
998 #ifdef QUIETBACKGROUND
1005 return Tscore[ply - 1];
1008 /******************************************************/
1011 mv = (node->f << 8) | node->t;
1018 * We have a move so put it in local table - if it's already there
1019 * done else if not there or needs to be updated also put it in
1024 if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
1026 # ifdef HASHFILE /* MCV: warning: this confuses the formatter. */
1028 && PutInTTable(side, best, depth, ply, alpha, beta, mv)
1030 && (depth > HashDepth)
1031 && (GameCnt < HashMoveLimit))
1034 && PutInTTable(side, best, depth, ply, alpha, beta, mv))
1037 PutInFTable(side, best, depth, ply,
1038 alpha, beta, node->f, node->t);
1046 unsigned short h, x;
1049 if (history[x = hindex(side, h)] < HISTORYLIM)
1050 history[x] += (unsigned short) 1 << depth;
1053 if (node->t != (short)(GameList[GameCnt].gmove & 0xFF))
1059 else if (mv != killr1[ply])
1061 killr2[ply] = killr1[ply];
1066 killr0[ply] = ((best > SCORE_LIMIT) ? mv : 0);
1075 * Update the PieceList and Pindex arrays when a piece is captured or when a
1076 * capture is unmade.
1080 UpdatePieceList(short side, short sq, UpdatePieceList_mode iop)
1084 if (iop == REMOVE_PIECE)
1088 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1090 PieceList[side][i] = PieceList[side][i + 1];
1091 Pindex[PieceList[side][i]] = i;
1094 else if (board[sq] == king)
1096 /* king must have index 0 */
1097 for (i = PieceCnt[side]; i >= 0; i--)
1099 PieceList[side][i + 1] = PieceList[side][i];
1100 Pindex[PieceList[side][i + 1]] = i + 1;
1104 PieceList[side][0] = sq;
1110 PieceList[side][PieceCnt[side]] = sq;
1111 Pindex[sq] = PieceCnt[side];
1117 /* Make or Unmake drop move. */
1120 drop(short side, short piece, short f, short t, short iop)
1128 #if !defined SAVE_SVALUE
1132 n = Captured[side][piece]--;
1134 UpdateDropHashbd(side, piece, n);
1135 UpdateHashbd(side, piece, -1, t);
1136 UpdatePieceList(side, t, ADD_PIECE);
1140 ++PawnCnt[side][column(t)];
1144 HasPiece[side][piece]++;
1149 board[t] = no_piece;
1151 n = ++Captured[side][piece];
1153 UpdateDropHashbd(side, piece, n);
1154 UpdateHashbd(side, piece, -1, t);
1155 UpdatePieceList(side, t, REMOVE_PIECE);
1158 --PawnCnt[side][column(t)];
1161 HasPiece[side][piece]--;
1170 unsigned long chashkey, chashbd;
1172 chashbd = chashkey = 0;
1174 for (sq = 0; sq < NO_SQUARES; sq++)
1176 if (color[sq] != neutral)
1178 chashbd ^= (*hashcode)[color[sq]][board[sq]][sq].bd;
1179 chashkey ^= (*hashcode)[color[sq]][board[sq]][sq].key;
1182 /* hashcodes for initial board are 0 ! */
1183 if (Stcolor[sq] != neutral)
1185 chashbd ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].bd;
1186 chashkey ^= (*hashcode)[Stcolor[sq]][Stboard[sq]][sq].key;
1190 for (side = 0; side <= 1; side++)
1194 for (piece = 0; piece < NO_PIECES; piece++)
1196 short n = Captured[side][piece];
1202 for (i = 1; i <= n; i++)
1204 chashbd ^= (*drop_hashcode)[side][piece][i].bd;
1205 chashkey ^= (*drop_hashcode)[side][piece][i].key;
1211 if (chashbd != hashbd)
1212 printf("chashbd %lu != hashbd %lu\n", chashbd, hashbd);
1214 if (chashkey != hashkey)
1215 printf("chashkey %lu != hashkey %lu\n", chashkey, hashkey);
1217 if (chashbd != hashbd || chashkey != hashkey)
1228 * Update Arrays board[], color[], and Pindex[] to reflect the new board
1229 * position obtained after making the move pointed to by node. Also update
1230 * miscellaneous stuff that changes when a move is made.
1234 MakeMove(short side,
1236 short *tempb, /* piece at to square */
1237 short *tempc, /* color of to square */
1238 short *tempsf, /* static value of piece on from */
1239 short *tempst, /* static value of piece on to */
1240 short *INCscore) /* score increment */
1247 g = &GameList[++GameCnt];
1248 g->hashkey = hashkey;
1250 FROMsquare = f = node->f;
1251 TOsquare = t = (node->t & 0x7f);
1252 *INCscore = (short)node->INCscore;
1254 g->gmove = (f << 8) | node->t;
1255 g->flags = node->flags;
1261 algbr(f, t, node->flags);
1262 printf("error before MakeMove: %s\n", mvstr[0]);
1263 UpdateDisplay(0, 0, 1, 0);
1265 for (i = 1; i <= GameCnt; i++)
1267 movealgbr(GameList[i].gmove, mvstr[0]);
1268 printf("%d: %s\n", i, mvstr[0]);
1275 rpthash[side][hashkey & 0xFF]++, ISZERO++;
1279 g->fpiece = (node->flags & pmask);
1280 g->piece = *tempb = no_piece;
1281 g->color = *tempc = neutral;
1283 #if !defined SAVE_SVALUE
1285 *tempst = svalue[t];
1288 (void)drop(side, g->fpiece, f, t, 1);
1292 #if !defined SAVE_SVALUE
1293 *tempsf = svalue[f];
1294 *tempst = svalue[t];
1297 g->fpiece = board[f];
1298 g->piece = *tempb = board[t];
1299 g->color = *tempc = color[t];
1303 if (*tempc != neutral)
1305 /* Capture a piece */
1306 UpdatePieceList(*tempc, t, REMOVE_PIECE);
1308 /* if capture decrement pawn count */
1310 --PawnCnt[*tempc][column(t)];
1312 mtl[xside] -= (*value)[stage][*tempb];
1313 HasPiece[xside][*tempb]--;
1316 short n, upiece = unpromoted[*tempb];
1318 /* add "upiece" captured by "side" */
1319 n = ++Captured[side][upiece];
1321 UpdateDropHashbd(side, upiece, n);
1322 mtl[side] += (*value)[stage][upiece];
1325 /* remove "*tempb" of "xside" from board[t] */
1326 UpdateHashbd(xside, *tempb, -1, t);
1328 #if !defined SAVE_SVALUE
1329 *INCscore += *tempst; /* add value of catched piece
1338 #if !defined SAVE_SVALUE
1339 svalue[t] = svalue[f];
1343 Pindex[t] = Pindex[f];
1344 PieceList[side][Pindex[t]] = t;
1346 board[f] = no_piece;
1348 if (node->flags & promote)
1352 board[t] = tob = promoted[fromb];
1354 /* remove unpromoted piece from board[f] */
1355 UpdateHashbd(side, fromb, f, -1);
1357 /* add promoted piece to board[t] */
1358 UpdateHashbd(side, tob, -1, t);
1359 mtl[side] += value[stage][tob] - value[stage][fromb];
1362 --PawnCnt[side][column(f)];
1364 HasPiece[side][fromb]--;
1365 HasPiece[side][tob]++;
1367 #if !defined SAVE_SVALUE
1368 *INCscore -= *tempsf;
1374 /* remove piece from board[f] and add it to board[t] */
1375 UpdateHashbd(side, fromb, f, t);
1382 algbr(f, t, node->flags);
1386 printf("error in MakeMove: %s\n", mvstr[0]);
1400 UnmakeMove(short side,
1412 Game50 = GameList[GameCnt].Game50;
1414 if (node->flags & dropmask)
1416 (void)drop(side, (node->flags & pmask), f, t, 2);
1418 #if !defined SAVE_SVALUE
1419 svalue[t] = *tempst;
1426 color[f] = color[t];
1427 board[f] = tob = fromb = board[t];
1429 #if !defined SAVE_SVALUE
1430 svalue[f] = *tempsf;
1433 Pindex[f] = Pindex[t];
1434 PieceList[side][Pindex[f]] = f;
1438 #if !defined SAVE_SVALUE
1439 svalue[t] = *tempst;
1443 if (node->flags & promote)
1445 board[f] = fromb = unpromoted[tob];
1446 mtl[side] += value[stage][fromb] - value[stage][tob];
1449 ++PawnCnt[side][column(f)];
1451 HasPiece[side][fromb]++;
1452 HasPiece[side][tob]--;
1454 /* add unpromoted piece to board[f] */
1455 UpdateHashbd(side, fromb, f, -1);
1457 /* remove promoted piece from board[t] */
1458 UpdateHashbd(side, tob, -1, t);
1464 --PawnCnt[side][column(t)];
1465 ++PawnCnt[side][column(f)];
1468 /* remove piece from board[t] and add it to board[f] */
1469 UpdateHashbd(side, fromb, f, t);
1473 if (*tempc != neutral)
1475 short n, upiece = unpromoted[*tempb];
1477 UpdatePieceList(*tempc, t, ADD_PIECE);
1480 ++PawnCnt[*tempc][column(t)];
1482 mtl[xside] += (*value)[stage][*tempb];
1483 HasPiece[xside][*tempb]++;
1484 mtl[side] -= (*value)[stage][upiece];
1486 /* remove "upiece" captured by "side" */
1487 n = Captured[side][upiece]--;
1489 UpdateDropHashbd(side, upiece, n);
1491 /* replace captured piece on board[t] */
1492 UpdateHashbd(xside, *tempb, -1, t);
1500 rpthash[side][hashkey & 0xFF]--, ISZERO--;
1503 algbr(f, t, node->flags);
1507 printf("error in UnmakeMove: %s\n", mvstr[0]);
1516 * Scan thru the board seeing what's on each square. If a piece is found,
1517 * update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1518 * determine the material for each side and set the hashkey and hashbd
1519 * variables to represent the current board position. Array
1520 * PieceList[side][indx] contains the location of all the pieces of either
1521 * side. Array Pindex[sq] contains the indx into PieceList for a given
1526 InitializeStats(void)
1530 for (i = 0; i < NO_COLS; i++)
1531 PawnCnt[black][i] = PawnCnt[white][i] = 0;
1533 mtl[black] = mtl[white] = 0;
1534 PieceCnt[black] = PieceCnt[white] = 0;
1535 hashbd = hashkey = 0;
1537 for (sq = 0; sq < NO_SQUARES; sq++)
1539 if (color[sq] != neutral)
1541 mtl[color[sq]] += (*value)[stage][board[sq]];
1543 if (board[sq] == pawn)
1544 ++PawnCnt[color[sq]][column(sq)];
1546 Pindex[sq] = ((board[sq] == king) ? 0 : ++PieceCnt[color[sq]]);
1547 PieceList[color[sq]][Pindex[sq]] = sq;
1548 UpdateHashbd(color[sq], board[sq], sq, -1);
1551 /* hashcodes for initial board are 0 ! */
1552 if (Stcolor[sq] != neutral)
1553 UpdateHashbd(Stcolor[sq], Stboard[sq], sq, -1);
1559 for (side = 0; side <= 1; side++)
1563 for (piece = 0; piece < NO_PIECES; piece++)
1565 short n = Captured[side][piece];
1569 Captured[side][piece] = 0;
1571 for (i = 1; i <= n; i++)
1573 ++Captured[side][piece];
1574 UpdateDropHashbd(side, piece, i);
1575 mtl[side] += (*value)[stage][piece];
1585 printf("error in InitializeStats\n");