Make ShowMessage stdarg-enabled.
[gnushogi.git] / gnushogi / makepattern.c
1 /*
2  * FILE: makepattern.c
3  *
4  * ----------------------------------------------------------------------
5  * Copyright (c) 1993, 1994, 1995 Matthias Mutz
6  * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
7  * Copyright (c) 2008, 2013, 2014 Yann Dirson and the Free Software Foundation
8  *
9  * GNU SHOGI is based on GNU CHESS
10  *
11  * Copyright (c) 1988, 1989, 1990 John Stanback
12  * Copyright (c) 1992 Free Software Foundation
13  *
14  * This file is part of GNU SHOGI.
15  *
16  * GNU Shogi is free software; you can redistribute it and/or modify it
17  * under the terms of the GNU General Public License as published by the
18  * Free Software Foundation; either version 3 of the License,
19  * or (at your option) any later version.
20  *
21  * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
22  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with GNU Shogi; see the file COPYING. If not, see
28  * <http://www.gnu.org/licenses/>.
29  * ----------------------------------------------------------------------
30  *
31  */
32
33 #include "gnushogi.h"
34 #include "pattern.h"
35
36 #define MAX_PATTERN_DATA     5000
37 #define MAX_OPENING_SEQUENCE 20
38 #define MAX_PATTERN          200
39
40 short xboard = false;
41
42 small_short pattern_data[MAX_PATTERN_DATA];
43
44 /* minimal ShowMessage to avoid dependency on extraneous display code */
45 static void
46 Dummy_ShowMessage(char *format, ...)
47 {
48     va_list ap;
49     va_start(ap, format);
50     vprintf(format, ap);
51     va_end(ap);
52 }
53 static struct display dummydsp = {
54   .ShowMessage = Dummy_ShowMessage,
55 };
56 struct display *dsp = &dummydsp;
57
58 #define is_digit(c) (((c) >= '0') && ((c) <= '9'))
59 #define is_alpha(c) ((((c) >= 'a') && ((c) <= 'z')) \
60     || (((c) >= 'A') && ((c) <= 'Z')))
61 #define eos(s)      ((*s == '\0') || (*s == '\n'))
62
63
64 /* skip blanks and comments in brackets */
65
66 static void
67 skipbb(char **s)
68 {
69     while ((**s == ' ') || (**s == '|') || (**s == '['))
70     {
71         if (**s == '[')
72         {
73             while (**s != ']')
74                 (*s)++;
75         }
76
77         (*s)++;
78     }
79 }
80
81
82 /* skip unsigned numbers */
83
84 static void
85 skipi(char **s)
86 {
87     while (is_digit(**s))
88         (*s)++;
89
90     skipbb(s);
91 }
92
93
94 static short
95 ScanPiece(char **s, small_short *side,
96           small_short *piece, small_short *square)
97 {
98     short isp, isw, c, r;
99
100     /* determine promotion status */
101     if (**s == '+')
102         isp = true, (*s)++;  /* FIXME: split into two lines. */
103     else
104         isp = false;
105
106     /* determine side and piece */
107     for (c = 0; c < NO_PIECES; c++)
108     {
109         if ((isw = (**s == pxx[c])) || (**s == qxx[c]))
110         {
111             *piece = isp ? promoted[c] : unpromoted[c];
112             *side  = isw;
113             (*s)++;
114             break;
115         }
116     }
117
118     if (c == NO_PIECES)
119         return 1;
120
121     if (**s == '*')
122     {
123         /* piece is captured */
124         (*s)++;
125         *square = NO_SQUARES + *piece;
126     }
127     else
128     {
129         /* determine column */
130         for (c = 0; c < NO_COLS; c++)
131         {
132             if (**s == COL_NAME(c))
133             {
134                 (*s)++;
135                 break;
136             }
137         }
138
139         if (c >= NO_COLS)
140             return 1;
141
142         /* determine row */
143         for (r = 0; r < NO_ROWS; r++)
144         {
145             if (**s == ROW_NAME(r))
146             {
147                 (*s)++;
148                 break;
149             }
150         }
151
152         if (r >= NO_ROWS)
153             return 1;
154
155         /* determine square */
156         *square = r * NO_COLS + c;
157     }
158
159     skipbb(s);
160     return 0;
161 }
162
163
164 static short
165 ScanPattern (char *s, short *pindex)
166 {
167     small_short side, piece, square;
168     skipbb(&s); /* skip blanks and comments */
169
170     while (is_digit(*s))
171     {
172         pattern_data[(*pindex)++] = atoi(s);
173         skipi(&s);
174     }
175
176     pattern_data[(*pindex)++] = END_OF_LINKS;
177     skipbb(&s);
178
179     while (!eos(s))
180     {
181         if (ScanPiece(&s, &side, &piece, &square))
182         {
183             return 1;
184         }
185         else
186         {
187             pattern_data[(*pindex)++] = piece;
188             pattern_data[(*pindex)++] = (side ? -square : square);
189         }
190
191     }
192
193     pattern_data[(*pindex)++] = END_OF_FIELDS;
194     return 0;
195 }
196
197
198 void
199 ReadOpeningSequences (short *pindex, const char* patternfile)
200 {
201     FILE *fd;
202     char s[256];
203     short max_pattern = 0;
204     short max_opening_sequence = 0;
205
206     fd = fopen (patternfile, "r");
207
208     if (fd == NULL) {
209         sprintf(s, "no pattern file '%s'", patternfile);
210         dsp->ShowMessage(s);
211         return;
212     }
213
214     *pindex = 0;
215
216     while (fgets (s, 256, fd) != NULL)
217     {
218         if (*s == '#')
219         {
220             /* comment, skip line */
221         }
222         else if (is_alpha(*s))
223         {
224             if (max_opening_sequence++ > 0)
225             {
226                 pattern_data[(*pindex)++] = END_OF_PATTERNS;
227             }
228
229             pattern_data[(*pindex)++] = ValueOfOpeningName(s);
230         }
231         else
232         {
233             if (ScanPattern(s, pindex))
234             {
235                 dsp->ShowMessage("error in pattern sequence...");
236                 exit(1);
237             }
238             else
239             {
240                 max_pattern++;
241             }
242         }
243     }
244
245     pattern_data[(*pindex)++] = END_OF_PATTERNS;
246     pattern_data[(*pindex)++] = END_OF_SEQUENCES;
247
248     sprintf(s,
249             "Pattern: %d bytes for %d sequences with %d patterns.\n",
250             *pindex, max_opening_sequence, max_pattern);
251     dsp->ShowMessage(s);
252
253     fclose(fd);
254 }
255
256
257 void
258 WriteOpeningSequences (short pindex, const char* patternincfile)
259 {
260     FILE *fd;
261     short n = 0;
262     short max_pattern = 0;
263     short max_opening_sequence = 0;
264
265     fd = fopen (patternincfile, "w");
266     fprintf(fd, "#define MAX_PATTERN_DATA %d\n\n", pindex);
267     fprintf(fd, "small_short pattern_data[MAX_PATTERN_DATA] =\n{\n");
268
269     do
270     {
271         fprintf(fd, "  %d,\n", pattern_data[n++]);
272
273         do
274         {
275             fprintf(fd, "    ");
276
277             /* write links */
278             while (pattern_data[n] != END_OF_LINKS)
279             {
280                 fprintf(fd, "%d, ", pattern_data[n++]);
281             };
282
283             fprintf(fd, "%d, ", pattern_data[n++]);
284
285             /* write pattern */
286             do
287             {
288                 fprintf(fd, "%d,", pattern_data[n++]);
289             }
290             while (pattern_data[n] != END_OF_FIELDS);
291
292             fprintf(fd, "%d,\n", pattern_data[n++]);
293             max_pattern++;
294         }
295         while (pattern_data[n] != END_OF_PATTERNS);
296
297         fprintf(fd, "    %d,\n", pattern_data[n++]);
298         max_opening_sequence++;
299     }
300     while (pattern_data[n] != END_OF_SEQUENCES);
301
302     fprintf(fd, "  %d\n}; \n", pattern_data[n++]);
303     fprintf(fd, "\n#define MAX_OPENING_SEQUENCE %d\n", max_opening_sequence);
304     fprintf(fd, "\n#define MAX_PATTERN %d\n", max_pattern);
305     fclose(fd);
306 }
307
308