Changing license to GPL3 (and bumping version to 1.4.0).
[gnushogi.git] / gnushogi / makepattern.c
1 /*
2  * FILE: makepattern.c
3  *
4  * ----------------------------------------------------------------------
5  *
6  * Copyright (c) 2012 Free Software Foundation
7  *
8  * GNU SHOGI is based on GNU CHESS
9  *
10  * This file is part of GNU SHOGI.
11  *
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.
16  *
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.
21  *
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  * ----------------------------------------------------------------------
26  *
27  */
28
29 #include "gnushogi.h"
30 #include "pattern.h"
31
32 #define MAX_PATTERN_DATA     5000
33 #define MAX_OPENING_SEQUENCE 20
34 #define MAX_PATTERN          200
35
36 char *patternfile = PATTERNFILE;
37
38 #define is_digit(c) (((c) >= '0') && ((c) <= '9'))
39 #define is_alpha(c) ((((c) >= 'a') && ((c) <= 'z')) \
40     || (((c) >= 'A') && ((c) <= 'Z')))
41 #define eos(s)      ((*s == '\0') || (*s == '\n'))
42
43
44 /* skip blanks and comments in brackets */
45
46 static void
47 skipbb(char **s)
48 {
49     while ((**s == ' ') || (**s == '|') || (**s == '['))
50     {
51         if (**s == '[')
52         {
53             while (**s != ']')
54                 (*s)++;
55         }
56
57         (*s)++;
58     }
59 }
60
61
62 /* skip unsigned numbers */
63
64 static void
65 skipi(char **s)
66 {
67     while (is_digit(**s))
68         (*s)++;
69
70     skipbb(s);
71 }
72
73
74 static short
75 ScanPiece(char **s, small_short *side,
76           small_short *piece, small_short *square)
77 {
78     short isp, isw, c, r;
79
80     /* determine promotion status */
81     if (**s == '+')
82         isp = true, (*s)++;  /* FIXME: split into two lines. */
83     else
84         isp = false;
85
86     /* determine side and piece */
87     for (c = 0; c < NO_PIECES; c++)
88     {
89         if ((isw = (**s == pxx[c])) || (**s == qxx[c]))
90         {
91             *piece = isp ? promoted[c] : unpromoted[c];
92             *side  = isw;
93             (*s)++;
94             break;
95         }
96     }
97
98     if (c == NO_PIECES)
99         return 1;
100
101     if (**s == '*')
102     {
103         /* piece is captured */
104         (*s)++;
105         *square = NO_SQUARES + *piece;
106     }
107     else
108     {
109         /* determine column */
110         for (c = 0; c < NO_COLS; c++)
111         {
112             if (**s == cxx[c])
113             {
114                 (*s)++;
115                 break;
116             }
117         }
118
119         if (c >= NO_COLS)
120             return 1;
121
122         /* determine row */
123         for (r = 0; r < NO_ROWS; r++)
124         {
125             if (**s == rxx[r])
126             {
127                 (*s)++;
128                 break;
129             }
130         }
131
132         if (r >= NO_ROWS)
133             return 1;
134
135         /* determine square */
136         *square = r * NO_COLS + c;
137     }
138
139     skipbb(s);
140     return 0;
141 }
142
143
144 static short
145 ScanPattern (char *s, short *pindex)
146 {
147     small_short side, piece, square;
148     skipbb(&s); /* skip blanks and comments */
149
150     while (is_digit(*s))
151     {
152         pattern_data[(*pindex)++] = atoi(s);
153         skipi(&s);
154     }
155
156     pattern_data[(*pindex)++] = END_OF_LINKS;
157     skipbb(&s);
158
159     while (!eos(s))
160     {
161         if (ScanPiece(&s, &side, &piece, &square))
162         {
163             return 1;
164         }
165         else
166         {
167             pattern_data[(*pindex)++] = piece;
168             pattern_data[(*pindex)++] = (side ? -square : square);
169         }
170
171     }
172
173     pattern_data[(*pindex)++] = END_OF_FIELDS;
174     return 0;
175 }
176
177
178 void
179 ReadOpeningSequences (short *pindex)
180
181 {
182     FILE *fd;
183     char s[256];
184     short max_pattern = 0;
185     short max_opening_sequence = 0;
186
187     if ((fd = fopen (patternfile, "r")) == NULL)
188         fd = fopen ("gnushogi.pat", "r");
189
190     if (fd != NULL)
191     {
192         *pindex = 0;
193
194         while (fgets (s, 256, fd) != NULL)
195         {
196             if (*s == '#')
197             {
198                 /* comment, skip line */
199             }
200             else if (is_alpha(*s))
201             {
202                 if (max_opening_sequence++ > 0)
203                 {
204                     pattern_data[(*pindex)++] = END_OF_PATTERNS;
205                 }
206
207                 pattern_data[(*pindex)++] = ValueOfOpeningName(s);
208             }
209             else
210             {
211                 if (ScanPattern(s, pindex))
212                 {
213                     ShowMessage("error in pattern sequence...");
214                     exit(1);
215                 }
216                 else
217                 {
218                     max_pattern++;
219                 }
220             }
221         }
222
223         pattern_data[(*pindex)++] = END_OF_PATTERNS;
224         pattern_data[(*pindex)++] = END_OF_SEQUENCES;
225
226         if (NOT_CURSES)
227         {
228             sprintf(s,
229                     "Pattern: %d bytes for %d sequences with %d patterns.\n",
230                     *pindex, max_opening_sequence, max_pattern);
231             ShowMessage(s);
232         }
233         fclose(fd);
234     }
235     else if (NOT_CURSES)
236     {
237         sprintf(s, "no pattern file '%s'", patternfile);
238         ShowMessage(s);
239     }
240 }
241
242
243 void
244 WriteOpeningSequences (short pindex)
245 {
246     FILE *fd;
247     short n = 0;
248     short max_pattern = 0;
249     short max_opening_sequence = 0;
250
251     fd = fopen ("pattern.inc", "w");
252     fprintf(fd, "#define MAX_PATTERN_DATA %d\n\n", pindex);
253     fprintf(fd, "small_short pattern_data[MAX_PATTERN_DATA] =\n{\n");
254
255     do
256     {
257         fprintf(fd, "  %d,\n", pattern_data[n++]);
258
259         do
260         {
261             fprintf(fd, "    ");
262
263             /* write links */
264             while (pattern_data[n] != END_OF_LINKS)
265             {
266                 fprintf(fd, "%d, ", pattern_data[n++]);
267             };
268
269             fprintf(fd, "%d, ", pattern_data[n++]);
270
271             /* write pattern */
272             do
273             {
274                 fprintf(fd, "%d,", pattern_data[n++]);
275             }
276             while (pattern_data[n] != END_OF_FIELDS);
277
278             fprintf(fd, "%d,\n", pattern_data[n++]);
279             max_pattern++;
280         }
281         while (pattern_data[n] != END_OF_PATTERNS);
282
283         fprintf(fd, "    %d,\n", pattern_data[n++]);
284         max_opening_sequence++;
285     }
286     while (pattern_data[n] != END_OF_SEQUENCES);
287
288     fprintf(fd, "  %d\n}; \n", pattern_data[n++]);
289     fprintf(fd, "\n#define MAX_OPENING_SEQUENCE %d\n", max_opening_sequence);
290     fprintf(fd, "\n#define MAX_PATTERN %d\n", max_pattern);
291     fclose(fd);
292 }
293
294