Merge branch 'maint'
[gnushogi.git] / gnushogi / genmove.c
blobd42c1d6cb8c19b8f7c9df0496da6c433dc48aebd
1 /*
2 * FILE: genmove.c
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
23 * for more details.
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 * ----------------------------------------------------------------------
32 #include "gnushogi.h"
34 /* #define DONTUSE_HEURISTIC */
36 short *TrP;
38 static struct leaf *node;
39 static short sqking, sqxking;
40 static short InCheck = false, GenerateAllMoves = false;
41 static short check_determined = false;
43 short deepsearchcut = true;
44 short tas = false, taxs = false, ssa = false;
46 short generate_move_flags = false;
50 * Ply limits for deep search cut. No moves or drops flagged with "stupid"
51 * are considered beyond ply BEYOND_STUPID. Only moves or drops flagged
52 * with "kingattack" are considered beyond ply BEYOND_KINGATTACK. No moves
53 * or drops flagged with "questionable" are considered beyond ply
54 * BEYOND_QUESTIONABLE. Only moves or drops flagged with "tesuji" are
55 * considered beyond ply BEYOND_TESUJI. No drops are considered beyond ply
56 * BEYOND_DROP. Exceptions: moves or drops that prevent check or give
57 * check are always considered.
60 #define BEYOND_STUPID 0
61 #define BEYOND_TIMEOUT 2
62 #define BEYOND_KINGATTACK 6
63 #define BEYOND_QUESTIONABLE 8
64 #define BEYOND_TESUJI 8
65 #define BEYOND_DROP 10
67 #ifdef DONTUSE_HEURISTIC
68 static short MaxNum[MAXDEPTH] =
70 -1, 40, 80, 20, 40, 10, 5, 5, 5, 5,
71 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
72 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
73 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
75 #endif
77 #ifdef HASHKEYTEST
78 extern int CheckHashKey();
79 extern char mvstr[4][6];
80 #endif
84 * Update Arrays board[] and color[] to reflect the new board
85 * position obtained after making the move pointed to by node.
88 inline static void
89 GenMakeMove(short side,
90 short f,
91 short t,
92 short *tempb, /* piece at to square */
93 short *tempc, /* color of to square */
94 short promote_piece)
96 short piece, upiece, n;
98 t = t & 0x7f;
100 if (f > NO_SQUARES)
102 piece = f - NO_SQUARES;
104 if (piece > NO_PIECES)
105 piece -= NO_PIECES;
107 board[t] = piece;
108 color[t] = side;
109 n = (Captured[side][piece])--;
110 UpdateDropHashbd(side, piece, n);
111 UpdateHashbd(side, piece, -1, t);
112 UpdatePieceList(side, t, ADD_PIECE);
114 else
116 *tempb = board[t];
117 *tempc = color[t];
119 if (*tempb != no_piece)
121 n = ++Captured[side][upiece = unpromoted[*tempb]];
122 UpdateDropHashbd(side, upiece, n);
123 UpdateHashbd(*tempc, *tempb, -1, t);
124 UpdatePieceList(*tempc, t, REMOVE_PIECE);
127 piece = board[f];
128 Pindex[t] = Pindex[f];
129 PieceList[side][Pindex[t]] = t;
130 color[f] = neutral;
131 board[f] = no_piece;
132 color[t] = side;
134 if (promote_piece)
136 UpdateHashbd(side, piece, f, -1);
137 board[t] = promoted[piece];
138 UpdateHashbd(side, board[t], -1, t);
140 else
142 board[t] = piece;
143 UpdateHashbd(side, piece, f, t);
147 #ifdef HASHKEYTEST
148 if (CheckHashKey())
150 algbr(f, t, 0);
151 printf("error in GenMakeMove: %s\n", mvstr[0]);
152 exit(1);
154 #endif
160 * Take back a move.
163 static void
164 GenUnmakeMove(short side,
165 short f,
166 short t,
167 short tempb,
168 short tempc,
169 short promote_piece)
171 short piece, upiece, n;
173 t = t & 0x7f;
175 if (f > NO_SQUARES)
177 piece = f - NO_SQUARES;
179 if (piece > NO_PIECES)
180 piece -= NO_PIECES;
182 board[t] = no_piece;
183 color[t] = neutral;
184 n = ++Captured[side][piece];
185 UpdateDropHashbd(side, piece, n);
186 UpdateHashbd(side, piece, -1, t);
187 UpdatePieceList(side, t, REMOVE_PIECE);
189 else
191 piece = board[t];
192 color[t] = tempc;
193 board[t] = tempb;
194 Pindex[f] = Pindex[t];
195 PieceList[side][Pindex[f]] = f;
197 if (tempb != no_piece)
199 /* FIXME: make this next line a bit more reasonable... */
200 n = (Captured[side][upiece = unpromoted[tempb]])--;
201 UpdateDropHashbd(side, upiece, n);
202 UpdateHashbd(tempc, tempb, -1, t);
203 UpdatePieceList(tempc, t, ADD_PIECE);
206 color[f] = side;
208 if (promote_piece)
210 UpdateHashbd(side, piece, -1, t);
211 board[f] = unpromoted[piece];
212 UpdateHashbd(side, board[f], f, -1);
214 else
216 board[f] = piece;
217 UpdateHashbd(side, piece, f, t);
221 #ifdef HASHKEYTEST
222 if (CheckHashKey())
224 algbr(f, t, 0);
225 printf("error in GenUnmakeMove: %s\n", mvstr[0]);
226 exit(1);
228 #endif
233 static void
234 gives_check_flag(unsigned short *flags, short side, short f, short t)
236 short tempb, tempc, blockable, promote_piece;
237 promote_piece = (*flags & promote) != 0;
238 GenMakeMove(side, f, t, &tempb, &tempc, promote_piece);
240 if (SqAttacked(sqxking, side, &blockable))
241 *flags |= check;
243 GenUnmakeMove(side, f, t, tempb, tempc, promote_piece);
247 inline static void
248 Link(short side,
249 short from, short to, unsigned short local_flag, short s)
251 if (*TrP == TREE)
253 dsp->ShowMessage("TREE overflow\n");
255 else
257 node->f = from;
258 node->t = (local_flag & promote) ? (to | 0x80) : to;
259 node->reply = 0;
260 node->flags = local_flag;
261 node->score = s;
262 node->INCscore = INCscore;
264 if (GenerateAllMoves)
266 /* FIXME: gimme a break! */
267 (*TrP)++, node++;
269 else if (InCheck)
271 /* only moves out of check */
272 short tempb, tempc, sq, threat, blockable, promote_piece;
273 promote_piece = (node->flags & promote) != 0;
274 GenMakeMove(side, node->f, node->t,
275 &tempb, &tempc, promote_piece);
276 sq = (from == sqking) ? to : sqking;
277 threat = SqAttacked(sq, side ^ 1, &blockable);
278 GenUnmakeMove(side, node->f, node->t,
279 tempb, tempc, promote_piece);
281 if (!threat)
283 /* FIXME! Gimme a break! */
284 (*TrP)++, node++;
287 else if (flag.tsume)
289 /* only moves that give check */
290 if (!(node->flags & check) && !check_determined)
292 /* determine check flag */
293 gives_check_flag(&node->flags, side, node->f, node->t);
296 if (node->flags & check)
298 /* FIXME! Gimme a break! */
299 (*TrP)++, node++;
302 else
304 /* FIXME! Gimme a break! */
305 (*TrP)++, node++;
311 inline int
312 PromotionPossible(short color, short f, short t, short p)
314 if (color == black)
316 if ((!InWhiteCamp(f)) && (!InWhiteCamp(t)))
317 return false;
319 else
321 if ((!InBlackCamp(f)) && (!InBlackCamp(t)))
322 return false;
325 /* FIXME: this can be simplified... */
326 switch (p)
328 case pawn:
329 #ifndef MINISHOGI
330 case lance:
331 case knight:
332 #endif
333 case silver:
334 case bishop:
335 case rook:
336 return true;
339 return false;
343 static inline int
344 NonPromotionPossible(short color,
345 short t, short p)
347 switch (p)
349 case pawn :
350 if (color == black)
352 return ((t < 72)
353 ? true
354 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
356 else
358 return ((t > 8)
359 ? true
360 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
363 #ifndef MINISHOGI
364 case lance:
365 if (color == black)
367 return ((t < 72)
368 ? true
369 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
371 else
373 return ((t > 8)
374 ? true
375 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
378 case knight:
379 if (color == black)
381 return ((t < 63)
382 ? true
383 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
385 else
387 return ((t > 17)
388 ? true
389 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
391 #endif
394 return true;
398 #if defined FIELDBONUS || defined DROPBONUS
400 /* bonus for possible next moves */
402 inline static short
403 field_bonus(short side, short piece,
404 short f, short t, unsigned short *local_flag)
406 short s, u, ptyp;
407 unsigned char *ppos, *pdir;
408 short c1, c2;
410 #ifdef SAVE_NEXTPOS
411 short d;
412 #endif
414 c1 = side;
415 c2 = side ^ 1;
416 s = 0;
417 check_determined = true;
419 ptyp = ptype[side][piece];
421 #ifdef SAVE_NEXTPOS
422 u = first_direction(ptyp, &d, t);
423 #else
424 ppos = (*nextpos[ptyp])[t];
425 pdir = (*nextdir[ptyp])[t];
426 u = ppos[t];
427 #endif
431 short coloru = color[u];
433 if (piece != king && GameCnt > 40)
435 if (distance(u, EnemyKing) <= 1)
437 /* can reach square near own king */
438 s += 2;
439 *local_flag |= kingattack;
441 else if (distance(u, OwnKing) <= 1)
443 /* can reach square near enemy king */
444 s++;
445 *local_flag |= kingattack;
449 if (coloru == side)
451 /* impossible next move */
452 #ifdef SAVE_NEXTPOS
453 u = next_direction(ptyp, &d, t);
454 #else
455 u = pdir[u];
456 #endif
458 else
460 /* possible next move */
461 if (PromotionPossible(side, t, u, piece))
463 /* possible promotion in next move */
464 if (piece == pawn)
466 s += 2;
467 #ifdef TESUJIBONUS
468 if (!InPromotionZone(side, t))
470 *local_flag |= tesuji; /* The dangling pawn */
471 s++;
473 #endif
475 else
477 s++;
481 if (coloru == neutral)
483 /* next move to an empty square */
484 if (u == FROMsquare)
486 /* opponent has just left this square */
487 s++;
490 #ifdef SAVE_NEXTPOS
491 u = next_position(ptyp, &d, t, u);
492 #else
493 u = ppos[u];
494 #endif
496 else
498 /* attack opponents piece */
499 #ifdef TESUJIBONUS
500 short boardu, upiece, rvupiece, rvuboard;
501 #endif
502 s++;
504 if (u == TOsquare) /* opponent has moved to TOsquare */
505 s++;
507 if ((boardu = board[u]) == king)
509 s += 20; INCscore -= 18;
510 *local_flag |= check; /* move threatens
511 * opponents king */
514 #ifdef TESUJIBONUS
515 upiece = unpromoted[piece];
516 rvupiece = relative_value[upiece];
517 rvuboard = relative_value[unpromoted[boardu]];
519 if ((upiece == pawn) && (Captured[side][pawn] > 1))
521 *local_flag |= tesuji; /* The joining pawn attack */
522 s++;
525 if (rvupiece <= rvuboard)
527 *local_flag |= tesuji; /* The striking pawn
528 * (piece) attack */
530 if (f > NO_SQUARES)
531 s += 2;
532 else
533 s++;
535 if (upiece == pawn)
536 s++;
538 /* CHECKME: is this right? */
539 if (((rvupiece == rvuboard) && (upiece == pawn))
540 || (upiece == bishop)
541 #ifndef MINISHOGI
542 || (upiece == knight)
543 #endif
546 s++; /* The opposing pawn (piece) */
548 if (upiece == pawn)
549 s++;
552 #endif
554 #ifdef SAVE_NEXTPOS
555 u = next_direction(ptyp, &d, t);
556 #else
557 u = pdir[u];
558 #endif
562 while (u != t);
564 INCscore += s;
566 return s;
569 #endif
575 * Add a move to the tree. Assign a bonus to order the moves as follows:
576 * 1. Principle variation 2. Capture of last moved piece 3. Other captures
577 * (major pieces first) 4. Killer moves 5. Tesuji drops 6. Other Moves
578 * 7. Other drops. 8. Non-promoting moves
579 * If the flag.tsume is set, assign a high bonus for checks.
582 /* inline */ void
583 LinkMove(short ply, short f,
584 short t,
585 unsigned short local_flag,
586 short xside,
587 short score_if_impossible)
589 short s = 0;
590 short side, piece, mv;
591 short flag_tsume, try_link = true;
592 short c1, c2, ds, is_drop = f > NO_SQUARES;
593 unsigned long as = 0;
595 flag_tsume = flag.tsume;
597 c1 = side = xside ^ 1;
598 c2 = xside;
601 * Is it determined whether the move gives check ?
604 check_determined = ((local_flag & check) != 0);
606 mv = (f << 8) | ((local_flag & promote) ? (t | 0x80) : t);
608 if (f > NO_SQUARES)
610 piece = f - NO_SQUARES;
612 if (piece > NO_PIECES)
613 piece -= NO_PIECES;
615 else
617 piece = board[f];
620 if (score_if_impossible < 0)
622 /* The move is flagged as illegal. */
623 Link(side,
624 f, t, local_flag, score_if_impossible);
626 return;
629 INCscore = 0;
631 #ifdef HISTORY
632 s += history[hindex(side, mv)];
633 #endif
635 /* If we're running short of tree nodes, go into tsume mode. */
637 if (!(local_flag & capture))
639 if (*TrP > (TREE - 300))
641 /* too close to tree table limit */
642 flag.tsume = true;
646 /* Guess strength of move and set flags. */
648 if ((piece != king) && (!in_opening_stage))
650 if (distance(t, EnemyKing) <= 1)
652 /* bonus for square near enemy king */
653 s += 15;
654 INCscore += 2;
655 local_flag |= kingattack;
657 else if (distance(t, OwnKing) <= 1)
659 /* bonus for square near own king */
660 s += 10;
661 INCscore++;
662 local_flag |= kingattack;
666 if (tas) /* own attack array available */
668 /* square t defended by own piece (don't count piece to move) ? */
669 if (is_drop
670 ? (as = attack[side][t])
671 : (as = ((attack[side][t] & CNT_MASK) > 1)))
672 s += (ds = in_endgame_stage ? 100 : 10);
675 if (taxs) /* opponents attack array available */
677 /* square t not threatened by opponent or
678 * defended and only threatened by opponents king ?
680 unsigned long axs;
682 if (!(axs = attack[xside][t])
683 || (tas && as && (axs & control[king]) && (axs & CNT_MASK) == 1))
685 /* FIXME: this is a mess; clean up. */
686 s += (ds = in_endgame_stage
687 ? 200
688 : (is_drop
689 ? (InPromotionZone(side, t)
690 ? 40 + relative_value[piece]
691 : 10)
692 : 20));
696 /* target square near area of action */
698 if (TOsquare >= 0)
699 s += (9 - distance(TOsquare, t));
701 if (FROMsquare >= 0)
702 s += (9 - distance(FROMsquare, t)) / 2;
704 /* target square near own or enemy king */
706 if (!in_opening_stage && piece != king)
708 if (balance[c1] < 50)
709 s += (9 - distance(EnemyKing, t)) * (50 - balance[c1]) / 20;
710 else
711 s += (9 - distance(OwnKing, t)) * (balance[c1] - 50) / 20;
714 if (f > NO_SQUARES)
716 /* bonus for drops, in order to place
717 * drops before questionable moves */
718 s += in_endgame_stage ? 25 : 10;
720 if (t == FROMsquare)
722 /* drop to the square the opponent has just left */
723 s += 5;
726 if (piece == gold)
727 s -= 32 / Captured[side][gold];
728 else if (piece == silver)
729 s -= 16 / Captured[side][silver];
731 #if defined DROPBONUS
732 s += field_bonus(side, piece, f, t, &local_flag);
734 if (s == 10 && piece != pawn)
735 local_flag |= questionable;
736 #endif
738 else
740 /* bonus for moves (non-drops) */
741 int consider_last = false;
743 if (in_endgame_stage && Captured[side][gold])
744 s += 10;
746 s += 20;
748 if (t == FROMsquare)
750 /* move to the square the opponent has just left */
751 s += in_endgame_stage ? 10 : 1;
754 if (color[t] != neutral)
756 /* Captures */
757 if (in_endgame_stage)
759 s += relative_value[board[t]] - relative_value[piece];
761 else
763 s += (*value)[stage][board[t]] - relative_value[piece];
766 if (t == TOsquare) /* Capture of last moved piece */
767 s += in_endgame_stage ? 5 : 50;
770 if (local_flag & promote)
772 /* bonus for promotions */
773 s++;
774 INCscore += value[stage][promoted[piece]] - value[stage][piece];
776 else
778 /* bonus for non-promotions */
779 if (PromotionPossible(side, f, t, piece))
781 #ifdef TESUJIBONUS
782 /* Look at non-promoting silver or knight */
783 if (piece == silver
784 #ifndef MINISHOGI
785 || piece == knight
786 #endif
789 local_flag |= tesuji; /* Non-promotion */
790 s++;
792 else
793 #endif
795 consider_last = true;
797 if (piece == pawn || piece == bishop || piece == rook)
799 local_flag |= stupid;
800 INCscore -= 20;
802 else
804 local_flag |= questionable;
805 INCscore -= 10;
811 if (consider_last)
813 if (local_flag & stupid)
814 s = 0;
815 else
816 s = s % 20;
818 else
820 #if defined FIELDBONUS
821 s += field_bonus(side, piece, f, t, &local_flag);
822 #endif
826 #if defined CHECKBONUS
827 /* determine check flag */
828 if (!(local_flag & check) && !check_determined)
830 gives_check_flag(&local_flag, side, f, t);
832 if (local_flag & check)
833 s += 20;
835 #endif
837 /* check conditions for deep search cut (flag.tsume = true) */
839 #ifdef DEEPSEARCHCUT
840 if (!flag.tsume && deepsearchcut)
842 if ((ply > BEYOND_STUPID) && (local_flag & stupid))
844 try_link = flag.force || ((ply == 1) && (side != computer));
846 else if (hard_time_limit && (ply > BEYOND_TIMEOUT) && flag.timeout)
848 flag.tsume = true;
850 else if ((ply > BEYOND_KINGATTACK) && !(local_flag & kingattack))
852 flag.tsume = true;
854 else if ((ply > BEYOND_QUESTIONABLE) && (local_flag & questionable))
856 flag.tsume = true;
857 #ifdef TESUJIBONUS
859 else if ((ply > BEYOND_TESUJI) && !(local_flag & tesuji))
861 flag.tsume = true;
862 #endif
864 else if ((ply > BEYOND_DROP) && (f > NO_SQUARES))
866 flag.tsume = true;
869 #endif
871 if (try_link || GenerateAllMoves)
873 Link(side, f, t, local_flag,
874 s - ((SCORE_LIMIT + 1000) * 2));
877 flag.tsume = flag_tsume;
882 short
883 DropPossible(short piece, short side, short sq)
885 short r = row(sq), possible = true;
887 if (board[sq] != no_piece)
889 possible = false;
891 else if (piece == pawn)
893 if ((side == black) && (r == 8))
895 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
897 else if ((side == white) && (r == 0))
899 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
901 else if (PawnCnt[side][column(sq)])
903 possible = (generate_move_flags ? ILLEGAL_DOUBLED : false);
906 /* Pawn drops are invalid if they mate the opponent. */
907 if (possible)
909 short f, tempb, tempc;
910 f = pawn + NO_SQUARES;
912 if (side == white)
913 f += NO_PIECES;
915 GenMakeMove(side, f, sq, &tempb, &tempc, false);
917 if (IsCheckmate(side^1, -1, -1))
918 possible = (generate_move_flags ? ILLEGAL_MATE : false);
920 GenUnmakeMove(side, f, sq, tempb, tempc, false);
923 #ifndef MINISHOGI
924 else if (piece == lance)
926 if ((side == black) && (r == 8))
927 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
928 else if ((side == white) && (r == 0))
929 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
931 else if (piece == knight)
933 if ((side == black) && (r >= 7))
934 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
935 else if ((side == white) && (r <= 1))
936 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
938 #endif
940 return possible;
944 #if defined DONTUSE_HEURISTIC
945 static void
946 SortMoves(short ply)
948 short p;
950 for (p = TrPnt[ply]; p < TrPnt[ply+1]; p++)
951 pick(p, TrPnt[ply+1] - 1);
953 #endif /* DONTUSE_HEURISTIC */
956 #ifdef DONTUSE_HEURISTIC
958 static void
959 DontUseMoves(short ply, short n)
961 struct leaf *p;
962 short i, k;
964 /* k = number of check moves + number of captures */
965 for (i = TrPnt[ply], k = 0; i < TrPnt[ply+1]; i++)
967 p = &Tree[i];
969 if ((p->flags & check) || (p->flags & capture))
971 if (++k >= n)
972 return;
976 /* use n moves */
977 for (i = TrPnt[ply]; i < TrPnt[ply+1]; i++)
979 p = &Tree[i];
981 if (!((p->flags & check) || (p->flags & capture)))
983 if (k < n)
984 k++;
985 else
987 p->score = DONTUSE;
993 #endif
998 * Generate moves for a piece. The moves are taken from the precalculated
999 * array nextpos/nextdir. If the board is free, next move is chosen from
1000 * nextpos else from nextdir.
1003 inline void
1004 GenMoves(short ply, short sq, short side,
1005 short xside)
1007 short u, piece;
1008 short ptyp, possible;
1009 #ifdef SAVE_NEXTPOS
1010 short d;
1011 #else
1012 unsigned char *ppos, *pdir;
1013 #endif
1015 piece = board[sq];
1016 ptyp = ptype[side][piece];
1018 #ifdef SAVE_NEXTPOS
1019 u = first_direction(ptyp, &d, sq);
1020 #else
1021 ppos = (*nextpos[ptyp])[sq];
1022 pdir = (*nextdir[ptyp])[sq];
1023 u = ppos[sq];
1024 #endif
1028 unsigned short local_flag;
1029 short c;
1031 if ((c = color[u]) == xside)
1032 local_flag = capture;
1033 else
1034 local_flag = 0;
1036 if (c != side && board[u] != king)
1038 if (PromotionPossible(color[sq], sq, u, piece))
1040 LinkMove(ply, sq, u, local_flag | promote, xside, true);
1042 if ((possible
1043 = NonPromotionPossible(color[sq], u, piece)))
1045 LinkMove(ply, sq, u, local_flag, xside, possible);
1048 else
1050 LinkMove(ply, sq, u, local_flag, xside, true);
1054 if (c == neutral)
1055 #ifdef SAVE_NEXTPOS
1057 u = next_position(ptyp, &d, sq, u);
1059 else
1061 u = next_direction(ptyp, &d, sq);
1063 #else
1065 u = ppos[u];
1067 else
1069 u = pdir[u];
1071 #endif
1073 while (u != sq);
1080 * Drop each piece in hand of "side" to square "u" (if allowed).
1083 static void
1084 DropToSquare(short side, short xside, short ply, short u)
1086 short i, possible;
1088 for (i = pawn; i < king; i++)
1090 if (Captured[side][i])
1092 if ((possible = DropPossible(i, side, u)))
1094 short f;
1095 f = NO_SQUARES + i;
1097 if (side == white)
1098 f += NO_PIECES;
1100 LinkMove(ply, f, u, (dropmask | i), xside, possible);
1109 * Add drops of side that prevent own king from being in check
1110 * from xside's sweeping pieces.
1113 static void
1114 LinkPreventCheckDrops(short side, short xside, short ply)
1116 #ifdef SAVE_NEXTPOS
1117 short d, dd;
1118 #else
1119 unsigned char *ppos, *pdir;
1120 #endif
1121 short piece, u, xu, square, ptyp;
1122 short n, drop_square[9];
1124 if (board[square = PieceList[side][0]] != king)
1125 return;
1127 for (piece = pawn+1; piece <= rook; piece++)
1129 if (
1130 #ifndef MINISHOGI
1131 piece == lance ||
1132 #endif
1133 piece == bishop || piece == rook)
1135 /* check for threat of xside piece */
1136 ptyp = ptype[side][piece];
1137 n = 0;
1138 #ifdef SAVE_NEXTPOS
1139 u = first_direction(ptyp, &d, square);
1140 #else
1141 ppos = (*nextpos[ptyp])[square];
1142 pdir = (*nextdir[ptyp])[square];
1143 u = ppos[square];
1144 #endif
1148 if (color[u] == neutral)
1150 #ifdef SAVE_NEXTPOS
1151 dd = d;
1152 xu = next_position(ptyp, &d, square, u);
1154 if (xu == next_direction(ptyp, &dd, square))
1156 n = 0; /* oops new direction */
1158 else
1160 drop_square[n++] = u;
1162 #else
1164 if ((xu = ppos[u]) == pdir[u])
1166 n = 0; /* oops new direction */
1168 else
1170 drop_square[n++] = u;
1172 #endif
1173 u = xu;
1175 else
1177 if (color[u] == xside && (unpromoted[board[u]] == piece))
1179 /* king is threatened by opponents piece */
1180 while (n > 0)
1182 DropToSquare(side, xside, ply, drop_square[--n]);
1185 else
1187 n = 0;
1189 #ifdef SAVE_NEXTPOS
1190 u = next_direction(ptyp, &d, square);
1191 #else
1192 u = pdir[u];
1193 #endif
1196 while (u != square);
1204 * Add drops that check enemy king.
1207 static void
1208 LinkCheckDrops(short side, short xside, short ply)
1210 #ifdef SAVE_NEXTPOS
1211 short d;
1212 #else
1213 unsigned char *ppos, *pdir;
1214 #endif
1215 short u, ptyp;
1216 short square, piece;
1218 if (board[square = PieceList[xside][0]] != king)
1219 return;
1221 for (piece = pawn; piece < king; piece++)
1223 if (Captured[side][piece])
1226 * "side" has "piece" in hand. Try to make a piece move from
1227 * opponents king square and drop this piece to each reachable
1228 * empty square. This definitely gives check! For a pawn drop
1229 * it must not double pawns and it must not be checkmate!
1232 ptyp = ptype[xside][piece];
1233 #ifdef SAVE_NEXTPOS
1234 u = first_direction(ptyp, &d, square);
1235 #else
1236 ppos = (*nextpos[ptyp])[square];
1237 pdir = (*nextdir[ptyp])[square];
1238 u = ppos[square];
1239 #endif
1242 if (color[u] == neutral)
1244 if (piece != pawn || DropPossible(pawn, side, u))
1246 short f;
1247 f = NO_SQUARES + piece;
1249 if (side == white)
1250 f += NO_PIECES;
1252 LinkMove(ply, f, u,
1253 (dropmask | piece | check), xside, true);
1256 #ifdef SAVE_NEXTPOS
1257 u = next_position(ptyp, &d, square, u);
1258 #else
1259 u = ppos[u];
1260 #endif
1262 else
1264 #ifdef SAVE_NEXTPOS
1265 u = next_direction(ptyp, &d, square);
1266 #else
1267 u = pdir[u];
1268 #endif
1271 while (u != square);
1279 * Fill the array Tree[] with all available moves for side to play. Array
1280 * TrPnt[ply] contains the index into Tree[] of the first move at a ply.
1281 * in_check = 0 side is not in check
1282 * in_check > 1 side is in check
1283 * in_check < 0 don't know
1284 * in_check -2 indicates move generation for book moves
1287 void
1288 MoveList(short side, short ply,
1289 short in_check, short blockable)
1291 short i, xside, u;
1292 struct leaf *firstnode;
1293 short flag_tsume, num;
1295 #ifdef HISTORY
1296 unsigned short hiHt = 0, hi0 = 0, hi1 = 0, hi2 = 0, hi3 = 0, hi4 = 0;
1297 #endif
1299 flag_tsume = flag.tsume;
1301 xside = side ^ 1;
1303 sqking = PieceList[side][0];
1304 sqxking = PieceList[xside][0];
1306 if (in_check >= 0)
1308 InCheck = in_check;
1310 else
1312 InCheck = (board[sqking] == king)
1313 ? SqAttacked(sqking, xside, &blockable)
1314 : false;
1317 GenerateAllMoves = (in_check == -2) || generate_move_flags;
1319 if (InCheck /* && (ply > 1 || side == computer) */)
1321 /* Own king in check */
1322 flag.tsume = true;
1325 TrP = &TrPnt[ply + 1];
1326 *TrP = TrPnt[ply];
1328 firstnode = node = &Tree[*TrP];
1330 if (!PV)
1331 Swag0 = killr0[ply];
1332 else
1333 Swag0 = PV;
1335 Swag1 = killr1[ply];
1336 Swag2 = killr2[ply];
1337 Swag3 = killr3[ply];
1339 if (ply > 2)
1340 Swag4 = killr1[ply - 2];
1341 else
1342 Swag4 = 0;
1344 #ifdef HISTORY
1345 if (use_history)
1347 history[hiHt = hindex(side, SwagHt)] += 5000;
1348 history[hi0 = hindex(side, Swag0)] += 2000;
1349 history[hi1 = hindex(side, Swag1)] += 60;
1350 history[hi2 = hindex(side, Swag2)] += 50;
1351 history[hi3 = hindex(side, Swag3)] += 40;
1352 history[hi4 = hindex(side, Swag4)] += 30;
1354 #endif
1356 for (i = PieceCnt[side]; i >= 0; i--)
1357 GenMoves(ply, PieceList[side][i], side, xside);
1359 if (!InCheck || blockable)
1361 if (flag.tsume)
1363 /* special drop routine for tsume problems */
1364 if (InCheck)
1365 LinkPreventCheckDrops(side, xside, ply);
1366 else
1367 LinkCheckDrops(side, xside, ply);
1369 else
1371 for (u = 0; u < NO_SQUARES; u++)
1372 DropToSquare(side, xside, ply, u);
1376 #ifdef HISTORY
1377 if (use_history)
1379 history[hiHt] -= 5000;
1380 history[hi0] -= 2000;
1381 history[hi1] -= 60;
1382 history[hi2] -= 50;
1383 history[hi3] -= 40;
1384 history[hi4] -= 30;
1386 #endif
1388 SwagHt = 0; /* SwagHt is only used once */
1390 if (flag.tsume && node == firstnode)
1391 (*TrP)++;
1393 GenCnt += (num = (TrPnt[ply+1] - TrPnt[ply]));
1395 #ifdef DONTUSE_HEURISTIC
1396 /* remove some nodes in case of wide spread in depth */
1397 if (!flag.tsume && (i = MaxNum[ply]) > 0 && num > i)
1399 SortMoves(ply);
1400 DontUseMoves(ply, i);
1402 #endif
1404 flag.tsume = flag_tsume;
1410 * Fill the array Tree[] with all available captures for side to play. If
1411 * there is a non-promote option, discard the non-promoting move. Array
1412 * TrPnt[ply] contains the index into Tree[] of the first move at a ply.
1413 * If flag.tsume is set, only add captures (but also the non-promoting)
1414 * that threaten the opponents king.
1416 * in_check = 0: side is not in check
1417 * in_check > 1: side is in check
1418 * in_check < 0: we don't know
1421 void
1422 CaptureList(short side, short ply,
1423 short in_check, short blockable)
1425 short u, sq, xside;
1426 #ifdef SAVE_NEXTPOS
1427 short d;
1428 #else
1429 unsigned char *ppos, *pdir;
1430 #endif
1431 short i, piece, flag_tsume;
1432 small_short *PL;
1434 xside = side ^ 1;
1436 TrP = &TrPnt[ply + 1];
1437 *TrP = TrPnt[ply];
1438 node = &Tree[*TrP];
1440 flag_tsume = flag.tsume;
1442 sqking = PieceList[side][0];
1443 sqxking = PieceList[xside][0];
1445 if (in_check >= 0)
1447 InCheck = in_check;
1449 else
1451 InCheck = (board[sqking] == king)
1452 ? SqAttacked(sqking, xside, &blockable)
1453 : false;
1456 GenerateAllMoves = (in_check == -2);
1458 if (InCheck && (ply > 1 || side == computer))
1460 /* Own king is in check */
1461 flag.tsume = true;
1464 check_determined = false;
1466 PL = PieceList[side];
1468 for (i = 0; i <= PieceCnt[side]; i++)
1470 short ptyp;
1471 sq = PL[i];
1472 piece = board[sq];
1473 ptyp = ptype[side][piece];
1474 #ifdef SAVE_NEXTPOS
1475 u = first_direction(ptyp, &d, sq);
1476 #else
1477 ppos = (*nextpos[ptyp])[sq];
1478 pdir = (*nextdir[ptyp])[sq];
1479 u = ppos[sq];
1480 #endif
1483 if (color[u] == neutral)
1485 #ifdef SAVE_NEXTPOS
1486 u = next_position(ptyp, &d, sq, u);
1487 #else
1488 u = ppos[u];
1489 #endif
1491 else
1493 if (color[u] == xside && board[u] != king)
1495 short PP;
1497 if ((PP = PromotionPossible(color[sq], sq, u, piece)))
1499 Link(side,
1500 sq, u, capture | promote,
1501 (*value)[stage][board[u]]
1502 #if !defined SAVE_SVALUE
1503 + svalue[board[u]]
1504 #endif
1505 - relative_value[piece]);
1508 if (!PP || flag.tsume)
1510 Link(side,
1511 sq, u, capture,
1512 (*value)[stage][board[u]]
1513 #if !defined SAVE_SVALUE
1514 + svalue[board[u]]
1515 #endif
1516 - relative_value[piece]);
1520 #ifdef SAVE_NEXTPOS
1521 u = next_direction(ptyp, &d, sq);
1522 #else
1523 u = pdir[u];
1524 #endif
1527 while (u != sq);
1530 flag.tsume = flag_tsume;
1532 SwagHt = 0; /* SwagHt is only used once */
1539 * If the king is in check, try to find a move that prevents check.
1540 * If such a move is found, return false, otherwise return true.
1541 * in_check = 0: side is not in check
1542 * in_check > 1: side is in check
1543 * in_check < 0: don't know
1544 * blockable > 0 && check: check can possibly be prevented by a drop
1545 * blockable = 0 && check: check can definitely not be prevented by a drop
1546 * blockable < 0 && check: nothing known about type of check
1549 short
1550 IsCheckmate(short side, short in_check, short blockable)
1552 short u, sq, xside;
1553 #ifdef SAVE_NEXTPOS
1554 short d;
1555 #else
1556 unsigned char *ppos, *pdir;
1557 #endif
1558 short i, piece;
1559 small_short *PL;
1560 short tempb, tempc, ksq, threat, dummy, sqking;
1561 short InCheck;
1563 xside = side ^ 1;
1565 sqking = PieceList[side][0];
1568 * Checkmate is possible only if king is in check.
1571 if (in_check >= 0)
1572 InCheck = in_check;
1573 else if (board[sqking] == king)
1574 InCheck = SqAttacked(sqking, xside, &blockable);
1575 else
1576 InCheck = false;
1578 if (!InCheck)
1579 return false;
1582 * Try to find a move that prevents check.
1585 PL = PieceList[side];
1587 for (i = 0; i <= PieceCnt[side]; i++)
1589 short ptyp;
1590 sq = PL[i];
1591 piece = board[sq];
1592 ptyp = ptype[side][piece];
1593 #ifdef SAVE_NEXTPOS
1594 u = first_direction(ptyp, &d, sq);
1595 #else
1596 ppos = (*nextpos[ptyp])[sq];
1597 pdir = (*nextdir[ptyp])[sq];
1598 u = ppos[sq];
1599 #endif
1602 if (color[u] == neutral || color[u] == xside)
1604 GenMakeMove(side, sq, u, &tempb, &tempc, false);
1605 ksq = (sq == sqking) ? u : sqking;
1606 threat = SqAttacked(ksq, xside, &dummy);
1607 GenUnmakeMove(side, sq, u, tempb, tempc, false);
1609 if (!threat)
1610 return false;
1613 #ifdef SAVE_NEXTPOS
1614 u = (color[u] == neutral)
1615 ? next_position(ptyp, &d, sq, u)
1616 : next_direction(ptyp, &d, sq);
1617 #else
1618 u = (color[u] == neutral) ? ppos[u] : pdir[u];
1619 #endif
1621 while (u != sq);
1625 * Couldn't find a move that prevents check.
1626 * Try to find a drop that prevents check.
1629 if (blockable != 0)
1631 for (piece = king - 1; piece >= pawn; piece--)
1633 if (Captured[side][piece])
1635 for (u = 0; u < NO_SQUARES; u++)
1637 if (DropPossible(piece, side, u))
1639 short f;
1640 f = NO_SQUARES + piece;
1642 if (side == white)
1643 f += NO_PIECES;
1645 GenMakeMove(side, f, u, &tempb, &tempc, false);
1646 threat = SqAttacked(sqking, xside, &dummy);
1647 GenUnmakeMove(side, f, u, tempb, tempc, false);
1649 if (!threat)
1650 return false;
1655 * If the piece could be dropped at any square, it is
1656 * impossible for any other piece drop to prevent check.
1657 * Drops are restricted for pawns, lances, and knights.
1660 if (piece >= silver)
1661 break;
1666 return true;