4 * ----------------------------------------------------------------------
5 * Copyright (c) 1993, 1994, 1995 Matthias Mutz
6 * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
8 * GNU SHOGI is based on GNU CHESS
10 * Copyright (c) 1988, 1989, 1990 John Stanback
11 * Copyright (c) 1992 Free Software Foundation
13 * This file is part of GNU SHOGI.
15 * GNU Shogi is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 3 of the License,
18 * or (at your option) any later version.
20 * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
21 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 * You should have received a copy of the GNU General Public License along
26 * with GNU Shogi; see the file COPYING. If not, see
27 * <http://www.gnu.org/licenses/>.
28 * ----------------------------------------------------------------------
35 /* constants and pattern_data are generated by "pat2inc" */
37 # include "gnushogi-pattern.inc"
39 # include "gnuminishogi-pattern.inc"
42 struct Pattern_rec Pattern[MAX_PATTERN];
43 struct OpeningSequence_rec OpeningSequence[MAX_OPENING_SEQUENCE];
45 small_short pattern_data[MAX_PATTERN_DATA];
49 NameOfOpeningValue (short i, char *name)
53 strcpy(name, "CASTLE_?_?");
57 strcpy(name, "ATTACK_?_?");
102 GetOpeningPatterns (short *max_opening_sequence)
111 OpeningSequence[os].opening_type = pattern_data[pindex++];
112 OpeningSequence[os].first_pattern[0] = p;
114 for (i = 1; i < MAX_SEQUENCE; i++)
115 OpeningSequence[os].first_pattern[i] = END_OF_PATTERNS;
119 Pattern[p].reachedGameCnt[black] = MAXMOVES;
120 Pattern[p].reachedGameCnt[white] = MAXMOVES;
121 Pattern[p].first_link = pindex;
123 while (pattern_data[pindex] != END_OF_LINKS)
127 Pattern[p].first_field = pindex;
129 while (pattern_data[pindex] != END_OF_FIELDS)
133 if (pattern_data[pindex] != END_OF_PATTERNS)
134 Pattern[p].next_pattern = p + 1;
136 Pattern[p].next_pattern = END_OF_PATTERNS;
140 while (pattern_data[pindex] != END_OF_PATTERNS);
145 while (pattern_data[pindex] != END_OF_SEQUENCES);
147 *max_opening_sequence = os;
153 ShowOpeningPatterns (short max_opening_sequence)
157 for (os = 0; os < max_opening_sequence; os++)
160 NameOfOpeningValue(OpeningSequence[os].opening_type, name);
161 printf("Opening Type: %s\n", name);
163 for (p = OpeningSequence[os].first_pattern[0], n = 0;
164 p != END_OF_PATTERNS;
165 p = Pattern[p].next_pattern, n++)
167 printf("Pattern %d (%d) with links ", p, n);
169 for (i = Pattern[p].first_link;
170 pattern_data[i] != END_OF_LINKS;
173 printf("%d ", pattern_data[i]);
177 DisplayPattern(stdout, Pattern[p].first_field);
185 set_field (short i, struct PatternField *field)
187 field->piece = pattern_data[i];
188 field->square = pattern_data[i+1];
190 if (field->square < 0)
192 field->square = -(field->square);
204 * piece_to_pattern_distance (side, piece, pside, pattern)
206 * Determine the minimum number of moves from the current position to a
207 * specific pattern for a specific piece. Consider the "side" piece of the
208 * pattern. The pattern should match for "pside".
212 piece_to_pattern_distance(short side, short piece,
213 short pside, short pattern)
215 short nP, P[4], nB, B[4]; /* at most 4 pieces of same kind */
216 short i, j, r, dd, occupied, mindd, c[4], d[4];
217 /* a "side" patternfield must match a "c1" piece on board: */
218 short c1 = side ^ pside;
221 * If pside == white, a black piece in the pattern should match a white
222 * piece on board, and vice versa. Furthermore, if pside == white,
223 * reversed pattern should match board.
226 /* special pawn handling */
230 mindd = occupied = 0;
232 for (i = Pattern[pattern].first_field;
233 pattern_data[i] != END_OF_FIELDS;
236 struct PatternField field;
237 set_field(i, &field);
239 if ((field.side == side) && (field.piece == pawn))
241 short t = field.square;
242 short pcol = column(t);
245 if (PawnCnt[c1][(side == c1) ? pcol : (8 - pcol)])
247 /* there is a pawn on the column */
248 for (j = 0; j <= PieceCnt[c1]; j++)
250 short sq = (short)PieceList[c1][j];
252 if (board[sq] == pawn)
255 sq = NO_SQUARES - 1 - sq;
257 if (column(sq) == pcol)
259 dd = piece_distance (side, pawn, sq, t);
261 printf("update %d pawn "
262 "from %d to %d is %d\n",
272 /* there is no pawn on the column; drop possible? */
273 if (Captured[c1][pawn])
277 printf("update %d pawn drop to %d is %d\n",
285 /* Increment distance if pattern field is occupied */
295 psq = (NO_SQUARES - 1 - t);
299 if ((color[psq] == pc) && (board[psq] != pawn))
302 printf("square %d is occupied\n", psq);
316 return mindd + occupied;
320 * Determine list of "side" "piece"s in pattern.
323 for (occupied = nP = 0, i = Pattern[pattern].first_field;
324 pattern_data[i] != END_OF_FIELDS;
327 struct PatternField field;
328 set_field(i, &field);
330 if ((field.side == side) && (field.piece == piece))
333 P[nP] = field.square;
335 printf("pattern %d piece %d on square %d\n", side, piece, P[nP]);
339 /* Increment distance if pattern field is occupied */
347 psq = NO_SQUARES - 1 - field.square;
351 if ((color[psq] == pc) && (board[psq] != field.piece))
354 printf("square %d is occupied\n", psq);
365 printf("finding in pattern %d pieces %d of side %d\n", nP, piece, side);
369 * Determine list of "side ^ pside" "piece"s captured or on board.
372 for (nB = 0; nB < Captured[c1][piece]; nB++)
373 B[nB] = NO_SQUARES + piece;
375 for (i = 0; i <= PieceCnt[c1]; i++)
377 short sq = PieceList[c1][i];
379 if (board[sq] == piece)
381 B[nB] = (pside == black) ? sq : (NO_SQUARES - 1 - sq);
383 printf("%d piece %d on square %d\n", side, piece, B[nB]);
390 printf("found on board %d pieces %d of side %d\n", nB, piece, side);
398 /* Determine best assignment from board piece to pattern piece */
402 mindd = CANNOT_REACH;
404 while ((r >= 0) && (mindd != 0))
413 for (i = 0; i < r; i++)
421 d[r] = piece_distance (side, piece, B[c[r]], P[r]);
423 printf("update d[%d] from %d to %d is %d\n",
424 r, B[c[r]], P[r], d[r]);
434 for (dd = i = 0; i < nP; i++)
437 if ((dd < mindd) || (mindd < 0))
441 printf("update min %d\n", mindd);
459 return (mindd + occupied);
466 * pattern_distance (pside, pattern)
468 * Determine the minimum number of moves for the pieces from
469 * the current position to reach a pattern.
470 * The result is CANNOT_REACH, if there is no possible sequence
476 pattern_distance (short pside, short pattern)
478 short side, piece, d, n;
481 printf("\nchecking pattern %d for pside=%d\n\n", pattern, pside);
484 for (n = side = 0; side <= 1 && n >= 0; side++)
486 for (piece = pawn; piece <= king; piece++)
488 d = piece_to_pattern_distance (side, piece, pside, pattern);
503 printf("\ndistance to pattern is %d\n\n", n);
512 * board_to_pattern_distance(pside, osequence, pmplty, GameCnt)
514 * Determine the maximal difference of the number of moves from the pattern
515 * to the initial position and to the current position.
516 * Differences are weighted, i.e. the more closer a position is to a pattern
517 * the more valuable is a move towards the pattern.
518 * Patterns, which are at least "pmplty" halfmoves away, are not counted.
522 board_to_pattern_distance
523 (short pside, short osequence, short pmplty, short GameCnt)
525 short i, d, dist, diff, weighted_diff;
526 short maxdiff = 0, max_weighted_diff = 0;
529 for (i = 0; i < MAX_SEQUENCE; i++)
531 for (pattern = OpeningSequence[osequence].first_pattern[i];
532 pattern != END_OF_PATTERNS;
533 pattern = Pattern[pattern].next_pattern)
535 if ((d = Pattern[pattern].distance[pside]) >= 0)
539 dist = pattern_distance (pside, pattern);
543 * "dist" is the distance of the current board
544 * position to the pattern. "d - dist" is the
545 * difference between the current distance and the
546 * initial distance. Compute "diff" as the weighted
550 /* try to reach the nearest pattern */
551 weighted_diff = (diff = (d - dist)) * (pmplty - d);
553 if (weighted_diff > max_weighted_diff)
558 maxdiff = weighted_diff;
560 max_weighted_diff = weighted_diff;
564 * A reached pattern should not be considered in
565 * the future (if GameCnt >= 0)
568 if (dist == 0 && GameCnt >= 0)
569 Pattern[pattern].reachedGameCnt[pside] = GameCnt;
583 DisplayPattern (FILE *fd, short n)
585 small_short pboard[NO_SQUARES], pcolor[NO_SQUARES];
588 for (sq = 0; sq < NO_SQUARES; sq++)
590 pboard[sq] = no_piece;
591 pcolor[sq] = neutral;
594 for (i = n; pattern_data[i] != END_OF_FIELDS; i += 2)
596 struct PatternField field;
597 set_field(i, &field);
598 pboard[field.square] = field.piece;
599 pcolor[field.square] = field.side;
602 for (r = NO_ROWS - 1; r >= 0; r--)
604 for (c = 0; c < NO_COLS; c++)
612 fprintf(fd, "%c%c", is_promoted[i] ? '+' : ' ',
613 pcolor[sq] ? pxx[i] : qxx[i]);
626 VisitReachable (int pside, short osequence, int k, int n, int remove)
631 /* Adjust to sequence pattern n */
632 for (i = 0, pattern = OpeningSequence[osequence].first_pattern[k];
635 pattern = Pattern[pattern].next_pattern;
638 /* do not perform visited link twice */
639 if (Pattern[pattern].visited)
645 Pattern[pattern].visited = true;
648 /* Declare links unreachable */
649 for (j = Pattern[pattern].first_link;
650 pattern_data[j] != END_OF_LINKS; j++)
652 VisitReachable(pside, osequence, k, pattern_data[j], remove);
655 /* Declare unreachable */
656 if (remove && Pattern[pattern].distance[pside] >= 0)
658 Pattern[pattern].distance[pside] = IS_SUCCESSOR;
663 /* simplified matching for opening type names */
665 #define match_char(a, b) \
666 (a == b || (a == '*' && b != 'U') || (b == '*' && a != 'U'))
668 #define match_name(a, b, l) \
669 (l > 8 && match_char(a[0], b[0]) && match_char(a[7], b[7]) \
670 && match_char(a[9], b[9]))
674 locate_opening_sequence(short pside, char *s, short GameCnt)
676 short i, j, k, os, d;
678 short check_visited[MAX_SEQUENCE];
679 char name[MAX_NAME], name2[MAX_NAME];
682 * Look for opening pattern name in the list of opening patterns.
687 for (i = 1, os = 0; os < MAX_OPENING_SEQUENCE; os++)
689 /* locate matching opening type name */
690 NameOfOpeningValue(OpeningSequence[os].opening_type, name);
692 if (match_name(s, name, l))
694 /* locate successor matching names */
695 for (k = os + 1; k < MAX_OPENING_SEQUENCE; k++)
697 NameOfOpeningValue(OpeningSequence[k].opening_type, name2);
699 if (match_name(s, name2, l))
701 OpeningSequence[os].first_pattern[i++]
702 = OpeningSequence[k].first_pattern[0];
710 if (os >= MAX_OPENING_SEQUENCE)
712 return END_OF_SEQUENCES;
716 for (; i < MAX_SEQUENCE;
717 OpeningSequence[os].first_pattern[i++] = END_OF_PATTERNS);
721 * Determine patterns which can be reached from the current
722 * board position. Only patterns which can be reached will be
723 * checked in the following search.
726 for (i = 0; i < MAX_SEQUENCE; i++)
728 check_visited[i] = false;
730 for (k = OpeningSequence[os].first_pattern[i];
731 k != END_OF_PATTERNS;
732 k = Pattern[k].next_pattern)
734 Pattern[k].visited = false;
738 for (i = 0; i < MAX_SEQUENCE; i++)
740 for (k = OpeningSequence[os].first_pattern[i];
741 k != END_OF_PATTERNS;
742 k = Pattern[k].next_pattern)
744 Pattern[k].distance[pside] = pattern_distance(pside, k);
746 /* Actually reached patterns need not to be observed. */
747 if (Pattern[k].distance[pside] == 0)
749 Pattern[k].distance[pside] = CANNOT_REACH;
750 check_visited[i] = Pattern[k].visited = true;
752 for (j = Pattern[k].first_link;
753 pattern_data[j] != END_OF_LINKS; j++)
755 VisitReachable(pside, os, i, pattern_data[j], false);
758 else if ((GameCnt >= 0)
759 && (GameCnt >= Pattern[k].reachedGameCnt[pside]))
761 Pattern[k].distance[pside] = IS_REACHED;
764 if (Pattern[k].reachedGameCnt[pside] >= GameCnt)
765 Pattern[k].reachedGameCnt[pside] = MAXMOVES;
770 * Remove reachable patterns from search, which are successors of
771 * reachable patterns. So, only the next pattern of a pattern sequence
775 for (i = 0; i < MAX_SEQUENCE; i++)
777 for (k = OpeningSequence[os].first_pattern[i];
778 k != END_OF_PATTERNS;
779 k = Pattern[k].next_pattern)
781 if (check_visited[i] && !Pattern[k].visited)
782 Pattern[k].distance[pside] = NOT_TO_REACH;
784 Pattern[k].visited = false;
788 for (i = 0; i < MAX_SEQUENCE; i++)
790 for (k = OpeningSequence[os].first_pattern[i];
791 k != END_OF_PATTERNS;
792 k = Pattern[k].next_pattern)
794 if ((d = Pattern[k].distance[pside]) >= 0)
796 for (j = Pattern[k].first_link;
797 pattern_data[j] != END_OF_LINKS; j++)
799 VisitReachable(pside, os, i, pattern_data[j], true);
806 * Look to see whether there is still a reachable pattern.
809 for (i = 0; i < MAX_SEQUENCE; i++)
811 for (k = OpeningSequence[os].first_pattern[i];
812 k != END_OF_PATTERNS;
813 k = Pattern[k].next_pattern)
815 if ((d = Pattern[k].distance[pside]) >= 0)
820 return END_OF_SEQUENCES;
827 update_advance_bonus (short pside, short os)
829 struct PatternField field;
832 for (j = 0; j < MAX_SEQUENCE; j++)
834 for (k = OpeningSequence[os].first_pattern[j];
835 k != END_OF_PATTERNS;
836 k = Pattern[k].next_pattern)
838 if ((d = Pattern[k].distance[pside]) >= 0)
840 for (i = Pattern[k].first_field;
841 pattern_data[i] != END_OF_FIELDS; i += 2)
843 set_field(i, &field);
844 if (field.side == black)
846 short square = (pside == black)
848 : NO_SQUARES - 1 - field.square;
850 (*Mpiece[field.piece])[pside][square]
851 += ADVNCM[field.piece];