Changing license to GPL3 (and bumping version to 1.4.0).
[gnushogi.git] / gnushogi / genmove.c
blob4c20a5f807efcca46a292ec2c5c1188cb0fcad12
1 /*
2 * FILE: genmove.c
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
20 * for more details.
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 * ----------------------------------------------------------------------
29 #include "gnushogi.h"
31 /* #define DONTUSE_HEURISTIC */
33 short *TrP;
35 static struct leaf *node;
36 static short sqking, sqxking;
37 static short InCheck = false, GenerateAllMoves = false;
38 static short check_determined = false;
40 short deepsearchcut = true;
41 short tas = false, taxs = false, ssa = false;
43 short generate_move_flags = false;
47 * Ply limits for deep search cut. No moves or drops flagged with "stupid"
48 * are considered beyond ply BEYOND_STUPID. Only moves or drops flagged
49 * with "kingattack" are considered beyond ply BEYOND_KINGATTACK. No moves
50 * or drops flagged with "questionable" are considered beyond ply
51 * BEYOND_QUESTIONABLE. Only moves or drops flagged with "tesuji" are
52 * considered beyond ply BEYOND_TESUJI. No drops are considered beyond ply
53 * BEYOND_DROP. Exceptions: moves or drops that prevent check or give
54 * check are always considered.
57 #define BEYOND_STUPID 0
58 #define BEYOND_TIMEOUT 2
59 #define BEYOND_KINGATTACK 6
60 #define BEYOND_QUESTIONABLE 8
61 #define BEYOND_TESUJI 8
62 #define BEYOND_DROP 10
64 #ifdef DONTUSE_HEURISTIC
65 static short MaxNum[MAXDEPTH] =
67 -1, 40, 80, 20, 40, 10, 5, 5, 5, 5,
68 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
69 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
70 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
72 #endif
74 #ifdef HASHKEYTEST
75 extern int CheckHashKey();
76 extern char mvstr[4][6];
77 #endif
81 * Update Arrays board[] and color[] to reflect the new board
82 * position obtained after making the move pointed to by node.
85 inline static void
86 GenMakeMove(short side,
87 short f,
88 short t,
89 short *tempb, /* piece at to square */
90 short *tempc, /* color of to square */
91 short promote_piece)
93 short piece, upiece, n;
95 t = t & 0x7f;
97 if (f > NO_SQUARES)
99 piece = f - NO_SQUARES;
101 if (piece > NO_PIECES)
102 piece -= NO_PIECES;
104 board[t] = piece;
105 color[t] = side;
106 n = (Captured[side][piece])--;
107 UpdateDropHashbd(side, piece, n);
108 UpdateHashbd(side, piece, -1, t);
109 UpdatePieceList(side, t, ADD_PIECE);
111 else
113 *tempb = board[t];
114 *tempc = color[t];
116 if (*tempb != no_piece)
118 n = ++Captured[side][upiece = unpromoted[*tempb]];
119 UpdateDropHashbd(side, upiece, n);
120 UpdateHashbd(*tempc, *tempb, -1, t);
121 UpdatePieceList(*tempc, t, REMOVE_PIECE);
124 piece = board[f];
125 Pindex[t] = Pindex[f];
126 PieceList[side][Pindex[t]] = t;
127 color[f] = neutral;
128 board[f] = no_piece;
129 color[t] = side;
131 if (promote_piece)
133 UpdateHashbd(side, piece, f, -1);
134 board[t] = promoted[piece];
135 UpdateHashbd(side, board[t], -1, t);
137 else
139 board[t] = piece;
140 UpdateHashbd(side, piece, f, t);
144 #ifdef HASHKEYTEST
145 if (CheckHashKey())
147 algbr(f, t, 0);
148 printf("error in GenMakeMove: %s\n", mvstr[0]);
149 exit(1);
151 #endif
157 * Take back a move.
160 static void
161 GenUnmakeMove(short side,
162 short f,
163 short t,
164 short tempb,
165 short tempc,
166 short promote_piece)
168 short piece, upiece, n;
170 t = t & 0x7f;
172 if (f > NO_SQUARES)
174 piece = f - NO_SQUARES;
176 if (piece > NO_PIECES)
177 piece -= NO_PIECES;
179 board[t] = no_piece;
180 color[t] = neutral;
181 n = ++Captured[side][piece];
182 UpdateDropHashbd(side, piece, n);
183 UpdateHashbd(side, piece, -1, t);
184 UpdatePieceList(side, t, REMOVE_PIECE);
186 else
188 piece = board[t];
189 color[t] = tempc;
190 board[t] = tempb;
191 Pindex[f] = Pindex[t];
192 PieceList[side][Pindex[f]] = f;
194 if (tempb != no_piece)
196 /* FIXME: make this next line a bit more reasonable... */
197 n = (Captured[side][upiece = unpromoted[tempb]])--;
198 UpdateDropHashbd(side, upiece, n);
199 UpdateHashbd(tempc, tempb, -1, t);
200 UpdatePieceList(tempc, t, ADD_PIECE);
203 color[f] = side;
205 if (promote_piece)
207 UpdateHashbd(side, piece, -1, t);
208 board[f] = unpromoted[piece];
209 UpdateHashbd(side, board[f], f, -1);
211 else
213 board[f] = piece;
214 UpdateHashbd(side, piece, f, t);
218 #ifdef HASHKEYTEST
219 if (CheckHashKey())
221 algbr(f, t, 0);
222 printf("error in GenUnmakeMove: %s\n", mvstr[0]);
223 exit(1);
225 #endif
230 static void
231 gives_check_flag(unsigned short *flags, short side, short f, short t)
233 short tempb, tempc, blockable, promote_piece;
234 promote_piece = (*flags & promote) != 0;
235 GenMakeMove(side, f, t, &tempb, &tempc, promote_piece);
237 if (SqAttacked(sqxking, side, &blockable))
238 *flags |= check;
240 GenUnmakeMove(side, f, t, tempb, tempc, promote_piece);
244 inline static void
245 Link(short side, short piece,
246 short from, short to, unsigned short local_flag, short s)
248 if (*TrP == TREE)
250 ShowMessage("TREE overflow\n");
252 else
254 node->f = from;
255 node->t = (local_flag & promote) ? (to | 0x80) : to;
256 node->reply = 0;
257 node->flags = local_flag;
258 node->score = s;
259 node->INCscore = INCscore;
261 if (GenerateAllMoves)
263 /* FIXME: gimme a break! */
264 (*TrP)++, node++;
266 else if (InCheck)
268 /* only moves out of check */
269 short tempb, tempc, sq, threat, blockable, promote_piece;
270 promote_piece = (node->flags & promote) != 0;
271 GenMakeMove(side, node->f, node->t,
272 &tempb, &tempc, promote_piece);
273 sq = (from == sqking) ? to : sqking;
274 threat = SqAttacked(sq, side ^ 1, &blockable);
275 GenUnmakeMove(side, node->f, node->t,
276 tempb, tempc, promote_piece);
278 if (!threat)
280 /* FIXME! Gimme a break! */
281 (*TrP)++, node++;
284 else if (flag.tsume)
286 /* only moves that give check */
287 if (!(node->flags & check) && !check_determined)
289 /* determine check flag */
290 gives_check_flag(&node->flags, side, node->f, node->t);
293 if (node->flags & check)
295 /* FIXME! Gimme a break! */
296 (*TrP)++, node++;
299 else
301 /* FIXME! Gimme a break! */
302 (*TrP)++, node++;
308 inline int
309 PromotionPossible(short color, short f, short t, short p)
311 if (color == black)
313 if ((f < 54) && (t < 54))
314 return false;
316 else
318 if ((f > 26) && (t > 26))
319 return false;
322 /* FIXME: this can be simplified... */
323 switch (p)
325 case pawn:
326 case lance:
327 case knight:
328 case silver:
329 case bishop:
330 case rook:
331 return true;
334 return false;
338 inline int
339 NonPromotionPossible(short color, short f,
340 short t, short p)
342 switch (p)
344 case pawn :
345 if (color == black)
347 return ((t < 72)
348 ? true
349 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
351 else
353 return ((t > 8)
354 ? true
355 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
358 case lance:
359 if (color == black)
361 return ((t < 72)
362 ? true
363 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
365 else
367 return ((t > 8)
368 ? true
369 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
372 case knight:
373 if (color == black)
375 return ((t < 63)
376 ? true
377 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
379 else
381 return ((t > 17)
382 ? true
383 : (generate_move_flags ? ILLEGAL_TRAPPED : false));
387 return true;
391 #if defined FIELDBONUS || defined DROPBONUS
393 /* bonus for possible next moves */
395 inline static short
396 field_bonus(short ply, short side, short piece,
397 short f, short t, unsigned short *local_flag)
399 short s, u, ptyp;
400 unsigned char *ppos, *pdir;
401 short c1, c2;
403 #ifdef SAVE_NEXTPOS
404 short d;
405 #endif
407 c1 = side;
408 c2 = side ^ 1;
409 s = 0;
410 check_determined = true;
412 ptyp = ptype[side][piece];
414 #ifdef SAVE_NEXTPOS
415 u = first_direction(ptyp, &d, t);
416 #else
417 ppos = (*nextpos[ptyp])[t];
418 pdir = (*nextdir[ptyp])[t];
419 u = ppos[t];
420 #endif
424 short coloru = color[u];
426 if (piece != king && GameCnt > 40)
428 if (distance(u, EnemyKing) <= 1)
430 /* can reach square near own king */
431 s += 2;
432 *local_flag |= kingattack;
434 else if (distance(u, OwnKing) <= 1)
436 /* can reach square near enemy king */
437 s++;
438 *local_flag |= kingattack;
442 if (coloru == side)
444 /* impossible next move */
445 #ifdef SAVE_NEXTPOS
446 u = next_direction(ptyp, &d, t);
447 #else
448 u = pdir[u];
449 #endif
451 else
453 /* possible next move */
454 if (PromotionPossible(side, t, u, piece))
456 /* possible promotion in next move */
457 if (piece == pawn)
459 s += 2;
460 #ifdef TESUJIBONUS
461 if (!InPromotionZone(side, t))
463 *local_flag |= tesuji; /* The dangling pawn */
464 s++;
466 #endif
468 else
470 s++;
474 if (coloru == neutral)
476 /* next move to an empty square */
477 if (u == FROMsquare)
479 /* opponent has just left this square */
480 s++;
483 #ifdef SAVE_NEXTPOS
484 u = next_position(ptyp, &d, t, u);
485 #else
486 u = ppos[u];
487 #endif
489 else
491 /* attack opponents piece */
492 #ifdef TESUJIBONUS
493 short boardu, upiece, rvupiece, rvuboard;
494 #endif
495 s++;
497 if (u == TOsquare) /* opponent has moved to TOsquare */
498 s++;
500 if ((boardu = board[u]) == king)
502 s += 20; INCscore -= 18;
503 *local_flag |= check; /* move threatens
504 * opponents king */
507 #ifdef TESUJIBONUS
508 upiece = unpromoted[piece];
509 rvupiece = relative_value[upiece];
510 rvuboard = relative_value[unpromoted[boardu]];
512 if ((upiece == pawn) && (Captured[side][pawn] > 1))
514 *local_flag |= tesuji; /* The joining pawn attack */
515 s++;
518 if (rvupiece <= rvuboard)
520 *local_flag |= tesuji; /* The striking pawn
521 * (piece) attack */
523 if (f > NO_SQUARES)
524 s += 2;
525 else
526 s++;
528 if (upiece == pawn)
529 s++;
531 /* CHECKME: is this right? */
532 if (((rvupiece == rvuboard) && (upiece == pawn))
533 || (upiece == bishop) || (upiece == knight))
535 s++; /* The opposing pawn (piece) */
537 if (upiece == pawn)
538 s++;
541 #endif
543 #ifdef SAVE_NEXTPOS
544 u = next_direction(ptyp, &d, t);
545 #else
546 u = pdir[u];
547 #endif
551 while (u != t);
553 INCscore += s;
555 return s;
558 #endif
564 * Add a move to the tree. Assign a bonus to order the moves as follows:
565 * 1. Principle variation 2. Capture of last moved piece 3. Other captures
566 * (major pieces first) 4. Killer moves 5. Tesuji drops 6. Other Moves
567 * 7. Other drops. 8. Non-promoting moves
568 * If the flag.tsume is set, assign a high bonus for checks.
571 /* inline */ void
572 LinkMove(short ply, short f,
573 short t,
574 unsigned short local_flag,
575 short xside,
576 short score_if_impossible)
578 short s = 0;
579 short side, piece, mv;
580 short flag_tsume, try_link = true;
581 short c1, c2, ds, is_drop = f > NO_SQUARES;
582 unsigned long as = 0;
584 flag_tsume = flag.tsume;
586 c1 = side = xside ^ 1;
587 c2 = xside;
590 * Is it determined whether the move gives check ?
593 check_determined = ((local_flag & check) != 0);
595 mv = (f << 8) | ((local_flag & promote) ? (t | 0x80) : t);
597 if (f > NO_SQUARES)
599 piece = f - NO_SQUARES;
601 if (piece > NO_PIECES)
602 piece -= NO_PIECES;
604 else
606 piece = board[f];
609 if (score_if_impossible < 0)
611 /* The move is flagged as illegal. */
612 Link(side, piece,
613 f, t, local_flag, score_if_impossible);
615 return;
618 INCscore = 0;
620 #ifdef HISTORY
621 s += history[hindex(side, mv)];
622 #endif
624 /* If we're running short of tree nodes, go into tsume mode. */
626 if (!(local_flag & capture))
628 if (*TrP > (TREE - 300))
630 /* too close to tree table limit */
631 flag.tsume = true;
635 /* Guess strength of move and set flags. */
637 if ((piece != king) && (!in_opening_stage))
639 if (distance(t, EnemyKing) <= 1)
641 /* bonus for square near enemy king */
642 s += 15;
643 INCscore += 2;
644 local_flag |= kingattack;
646 else if (distance(t, OwnKing) <= 1)
648 /* bonus for square near own king */
649 s += 10;
650 INCscore++;
651 local_flag |= kingattack;
655 if (tas) /* own attack array available */
657 /* square t defended by own piece (don't count piece to move) ? */
658 if (is_drop
659 ? (as = attack[side][t])
660 : (as = ((attack[side][t] & CNT_MASK) > 1)))
661 s += (ds = in_endgame_stage ? 100 : 10);
664 if (taxs) /* opponents attack array available */
666 /* square t not threatened by opponent or
667 * defended and only threatened by opponents king ?
669 unsigned long axs;
671 if (!(axs = attack[xside][t])
672 || (tas && as && (axs & control[king]) && (axs & CNT_MASK) == 1))
674 /* FIXME: this is a mess; clean up. */
675 s += (ds = in_endgame_stage
676 ? 200
677 : (is_drop
678 ? (InPromotionZone(side, t)
679 ? 40 + relative_value[piece]
680 : 10)
681 : 20));
685 /* target square near area of action */
687 if (TOsquare >= 0)
688 s += (9 - distance(TOsquare, t));
690 if (FROMsquare >= 0)
691 s += (9 - distance(FROMsquare, t)) / 2;
693 /* target square near own or enemy king */
695 if (!in_opening_stage && piece != king)
697 if (balance[c1] < 50)
698 s += (9 - distance(EnemyKing, t)) * (50 - balance[c1]) / 20;
699 else
700 s += (9 - distance(OwnKing, t)) * (balance[c1] - 50) / 20;
703 if (f > NO_SQUARES)
705 /* bonus for drops, in order to place
706 * drops before questionable moves */
707 s += in_endgame_stage ? 25 : 10;
709 if (t == FROMsquare)
711 /* drop to the square the opponent has just left */
712 s += 5;
715 if (piece == gold)
716 s -= 32 / Captured[side][gold];
717 else if (piece == silver)
718 s -= 16 / Captured[side][silver];
720 #if defined DROPBONUS
721 s += field_bonus(ply, side, piece, f, t, &local_flag);
723 if (s == 10 && piece != pawn)
724 local_flag |= questionable;
725 #endif
727 else
729 /* bonus for moves (non-drops) */
730 int consider_last = false;
732 if (in_endgame_stage && Captured[side][gold])
733 s += 10;
735 s += 20;
737 if (t == FROMsquare)
739 /* move to the square the opponent has just left */
740 s += in_endgame_stage ? 10 : 1;
743 if (color[t] != neutral)
745 /* Captures */
746 if (in_endgame_stage)
748 s += relative_value[board[t]] - relative_value[piece];
750 else
752 s += (*value)[stage][board[t]] - relative_value[piece];
755 if (t == TOsquare) /* Capture of last moved piece */
756 s += in_endgame_stage ? 5 : 50;
759 if (local_flag & promote)
761 /* bonus for promotions */
762 s++;
763 INCscore += value[stage][promoted[piece]] - value[stage][piece];
765 else
767 /* bonus for non-promotions */
768 if (PromotionPossible(side, f, t, piece))
770 #ifdef TESUJIBONUS
771 /* Look at non-promoting silver or knight */
772 if (piece == silver || piece == knight)
774 local_flag |= tesuji; /* Non-promotion */
775 s++;
777 else
778 #endif
780 consider_last = true;
782 if (piece == pawn || piece == bishop || piece == rook)
784 local_flag |= stupid;
785 INCscore -= 20;
787 else
789 local_flag |= questionable;
790 INCscore -= 10;
796 if (consider_last)
798 if (local_flag & stupid)
799 s = 0;
800 else
801 s = s % 20;
803 else
805 #if defined FIELDBONUS
806 s += field_bonus(ply, side, piece, f, t, &local_flag);
807 #endif
811 #if defined CHECKBONUS
812 /* determine check flag */
813 if (!(local_flag & check) && !check_determined)
815 gives_check_flag(&local_flag, side, f, t);
817 if (local_flag & check)
818 s += 20;
820 #endif
822 /* check conditions for deep search cut (flag.tsume = true) */
824 #ifdef DEEPSEARCHCUT
825 if (!flag.tsume && deepsearchcut)
827 if ((ply > BEYOND_STUPID) && (local_flag & stupid))
829 try_link = flag.force || ((ply == 1) && (side != computer));
831 else if (hard_time_limit && (ply > BEYOND_TIMEOUT) && flag.timeout)
833 flag.tsume = true;
835 else if ((ply > BEYOND_KINGATTACK) && !(local_flag & kingattack))
837 flag.tsume = true;
839 else if ((ply > BEYOND_QUESTIONABLE) && (local_flag & questionable))
841 flag.tsume = true;
842 #ifdef TESUJIBONUS
844 else if ((ply > BEYOND_TESUJI) && !(local_flag & tesuji))
846 flag.tsume = true;
847 #endif
849 else if ((ply > BEYOND_DROP) && (f > NO_SQUARES))
851 flag.tsume = true;
854 #endif
856 if (try_link || GenerateAllMoves)
858 Link(side, piece, f, t, local_flag,
859 s - ((SCORE_LIMIT + 1000) * 2));
862 flag.tsume = flag_tsume;
867 short
868 DropPossible(short piece, short side, short sq)
870 short r = row(sq), possible = true;
872 if (board[sq] != no_piece)
874 possible = false;
876 else if (piece == pawn)
878 if ((side == black) && (r == 8))
880 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
882 else if ((side == white) && (r == 0))
884 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
886 else if (PawnCnt[side][column(sq)])
888 possible = (generate_move_flags ? ILLEGAL_DOUBLED : false);
891 /* Pawn drops are invalid if they mate the opponent. */
892 if (possible)
894 short f, tempb, tempc;
895 f = pawn + NO_SQUARES;
897 if (side == white)
898 f += NO_PIECES;
900 GenMakeMove(side, f, sq, &tempb, &tempc, false);
902 if (IsCheckmate(side^1, -1, -1))
903 possible = (generate_move_flags ? ILLEGAL_MATE : false);
905 GenUnmakeMove(side, f, sq, tempb, tempc, false);
908 else if (piece == lance)
910 if ((side == black) && (r == 8))
911 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
912 else if ((side == white) && (r == 0))
913 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
915 else if (piece == knight)
917 if ((side == black) && (r >= 7))
918 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
919 else if ((side == white) && (r <= 1))
920 possible = (generate_move_flags ? ILLEGAL_TRAPPED : false);
923 return possible;
927 #if defined DONTUSE_HEURISTIC
928 static void
929 SortMoves(short ply)
931 short p;
933 for (p = TrPnt[ply]; p < TrPnt[ply+1]; p++)
934 pick(p, TrPnt[ply+1] - 1);
936 #endif /* DONTUSE_HEURISTIC */
939 #ifdef DONTUSE_HEURISTIC
941 static void
942 DontUseMoves(short ply, short n)
944 struct leaf *p;
945 short i, k;
947 /* k = number of check moves + number of captures */
948 for (i = TrPnt[ply], k = 0; i < TrPnt[ply+1]; i++)
950 p = &Tree[i];
952 if ((p->flags & check) || (p->flags & capture))
954 if (++k >= n)
955 return;
959 /* use n moves */
960 for (i = TrPnt[ply]; i < TrPnt[ply+1]; i++)
962 p = &Tree[i];
964 if (!((p->flags & check) || (p->flags & capture)))
966 if (k < n)
967 k++;
968 else
970 p->score = DONTUSE;
976 #endif
981 * Generate moves for a piece. The moves are taken from the precalculated
982 * array nextpos/nextdir. If the board is free, next move is chosen from
983 * nextpos else from nextdir.
986 inline void
987 GenMoves(short ply, short sq, short side,
988 short xside)
990 short u, piece;
991 short ptyp, possible;
992 #ifdef SAVE_NEXTPOS
993 short d;
994 #else
995 unsigned char *ppos, *pdir;
996 #endif
998 piece = board[sq];
999 ptyp = ptype[side][piece];
1001 #ifdef SAVE_NEXTPOS
1002 u = first_direction(ptyp, &d, sq);
1003 #else
1004 ppos = (*nextpos[ptyp])[sq];
1005 pdir = (*nextdir[ptyp])[sq];
1006 u = ppos[sq];
1007 #endif
1011 unsigned short local_flag;
1012 short c;
1014 if ((c = color[u]) == xside)
1015 local_flag = capture;
1016 else
1017 local_flag = 0;
1019 if (c != side && board[u] != king)
1021 if (PromotionPossible(color[sq], sq, u, piece))
1023 LinkMove(ply, sq, u, local_flag | promote, xside, true);
1025 if ((possible
1026 = NonPromotionPossible(color[sq], sq, u, piece)))
1028 LinkMove(ply, sq, u, local_flag, xside, possible);
1031 else
1033 LinkMove(ply, sq, u, local_flag, xside, true);
1037 if (c == neutral)
1038 #ifdef SAVE_NEXTPOS
1040 u = next_position(ptyp, &d, sq, u);
1042 else
1044 u = next_direction(ptyp, &d, sq);
1046 #else
1048 u = ppos[u];
1050 else
1052 u = pdir[u];
1054 #endif
1056 while (u != sq);
1063 * Drop each piece in hand of "side" to square "u" (if allowed).
1066 static void
1067 DropToSquare(short side, short xside, short ply, short u)
1069 short i, possible;
1071 for (i = pawn; i < king; i++)
1073 if (Captured[side][i])
1075 if ((possible = DropPossible(i, side, u)))
1077 short f;
1078 f = NO_SQUARES + i;
1080 if (side == white)
1081 f += NO_PIECES;
1083 LinkMove(ply, f, u, (dropmask | i), xside, possible);
1092 * Add drops of side that prevent own king from being in check
1093 * from xside's sweeping pieces.
1096 static void
1097 LinkPreventCheckDrops(short side, short xside, short ply)
1099 #ifdef SAVE_NEXTPOS
1100 short d, dd;
1101 #else
1102 unsigned char *ppos, *pdir;
1103 #endif
1104 short piece, u, xu, square, ptyp;
1105 short n, drop_square[9];
1107 if (board[square = PieceList[side][0]] != king)
1108 return;
1110 for (piece = lance; piece <= rook; piece++)
1112 if (piece == lance || piece == bishop || piece == rook)
1114 /* check for threat of xside piece */
1115 ptyp = ptype[side][piece];
1116 n = 0;
1117 #ifdef SAVE_NEXTPOS
1118 u = first_direction(ptyp, &d, square);
1119 #else
1120 ppos = (*nextpos[ptyp])[square];
1121 pdir = (*nextdir[ptyp])[square];
1122 u = ppos[square];
1123 #endif
1127 if (color[u] == neutral)
1129 #ifdef SAVE_NEXTPOS
1130 dd = d;
1131 xu = next_position(ptyp, &d, square, u);
1133 if (xu == next_direction(ptyp, &dd, square))
1135 n = 0; /* oops new direction */
1137 else
1139 drop_square[n++] = u;
1141 #else
1143 if ((xu = ppos[u]) == pdir[u])
1145 n = 0; /* oops new direction */
1147 else
1149 drop_square[n++] = u;
1151 #endif
1152 u = xu;
1154 else
1156 if (color[u] == xside && (unpromoted[board[u]] == piece))
1158 /* king is threatened by opponents piece */
1159 while (n > 0)
1161 DropToSquare(side, xside, ply, drop_square[--n]);
1164 else
1166 n = 0;
1168 #ifdef SAVE_NEXTPOS
1169 u = next_direction(ptyp, &d, square);
1170 #else
1171 u = pdir[u];
1172 #endif
1175 while (u != square);
1183 * Add drops that check enemy king.
1186 static void
1187 LinkCheckDrops(short side, short xside, short ply)
1189 #ifdef SAVE_NEXTPOS
1190 short d;
1191 #else
1192 unsigned char *ppos, *pdir;
1193 #endif
1194 short u, ptyp;
1195 short square, piece;
1197 if (board[square = PieceList[xside][0]] != king)
1198 return;
1200 for (piece = pawn; piece < king; piece++)
1202 if (Captured[side][piece])
1205 * "side" has "piece" in hand. Try to make a piece move from
1206 * opponents king square and drop this piece to each reachable
1207 * empty square. This definitely gives check! For a pawn drop
1208 * it must not double pawns and it must not be checkmate!
1211 ptyp = ptype[xside][piece];
1212 #ifdef SAVE_NEXTPOS
1213 u = first_direction(ptyp, &d, square);
1214 #else
1215 ppos = (*nextpos[ptyp])[square];
1216 pdir = (*nextdir[ptyp])[square];
1217 u = ppos[square];
1218 #endif
1221 if (color[u] == neutral)
1223 if (piece != pawn || DropPossible(pawn, side, u))
1225 short f;
1226 f = NO_SQUARES + piece;
1228 if (side == white)
1229 f += NO_PIECES;
1231 LinkMove(ply, f, u,
1232 (dropmask | piece | check), xside, true);
1235 #ifdef SAVE_NEXTPOS
1236 u = next_position(ptyp, &d, square, u);
1237 #else
1238 u = ppos[u];
1239 #endif
1241 else
1243 #ifdef SAVE_NEXTPOS
1244 u = next_direction(ptyp, &d, square);
1245 #else
1246 u = pdir[u];
1247 #endif
1250 while (u != square);
1258 * Fill the array Tree[] with all available moves for side to play. Array
1259 * TrPnt[ply] contains the index into Tree[] of the first move at a ply.
1260 * in_check = 0 side is not in check
1261 * in_check > 1 side is in check
1262 * in_check < 0 don't know
1263 * in_check -2 indicates move generation for book moves
1266 void
1267 MoveList(short side, short ply,
1268 short in_check, short blockable)
1270 short i, xside, u;
1271 struct leaf *firstnode;
1272 short flag_tsume, num;
1274 #ifdef HISTORY
1275 unsigned short hiHt = 0, hi0 = 0, hi1 = 0, hi2 = 0, hi3 = 0, hi4 = 0;
1276 #endif
1278 flag_tsume = flag.tsume;
1280 xside = side ^ 1;
1282 sqking = PieceList[side][0];
1283 sqxking = PieceList[xside][0];
1285 if (in_check >= 0)
1287 InCheck = in_check;
1289 else
1291 InCheck = (board[sqking] == king)
1292 ? SqAttacked(sqking, xside, &blockable)
1293 : false;
1296 GenerateAllMoves = (in_check == -2) || generate_move_flags;
1298 if (InCheck /* && (ply > 1 || side == computer) */)
1300 /* Own king in check */
1301 flag.tsume = true;
1304 TrP = &TrPnt[ply + 1];
1305 *TrP = TrPnt[ply];
1307 firstnode = node = &Tree[*TrP];
1309 if (!PV)
1310 Swag0 = killr0[ply];
1311 else
1312 Swag0 = PV;
1314 Swag1 = killr1[ply];
1315 Swag2 = killr2[ply];
1316 Swag3 = killr3[ply];
1318 if (ply > 2)
1319 Swag4 = killr1[ply - 2];
1320 else
1321 Swag4 = 0;
1323 #ifdef HISTORY
1324 if (use_history)
1326 history[hiHt = hindex(side, SwagHt)] += 5000;
1327 history[hi0 = hindex(side, Swag0)] += 2000;
1328 history[hi1 = hindex(side, Swag1)] += 60;
1329 history[hi2 = hindex(side, Swag2)] += 50;
1330 history[hi3 = hindex(side, Swag3)] += 40;
1331 history[hi4 = hindex(side, Swag4)] += 30;
1333 #endif
1335 for (i = PieceCnt[side]; i >= 0; i--)
1336 GenMoves(ply, PieceList[side][i], side, xside);
1338 if (!InCheck || blockable)
1340 if (flag.tsume)
1342 /* special drop routine for tsume problems */
1343 if (InCheck)
1344 LinkPreventCheckDrops(side, xside, ply);
1345 else
1346 LinkCheckDrops(side, xside, ply);
1348 else
1350 for (u = 0; u < NO_SQUARES; u++)
1351 DropToSquare(side, xside, ply, u);
1355 #ifdef HISTORY
1356 if (use_history)
1358 history[hiHt] -= 5000;
1359 history[hi0] -= 2000;
1360 history[hi1] -= 60;
1361 history[hi2] -= 50;
1362 history[hi3] -= 40;
1363 history[hi4] -= 30;
1365 #endif
1367 SwagHt = 0; /* SwagHt is only used once */
1369 if (flag.tsume && node == firstnode)
1370 (*TrP)++;
1372 GenCnt += (num = (TrPnt[ply+1] - TrPnt[ply]));
1374 #ifdef DONTUSE_HEURISTIC
1375 /* remove some nodes in case of wide spread in depth */
1376 if (!flag.tsume && (i = MaxNum[ply]) > 0 && num > i)
1378 SortMoves(ply);
1379 DontUseMoves(ply, i);
1381 #endif
1383 flag.tsume = flag_tsume;
1389 * Fill the array Tree[] with all available captures for side to play. If
1390 * there is a non-promote option, discard the non-promoting move. Array
1391 * TrPnt[ply] contains the index into Tree[] of the first move at a ply.
1392 * If flag.tsume is set, only add captures (but also the non-promoting)
1393 * that threaten the opponents king.
1395 * in_check = 0: side is not in check
1396 * in_check > 1: side is in check
1397 * in_check < 0: we don't know
1400 void
1401 CaptureList(short side, short ply,
1402 short in_check, short blockable)
1404 short u, sq, xside;
1405 #ifdef SAVE_NEXTPOS
1406 short d;
1407 #else
1408 unsigned char *ppos, *pdir;
1409 #endif
1410 short i, piece, flag_tsume;
1411 small_short *PL;
1413 xside = side ^ 1;
1415 TrP = &TrPnt[ply + 1];
1416 *TrP = TrPnt[ply];
1417 node = &Tree[*TrP];
1419 flag_tsume = flag.tsume;
1421 sqking = PieceList[side][0];
1422 sqxking = PieceList[xside][0];
1424 if (in_check >= 0)
1426 InCheck = in_check;
1428 else
1430 InCheck = (board[sqking] == king)
1431 ? SqAttacked(sqking, xside, &blockable)
1432 : false;
1435 GenerateAllMoves = (in_check == -2);
1437 if (InCheck && (ply > 1 || side == computer))
1439 /* Own king is in check */
1440 flag.tsume = true;
1443 check_determined = false;
1445 PL = PieceList[side];
1447 for (i = 0; i <= PieceCnt[side]; i++)
1449 short ptyp;
1450 sq = PL[i];
1451 piece = board[sq];
1452 ptyp = ptype[side][piece];
1453 #ifdef SAVE_NEXTPOS
1454 u = first_direction(ptyp, &d, sq);
1455 #else
1456 ppos = (*nextpos[ptyp])[sq];
1457 pdir = (*nextdir[ptyp])[sq];
1458 u = ppos[sq];
1459 #endif
1462 if (color[u] == neutral)
1464 #ifdef SAVE_NEXTPOS
1465 u = next_position(ptyp, &d, sq, u);
1466 #else
1467 u = ppos[u];
1468 #endif
1470 else
1472 if (color[u] == xside && board[u] != king)
1474 short PP;
1476 if ((PP = PromotionPossible(color[sq], sq, u, piece)))
1478 Link(side, piece,
1479 sq, u, capture | promote,
1480 (*value)[stage][board[u]]
1481 #if !defined SAVE_SVALUE
1482 + svalue[board[u]]
1483 #endif
1484 - relative_value[piece]);
1487 if (!PP || flag.tsume)
1489 Link(side, piece,
1490 sq, u, capture,
1491 (*value)[stage][board[u]]
1492 #if !defined SAVE_SVALUE
1493 + svalue[board[u]]
1494 #endif
1495 - relative_value[piece]);
1499 #ifdef SAVE_NEXTPOS
1500 u = next_direction(ptyp, &d, sq);
1501 #else
1502 u = pdir[u];
1503 #endif
1506 while (u != sq);
1509 flag.tsume = flag_tsume;
1511 SwagHt = 0; /* SwagHt is only used once */
1518 * If the king is in check, try to find a move that prevents check.
1519 * If such a move is found, return false, otherwise return true.
1520 * in_check = 0: side is not in check
1521 * in_check > 1: side is in check
1522 * in_check < 0: don't know
1523 * blockable > 0 && check: check can possibly be prevented by a drop
1524 * blockable = 0 && check: check can definitely not be prevented by a drop
1525 * blockable < 0 && check: nothing known about type of check
1528 short
1529 IsCheckmate(short side, short in_check, short blockable)
1531 short u, sq, xside;
1532 #ifdef SAVE_NEXTPOS
1533 short d;
1534 #else
1535 unsigned char *ppos, *pdir;
1536 #endif
1537 short i, piece;
1538 small_short *PL;
1539 short tempb, tempc, ksq, threat, dummy, sqking;
1540 short InCheck;
1542 xside = side ^ 1;
1544 sqking = PieceList[side][0];
1547 * Checkmate is possible only if king is in check.
1550 if (in_check >= 0)
1551 InCheck = in_check;
1552 else if (board[sqking] == king)
1553 InCheck = SqAttacked(sqking, xside, &blockable);
1554 else
1555 InCheck = false;
1557 if (!InCheck)
1558 return false;
1561 * Try to find a move that prevents check.
1564 PL = PieceList[side];
1566 for (i = 0; i <= PieceCnt[side]; i++)
1568 short ptyp;
1569 sq = PL[i];
1570 piece = board[sq];
1571 ptyp = ptype[side][piece];
1572 #ifdef SAVE_NEXTPOS
1573 u = first_direction(ptyp, &d, sq);
1574 #else
1575 ppos = (*nextpos[ptyp])[sq];
1576 pdir = (*nextdir[ptyp])[sq];
1577 u = ppos[sq];
1578 #endif
1581 if (color[u] == neutral || color[u] == xside)
1583 GenMakeMove(side, sq, u, &tempb, &tempc, false);
1584 ksq = (sq == sqking) ? u : sqking;
1585 threat = SqAttacked(ksq, xside, &dummy);
1586 GenUnmakeMove(side, sq, u, tempb, tempc, false);
1588 if (!threat)
1589 return false;
1592 #ifdef SAVE_NEXTPOS
1593 u = (color[u] == neutral)
1594 ? next_position(ptyp, &d, sq, u)
1595 : next_direction(ptyp, &d, sq);
1596 #else
1597 u = (color[u] == neutral) ? ppos[u] : pdir[u];
1598 #endif
1600 while (u != sq);
1604 * Couldn't find a move that prevents check.
1605 * Try to find a drop that prevents check.
1608 if (blockable != 0)
1610 for (piece = king - 1; piece >= pawn; piece--)
1612 if (Captured[side][piece])
1614 for (u = 0; u < NO_SQUARES; u++)
1616 if (DropPossible(piece, side, u))
1618 short f;
1619 f = NO_SQUARES + piece;
1621 if (side == white)
1622 f += NO_PIECES;
1624 GenMakeMove(side, f, u, &tempb, &tempc, false);
1625 threat = SqAttacked(sqking, xside, &dummy);
1626 GenUnmakeMove(side, f, u, tempb, tempc, false);
1628 if (!threat)
1629 return false;
1634 * If the piece could be dropped at any square, it is
1635 * impossible for any other piece drop to prevent check.
1636 * Drops are restricted for pawns, lances, and knights.
1639 if (piece > knight)
1640 break;
1645 return true;