Restore previous copyright information that got removed by error.
[gnushogi.git] / gnushogi / genmove.c
blob8eb0e3d2185bd9717bda7c649296b2fb5bd607db
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, short piece,
249 short from, short to, unsigned short local_flag, short s)
251 if (*TrP == TREE)
253 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 case lance:
330 case knight:
331 case silver:
332 case bishop:
333 case rook:
334 return true;
337 return false;
341 inline int
342 NonPromotionPossible(short color, short f,
343 short t, short p)
345 switch (p)
347 case pawn :
348 if (color == black)
350 return ((t < 72)
351 ? true
352 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
354 else
356 return ((t > 8)
357 ? true
358 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
361 case lance:
362 if (color == black)
364 return ((t < 72)
365 ? true
366 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
368 else
370 return ((t > 8)
371 ? true
372 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
375 case knight:
376 if (color == black)
378 return ((t < 63)
379 ? true
380 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
382 else
384 return ((t > 17)
385 ? true
386 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
390 return true;
394 #if defined FIELDBONUS || defined DROPBONUS
396 /* bonus for possible next moves */
398 inline static short
399 field_bonus(short ply, short side, short piece,
400 short f, short t, unsigned short *local_flag)
402 short s, u, ptyp;
403 unsigned char *ppos, *pdir;
404 short c1, c2;
406 #ifdef SAVE_NEXTPOS
407 short d;
408 #endif
410 c1 = side;
411 c2 = side ^ 1;
412 s = 0;
413 check_determined = true;
415 ptyp = ptype[side][piece];
417 #ifdef SAVE_NEXTPOS
418 u = first_direction(ptyp, &d, t);
419 #else
420 ppos = (*nextpos[ptyp])[t];
421 pdir = (*nextdir[ptyp])[t];
422 u = ppos[t];
423 #endif
427 short coloru = color[u];
429 if (piece != king && GameCnt > 40)
431 if (distance(u, EnemyKing) <= 1)
433 /* can reach square near own king */
434 s += 2;
435 *local_flag |= kingattack;
437 else if (distance(u, OwnKing) <= 1)
439 /* can reach square near enemy king */
440 s++;
441 *local_flag |= kingattack;
445 if (coloru == side)
447 /* impossible next move */
448 #ifdef SAVE_NEXTPOS
449 u = next_direction(ptyp, &d, t);
450 #else
451 u = pdir[u];
452 #endif
454 else
456 /* possible next move */
457 if (PromotionPossible(side, t, u, piece))
459 /* possible promotion in next move */
460 if (piece == pawn)
462 s += 2;
463 #ifdef TESUJIBONUS
464 if (!InPromotionZone(side, t))
466 *local_flag |= tesuji; /* The dangling pawn */
467 s++;
469 #endif
471 else
473 s++;
477 if (coloru == neutral)
479 /* next move to an empty square */
480 if (u == FROMsquare)
482 /* opponent has just left this square */
483 s++;
486 #ifdef SAVE_NEXTPOS
487 u = next_position(ptyp, &d, t, u);
488 #else
489 u = ppos[u];
490 #endif
492 else
494 /* attack opponents piece */
495 #ifdef TESUJIBONUS
496 short boardu, upiece, rvupiece, rvuboard;
497 #endif
498 s++;
500 if (u == TOsquare) /* opponent has moved to TOsquare */
501 s++;
503 if ((boardu = board[u]) == king)
505 s += 20; INCscore -= 18;
506 *local_flag |= check; /* move threatens
507 * opponents king */
510 #ifdef TESUJIBONUS
511 upiece = unpromoted[piece];
512 rvupiece = relative_value[upiece];
513 rvuboard = relative_value[unpromoted[boardu]];
515 if ((upiece == pawn) && (Captured[side][pawn] > 1))
517 *local_flag |= tesuji; /* The joining pawn attack */
518 s++;
521 if (rvupiece <= rvuboard)
523 *local_flag |= tesuji; /* The striking pawn
524 * (piece) attack */
526 if (f > NO_SQUARES)
527 s += 2;
528 else
529 s++;
531 if (upiece == pawn)
532 s++;
534 /* CHECKME: is this right? */
535 if (((rvupiece == rvuboard) && (upiece == pawn))
536 || (upiece == bishop) || (upiece == knight))
538 s++; /* The opposing pawn (piece) */
540 if (upiece == pawn)
541 s++;
544 #endif
546 #ifdef SAVE_NEXTPOS
547 u = next_direction(ptyp, &d, t);
548 #else
549 u = pdir[u];
550 #endif
554 while (u != t);
556 INCscore += s;
558 return s;
561 #endif
567 * Add a move to the tree. Assign a bonus to order the moves as follows:
568 * 1. Principle variation 2. Capture of last moved piece 3. Other captures
569 * (major pieces first) 4. Killer moves 5. Tesuji drops 6. Other Moves
570 * 7. Other drops. 8. Non-promoting moves
571 * If the flag.tsume is set, assign a high bonus for checks.
574 /* inline */ void
575 LinkMove(short ply, short f,
576 short t,
577 unsigned short local_flag,
578 short xside,
579 short score_if_impossible)
581 short s = 0;
582 short side, piece, mv;
583 short flag_tsume, try_link = true;
584 short c1, c2, ds, is_drop = f > NO_SQUARES;
585 unsigned long as = 0;
587 flag_tsume = flag.tsume;
589 c1 = side = xside ^ 1;
590 c2 = xside;
593 * Is it determined whether the move gives check ?
596 check_determined = ((local_flag & check) != 0);
598 mv = (f << 8) | ((local_flag & promote) ? (t | 0x80) : t);
600 if (f > NO_SQUARES)
602 piece = f - NO_SQUARES;
604 if (piece > NO_PIECES)
605 piece -= NO_PIECES;
607 else
609 piece = board[f];
612 if (score_if_impossible < 0)
614 /* The move is flagged as illegal. */
615 Link(side, piece,
616 f, t, local_flag, score_if_impossible);
618 return;
621 INCscore = 0;
623 #ifdef HISTORY
624 s += history[hindex(side, mv)];
625 #endif
627 /* If we're running short of tree nodes, go into tsume mode. */
629 if (!(local_flag & capture))
631 if (*TrP > (TREE - 300))
633 /* too close to tree table limit */
634 flag.tsume = true;
638 /* Guess strength of move and set flags. */
640 if ((piece != king) && (!in_opening_stage))
642 if (distance(t, EnemyKing) <= 1)
644 /* bonus for square near enemy king */
645 s += 15;
646 INCscore += 2;
647 local_flag |= kingattack;
649 else if (distance(t, OwnKing) <= 1)
651 /* bonus for square near own king */
652 s += 10;
653 INCscore++;
654 local_flag |= kingattack;
658 if (tas) /* own attack array available */
660 /* square t defended by own piece (don't count piece to move) ? */
661 if (is_drop
662 ? (as = attack[side][t])
663 : (as = ((attack[side][t] & CNT_MASK) > 1)))
664 s += (ds = in_endgame_stage ? 100 : 10);
667 if (taxs) /* opponents attack array available */
669 /* square t not threatened by opponent or
670 * defended and only threatened by opponents king ?
672 unsigned long axs;
674 if (!(axs = attack[xside][t])
675 || (tas && as && (axs & control[king]) && (axs & CNT_MASK) == 1))
677 /* FIXME: this is a mess; clean up. */
678 s += (ds = in_endgame_stage
679 ? 200
680 : (is_drop
681 ? (InPromotionZone(side, t)
682 ? 40 + relative_value[piece]
683 : 10)
684 : 20));
688 /* target square near area of action */
690 if (TOsquare >= 0)
691 s += (9 - distance(TOsquare, t));
693 if (FROMsquare >= 0)
694 s += (9 - distance(FROMsquare, t)) / 2;
696 /* target square near own or enemy king */
698 if (!in_opening_stage && piece != king)
700 if (balance[c1] < 50)
701 s += (9 - distance(EnemyKing, t)) * (50 - balance[c1]) / 20;
702 else
703 s += (9 - distance(OwnKing, t)) * (balance[c1] - 50) / 20;
706 if (f > NO_SQUARES)
708 /* bonus for drops, in order to place
709 * drops before questionable moves */
710 s += in_endgame_stage ? 25 : 10;
712 if (t == FROMsquare)
714 /* drop to the square the opponent has just left */
715 s += 5;
718 if (piece == gold)
719 s -= 32 / Captured[side][gold];
720 else if (piece == silver)
721 s -= 16 / Captured[side][silver];
723 #if defined DROPBONUS
724 s += field_bonus(ply, side, piece, f, t, &local_flag);
726 if (s == 10 && piece != pawn)
727 local_flag |= questionable;
728 #endif
730 else
732 /* bonus for moves (non-drops) */
733 int consider_last = false;
735 if (in_endgame_stage && Captured[side][gold])
736 s += 10;
738 s += 20;
740 if (t == FROMsquare)
742 /* move to the square the opponent has just left */
743 s += in_endgame_stage ? 10 : 1;
746 if (color[t] != neutral)
748 /* Captures */
749 if (in_endgame_stage)
751 s += relative_value[board[t]] - relative_value[piece];
753 else
755 s += (*value)[stage][board[t]] - relative_value[piece];
758 if (t == TOsquare) /* Capture of last moved piece */
759 s += in_endgame_stage ? 5 : 50;
762 if (local_flag & promote)
764 /* bonus for promotions */
765 s++;
766 INCscore += value[stage][promoted[piece]] - value[stage][piece];
768 else
770 /* bonus for non-promotions */
771 if (PromotionPossible(side, f, t, piece))
773 #ifdef TESUJIBONUS
774 /* Look at non-promoting silver or knight */
775 if (piece == silver || piece == knight)
777 local_flag |= tesuji; /* Non-promotion */
778 s++;
780 else
781 #endif
783 consider_last = true;
785 if (piece == pawn || piece == bishop || piece == rook)
787 local_flag |= stupid;
788 INCscore -= 20;
790 else
792 local_flag |= questionable;
793 INCscore -= 10;
799 if (consider_last)
801 if (local_flag & stupid)
802 s = 0;
803 else
804 s = s % 20;
806 else
808 #if defined FIELDBONUS
809 s += field_bonus(ply, side, piece, f, t, &local_flag);
810 #endif
814 #if defined CHECKBONUS
815 /* determine check flag */
816 if (!(local_flag & check) && !check_determined)
818 gives_check_flag(&local_flag, side, f, t);
820 if (local_flag & check)
821 s += 20;
823 #endif
825 /* check conditions for deep search cut (flag.tsume = true) */
827 #ifdef DEEPSEARCHCUT
828 if (!flag.tsume && deepsearchcut)
830 if ((ply > BEYOND_STUPID) && (local_flag & stupid))
832 try_link = flag.force || ((ply == 1) && (side != computer));
834 else if (hard_time_limit && (ply > BEYOND_TIMEOUT) && flag.timeout)
836 flag.tsume = true;
838 else if ((ply > BEYOND_KINGATTACK) && !(local_flag & kingattack))
840 flag.tsume = true;
842 else if ((ply > BEYOND_QUESTIONABLE) && (local_flag & questionable))
844 flag.tsume = true;
845 #ifdef TESUJIBONUS
847 else if ((ply > BEYOND_TESUJI) && !(local_flag & tesuji))
849 flag.tsume = true;
850 #endif
852 else if ((ply > BEYOND_DROP) && (f > NO_SQUARES))
854 flag.tsume = true;
857 #endif
859 if (try_link || GenerateAllMoves)
861 Link(side, piece, f, t, local_flag,
862 s - ((SCORE_LIMIT + 1000) * 2));
865 flag.tsume = flag_tsume;
870 short
871 DropPossible(short piece, short side, short sq)
873 short r = row(sq), possible = true;
875 if (board[sq] != no_piece)
877 possible = false;
879 else if (piece == pawn)
881 if ((side == black) && (r == 8))
883 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
885 else if ((side == white) && (r == 0))
887 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
889 else if (PawnCnt[side][column(sq)])
891 possible = (generate_move_flags ? ILLEGAL_DOUBLED : false);
894 /* Pawn drops are invalid if they mate the opponent. */
895 if (possible)
897 short f, tempb, tempc;
898 f = pawn + NO_SQUARES;
900 if (side == white)
901 f += NO_PIECES;
903 GenMakeMove(side, f, sq, &tempb, &tempc, false);
905 if (IsCheckmate(side^1, -1, -1))
906 possible = (generate_move_flags ? ILLEGAL_MATE : false);
908 GenUnmakeMove(side, f, sq, tempb, tempc, false);
911 else if (piece == lance)
913 if ((side == black) && (r == 8))
914 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
915 else if ((side == white) && (r == 0))
916 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
918 else if (piece == knight)
920 if ((side == black) && (r >= 7))
921 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
922 else if ((side == white) && (r <= 1))
923 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
926 return possible;
930 #if defined DONTUSE_HEURISTIC
931 static void
932 SortMoves(short ply)
934 short p;
936 for (p = TrPnt[ply]; p < TrPnt[ply+1]; p++)
937 pick(p, TrPnt[ply+1] - 1);
939 #endif /* DONTUSE_HEURISTIC */
942 #ifdef DONTUSE_HEURISTIC
944 static void
945 DontUseMoves(short ply, short n)
947 struct leaf *p;
948 short i, k;
950 /* k = number of check moves + number of captures */
951 for (i = TrPnt[ply], k = 0; i < TrPnt[ply+1]; i++)
953 p = &Tree[i];
955 if ((p->flags & check) || (p->flags & capture))
957 if (++k >= n)
958 return;
962 /* use n moves */
963 for (i = TrPnt[ply]; i < TrPnt[ply+1]; i++)
965 p = &Tree[i];
967 if (!((p->flags & check) || (p->flags & capture)))
969 if (k < n)
970 k++;
971 else
973 p->score = DONTUSE;
979 #endif
984 * Generate moves for a piece. The moves are taken from the precalculated
985 * array nextpos/nextdir. If the board is free, next move is chosen from
986 * nextpos else from nextdir.
989 inline void
990 GenMoves(short ply, short sq, short side,
991 short xside)
993 short u, piece;
994 short ptyp, possible;
995 #ifdef SAVE_NEXTPOS
996 short d;
997 #else
998 unsigned char *ppos, *pdir;
999 #endif
1001 piece = board[sq];
1002 ptyp = ptype[side][piece];
1004 #ifdef SAVE_NEXTPOS
1005 u = first_direction(ptyp, &d, sq);
1006 #else
1007 ppos = (*nextpos[ptyp])[sq];
1008 pdir = (*nextdir[ptyp])[sq];
1009 u = ppos[sq];
1010 #endif
1014 unsigned short local_flag;
1015 short c;
1017 if ((c = color[u]) == xside)
1018 local_flag = capture;
1019 else
1020 local_flag = 0;
1022 if (c != side && board[u] != king)
1024 if (PromotionPossible(color[sq], sq, u, piece))
1026 LinkMove(ply, sq, u, local_flag | promote, xside, true);
1028 if ((possible
1029 = NonPromotionPossible(color[sq], sq, u, piece)))
1031 LinkMove(ply, sq, u, local_flag, xside, possible);
1034 else
1036 LinkMove(ply, sq, u, local_flag, xside, true);
1040 if (c == neutral)
1041 #ifdef SAVE_NEXTPOS
1043 u = next_position(ptyp, &d, sq, u);
1045 else
1047 u = next_direction(ptyp, &d, sq);
1049 #else
1051 u = ppos[u];
1053 else
1055 u = pdir[u];
1057 #endif
1059 while (u != sq);
1066 * Drop each piece in hand of "side" to square "u" (if allowed).
1069 static void
1070 DropToSquare(short side, short xside, short ply, short u)
1072 short i, possible;
1074 for (i = pawn; i < king; i++)
1076 if (Captured[side][i])
1078 if ((possible = DropPossible(i, side, u)))
1080 short f;
1081 f = NO_SQUARES + i;
1083 if (side == white)
1084 f += NO_PIECES;
1086 LinkMove(ply, f, u, (dropmask | i), xside, possible);
1095 * Add drops of side that prevent own king from being in check
1096 * from xside's sweeping pieces.
1099 static void
1100 LinkPreventCheckDrops(short side, short xside, short ply)
1102 #ifdef SAVE_NEXTPOS
1103 short d, dd;
1104 #else
1105 unsigned char *ppos, *pdir;
1106 #endif
1107 short piece, u, xu, square, ptyp;
1108 short n, drop_square[9];
1110 if (board[square = PieceList[side][0]] != king)
1111 return;
1113 for (piece = lance; piece <= rook; piece++) /* FIXME */
1115 if (piece == lance || piece == bishop || piece == rook)
1117 /* check for threat of xside piece */
1118 ptyp = ptype[side][piece];
1119 n = 0;
1120 #ifdef SAVE_NEXTPOS
1121 u = first_direction(ptyp, &d, square);
1122 #else
1123 ppos = (*nextpos[ptyp])[square];
1124 pdir = (*nextdir[ptyp])[square];
1125 u = ppos[square];
1126 #endif
1130 if (color[u] == neutral)
1132 #ifdef SAVE_NEXTPOS
1133 dd = d;
1134 xu = next_position(ptyp, &d, square, u);
1136 if (xu == next_direction(ptyp, &dd, square))
1138 n = 0; /* oops new direction */
1140 else
1142 drop_square[n++] = u;
1144 #else
1146 if ((xu = ppos[u]) == pdir[u])
1148 n = 0; /* oops new direction */
1150 else
1152 drop_square[n++] = u;
1154 #endif
1155 u = xu;
1157 else
1159 if (color[u] == xside && (unpromoted[board[u]] == piece))
1161 /* king is threatened by opponents piece */
1162 while (n > 0)
1164 DropToSquare(side, xside, ply, drop_square[--n]);
1167 else
1169 n = 0;
1171 #ifdef SAVE_NEXTPOS
1172 u = next_direction(ptyp, &d, square);
1173 #else
1174 u = pdir[u];
1175 #endif
1178 while (u != square);
1186 * Add drops that check enemy king.
1189 static void
1190 LinkCheckDrops(short side, short xside, short ply)
1192 #ifdef SAVE_NEXTPOS
1193 short d;
1194 #else
1195 unsigned char *ppos, *pdir;
1196 #endif
1197 short u, ptyp;
1198 short square, piece;
1200 if (board[square = PieceList[xside][0]] != king)
1201 return;
1203 for (piece = pawn; piece < king; piece++)
1205 if (Captured[side][piece])
1208 * "side" has "piece" in hand. Try to make a piece move from
1209 * opponents king square and drop this piece to each reachable
1210 * empty square. This definitely gives check! For a pawn drop
1211 * it must not double pawns and it must not be checkmate!
1214 ptyp = ptype[xside][piece];
1215 #ifdef SAVE_NEXTPOS
1216 u = first_direction(ptyp, &d, square);
1217 #else
1218 ppos = (*nextpos[ptyp])[square];
1219 pdir = (*nextdir[ptyp])[square];
1220 u = ppos[square];
1221 #endif
1224 if (color[u] == neutral)
1226 if (piece != pawn || DropPossible(pawn, side, u))
1228 short f;
1229 f = NO_SQUARES + piece;
1231 if (side == white)
1232 f += NO_PIECES;
1234 LinkMove(ply, f, u,
1235 (dropmask | piece | check), xside, true);
1238 #ifdef SAVE_NEXTPOS
1239 u = next_position(ptyp, &d, square, u);
1240 #else
1241 u = ppos[u];
1242 #endif
1244 else
1246 #ifdef SAVE_NEXTPOS
1247 u = next_direction(ptyp, &d, square);
1248 #else
1249 u = pdir[u];
1250 #endif
1253 while (u != square);
1261 * Fill the array Tree[] with all available moves for side to play. Array
1262 * TrPnt[ply] contains the index into Tree[] of the first move at a ply.
1263 * in_check = 0 side is not in check
1264 * in_check > 1 side is in check
1265 * in_check < 0 don't know
1266 * in_check -2 indicates move generation for book moves
1269 void
1270 MoveList(short side, short ply,
1271 short in_check, short blockable)
1273 short i, xside, u;
1274 struct leaf *firstnode;
1275 short flag_tsume, num;
1277 #ifdef HISTORY
1278 unsigned short hiHt = 0, hi0 = 0, hi1 = 0, hi2 = 0, hi3 = 0, hi4 = 0;
1279 #endif
1281 flag_tsume = flag.tsume;
1283 xside = side ^ 1;
1285 sqking = PieceList[side][0];
1286 sqxking = PieceList[xside][0];
1288 if (in_check >= 0)
1290 InCheck = in_check;
1292 else
1294 InCheck = (board[sqking] == king)
1295 ? SqAttacked(sqking, xside, &blockable)
1296 : false;
1299 GenerateAllMoves = (in_check == -2) || generate_move_flags;
1301 if (InCheck /* && (ply > 1 || side == computer) */)
1303 /* Own king in check */
1304 flag.tsume = true;
1307 TrP = &TrPnt[ply + 1];
1308 *TrP = TrPnt[ply];
1310 firstnode = node = &Tree[*TrP];
1312 if (!PV)
1313 Swag0 = killr0[ply];
1314 else
1315 Swag0 = PV;
1317 Swag1 = killr1[ply];
1318 Swag2 = killr2[ply];
1319 Swag3 = killr3[ply];
1321 if (ply > 2)
1322 Swag4 = killr1[ply - 2];
1323 else
1324 Swag4 = 0;
1326 #ifdef HISTORY
1327 if (use_history)
1329 history[hiHt = hindex(side, SwagHt)] += 5000;
1330 history[hi0 = hindex(side, Swag0)] += 2000;
1331 history[hi1 = hindex(side, Swag1)] += 60;
1332 history[hi2 = hindex(side, Swag2)] += 50;
1333 history[hi3 = hindex(side, Swag3)] += 40;
1334 history[hi4 = hindex(side, Swag4)] += 30;
1336 #endif
1338 for (i = PieceCnt[side]; i >= 0; i--)
1339 GenMoves(ply, PieceList[side][i], side, xside);
1341 if (!InCheck || blockable)
1343 if (flag.tsume)
1345 /* special drop routine for tsume problems */
1346 if (InCheck)
1347 LinkPreventCheckDrops(side, xside, ply);
1348 else
1349 LinkCheckDrops(side, xside, ply);
1351 else
1353 for (u = 0; u < NO_SQUARES; u++)
1354 DropToSquare(side, xside, ply, u);
1358 #ifdef HISTORY
1359 if (use_history)
1361 history[hiHt] -= 5000;
1362 history[hi0] -= 2000;
1363 history[hi1] -= 60;
1364 history[hi2] -= 50;
1365 history[hi3] -= 40;
1366 history[hi4] -= 30;
1368 #endif
1370 SwagHt = 0; /* SwagHt is only used once */
1372 if (flag.tsume && node == firstnode)
1373 (*TrP)++;
1375 GenCnt += (num = (TrPnt[ply+1] - TrPnt[ply]));
1377 #ifdef DONTUSE_HEURISTIC
1378 /* remove some nodes in case of wide spread in depth */
1379 if (!flag.tsume && (i = MaxNum[ply]) > 0 && num > i)
1381 SortMoves(ply);
1382 DontUseMoves(ply, i);
1384 #endif
1386 flag.tsume = flag_tsume;
1392 * Fill the array Tree[] with all available captures for side to play. If
1393 * there is a non-promote option, discard the non-promoting move. Array
1394 * TrPnt[ply] contains the index into Tree[] of the first move at a ply.
1395 * If flag.tsume is set, only add captures (but also the non-promoting)
1396 * that threaten the opponents king.
1398 * in_check = 0: side is not in check
1399 * in_check > 1: side is in check
1400 * in_check < 0: we don't know
1403 void
1404 CaptureList(short side, short ply,
1405 short in_check, short blockable)
1407 short u, sq, xside;
1408 #ifdef SAVE_NEXTPOS
1409 short d;
1410 #else
1411 unsigned char *ppos, *pdir;
1412 #endif
1413 short i, piece, flag_tsume;
1414 small_short *PL;
1416 xside = side ^ 1;
1418 TrP = &TrPnt[ply + 1];
1419 *TrP = TrPnt[ply];
1420 node = &Tree[*TrP];
1422 flag_tsume = flag.tsume;
1424 sqking = PieceList[side][0];
1425 sqxking = PieceList[xside][0];
1427 if (in_check >= 0)
1429 InCheck = in_check;
1431 else
1433 InCheck = (board[sqking] == king)
1434 ? SqAttacked(sqking, xside, &blockable)
1435 : false;
1438 GenerateAllMoves = (in_check == -2);
1440 if (InCheck && (ply > 1 || side == computer))
1442 /* Own king is in check */
1443 flag.tsume = true;
1446 check_determined = false;
1448 PL = PieceList[side];
1450 for (i = 0; i <= PieceCnt[side]; i++)
1452 short ptyp;
1453 sq = PL[i];
1454 piece = board[sq];
1455 ptyp = ptype[side][piece];
1456 #ifdef SAVE_NEXTPOS
1457 u = first_direction(ptyp, &d, sq);
1458 #else
1459 ppos = (*nextpos[ptyp])[sq];
1460 pdir = (*nextdir[ptyp])[sq];
1461 u = ppos[sq];
1462 #endif
1465 if (color[u] == neutral)
1467 #ifdef SAVE_NEXTPOS
1468 u = next_position(ptyp, &d, sq, u);
1469 #else
1470 u = ppos[u];
1471 #endif
1473 else
1475 if (color[u] == xside && board[u] != king)
1477 short PP;
1479 if ((PP = PromotionPossible(color[sq], sq, u, piece)))
1481 Link(side, piece,
1482 sq, u, capture | promote,
1483 (*value)[stage][board[u]]
1484 #if !defined SAVE_SVALUE
1485 + svalue[board[u]]
1486 #endif
1487 - relative_value[piece]);
1490 if (!PP || flag.tsume)
1492 Link(side, piece,
1493 sq, u, capture,
1494 (*value)[stage][board[u]]
1495 #if !defined SAVE_SVALUE
1496 + svalue[board[u]]
1497 #endif
1498 - relative_value[piece]);
1502 #ifdef SAVE_NEXTPOS
1503 u = next_direction(ptyp, &d, sq);
1504 #else
1505 u = pdir[u];
1506 #endif
1509 while (u != sq);
1512 flag.tsume = flag_tsume;
1514 SwagHt = 0; /* SwagHt is only used once */
1521 * If the king is in check, try to find a move that prevents check.
1522 * If such a move is found, return false, otherwise return true.
1523 * in_check = 0: side is not in check
1524 * in_check > 1: side is in check
1525 * in_check < 0: don't know
1526 * blockable > 0 && check: check can possibly be prevented by a drop
1527 * blockable = 0 && check: check can definitely not be prevented by a drop
1528 * blockable < 0 && check: nothing known about type of check
1531 short
1532 IsCheckmate(short side, short in_check, short blockable)
1534 short u, sq, xside;
1535 #ifdef SAVE_NEXTPOS
1536 short d;
1537 #else
1538 unsigned char *ppos, *pdir;
1539 #endif
1540 short i, piece;
1541 small_short *PL;
1542 short tempb, tempc, ksq, threat, dummy, sqking;
1543 short InCheck;
1545 xside = side ^ 1;
1547 sqking = PieceList[side][0];
1550 * Checkmate is possible only if king is in check.
1553 if (in_check >= 0)
1554 InCheck = in_check;
1555 else if (board[sqking] == king)
1556 InCheck = SqAttacked(sqking, xside, &blockable);
1557 else
1558 InCheck = false;
1560 if (!InCheck)
1561 return false;
1564 * Try to find a move that prevents check.
1567 PL = PieceList[side];
1569 for (i = 0; i <= PieceCnt[side]; i++)
1571 short ptyp;
1572 sq = PL[i];
1573 piece = board[sq];
1574 ptyp = ptype[side][piece];
1575 #ifdef SAVE_NEXTPOS
1576 u = first_direction(ptyp, &d, sq);
1577 #else
1578 ppos = (*nextpos[ptyp])[sq];
1579 pdir = (*nextdir[ptyp])[sq];
1580 u = ppos[sq];
1581 #endif
1584 if (color[u] == neutral || color[u] == xside)
1586 GenMakeMove(side, sq, u, &tempb, &tempc, false);
1587 ksq = (sq == sqking) ? u : sqking;
1588 threat = SqAttacked(ksq, xside, &dummy);
1589 GenUnmakeMove(side, sq, u, tempb, tempc, false);
1591 if (!threat)
1592 return false;
1595 #ifdef SAVE_NEXTPOS
1596 u = (color[u] == neutral)
1597 ? next_position(ptyp, &d, sq, u)
1598 : next_direction(ptyp, &d, sq);
1599 #else
1600 u = (color[u] == neutral) ? ppos[u] : pdir[u];
1601 #endif
1603 while (u != sq);
1607 * Couldn't find a move that prevents check.
1608 * Try to find a drop that prevents check.
1611 if (blockable != 0)
1613 for (piece = king - 1; piece >= pawn; piece--)
1615 if (Captured[side][piece])
1617 for (u = 0; u < NO_SQUARES; u++)
1619 if (DropPossible(piece, side, u))
1621 short f;
1622 f = NO_SQUARES + piece;
1624 if (side == white)
1625 f += NO_PIECES;
1627 GenMakeMove(side, f, u, &tempb, &tempc, false);
1628 threat = SqAttacked(sqking, xside, &dummy);
1629 GenUnmakeMove(side, f, u, tempb, tempc, false);
1631 if (!threat)
1632 return false;
1637 * If the piece could be dropped at any square, it is
1638 * impossible for any other piece drop to prevent check.
1639 * Drops are restricted for pawns, lances, and knights.
1642 if (piece > knight)
1643 break;
1648 return true;