1 /*
2 Sjeng - a chess variants playing program
3 Copyright (C) 2000 Gian-Carlo Pascutto
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 File: book.c
20 Purpose: book initialization, selection of book moves, etc...
21
22 */
23
24 #include "sjeng.h"
25 #include "protos.h"
26 #include "extvars.h"
27
28 char book[4000][161];
29 char book_flags[4000][41];
30 int num_book_lines;
31 int book_ply;
32 int use_book;
33 char opening_history[STR_BUFF];
34
35 #define book_always 1 /* corresponds with ! */
36 #define book_never 2 /* corresponds with ? */
37 #define book_interesting 3 /* !? */
38 #define book_solid 4 /* = */
39 #define book_murky 5 /* ?! */
40
init_book(void)41 int init_book (void) {
42
43 /* simply read all the book moves into a book array. The book will be
44 a simple char[5000][81] array (5000 max book lines, since you can't
45 have *too* many when you're doing this slow strncpy method ;) After
46 all, this is really just a kludge 'till I add hashing, and support
47 transpositions and such ;) Returns true if reading in the book
48 was successful. */
49
50 FILE *f_book;
51 int ch, i = 0, j = 0;
52
53 int tagmode = FALSE; /* recognize multiple tags */
54 int commentmode = FALSE;
55
56 memset(book_flags, 0, sizeof(book_flags));
57 memset(book, 0, sizeof(book));
58
59 num_book_lines = 0;
60
61 /* init our random numbers: */
62 srand((unsigned) time (NULL));
63
64 if (Variant == Normal)
65 {
66 if ((f_book = fopen ("normal.opn", "r")) == NULL)
67 return FALSE;
68 }
69 else if (Variant == Crazyhouse)
70 {
71 if ((f_book = fopen ("zh.opn", "r")) == NULL)
72 return FALSE;
73 }
74 else if (Variant == Suicide)
75 {
76 if ((f_book = fopen ("suicide.opn", "r")) == NULL)
77 return FALSE;
78 }
79 else if (Variant == Losers)
80 {
81 if ((f_book = fopen ("losers.opn", "r")) == NULL)
82 return FALSE;
83 }
84 else
85 {
86 if ((f_book = fopen ("bug.opn", "r")) == NULL)
87 return FALSE;
88 }
89
90 while ((ch = getc(f_book)) != EOF) {
91
92 if (commentmode)
93 {
94 if (ch == '/') /* end comment */
95 {
96 commentmode = FALSE;
97 }
98 }
99 else
100 {
101 if (ch == '\n') { /* end of book line */
102
103 /* not ending an empty book line */
104 if (j > 0)
105 {
106 book[i++][j] = '\0';
107 j = 0;
108 }
109
110 tagmode = FALSE;
111 }
112 else if (ch == '!')
113 {
114 if (!tagmode)
115 {
116 book_flags[i][((j + 1) / 4) - 1] = book_always;
117 tagmode = TRUE;
118 }
119 else
120 {
121 book_flags[i][((j + 1) / 4) - 1] = book_murky;
122 }
123 }
124 else if (ch == '?')
125 {
126 if (!tagmode)
127 {
128 book_flags[i][((j + 1) / 4) - 1] = book_never;
129 tagmode = TRUE;
130 }
131 else
132 {
133 book_flags[i][((j + 1) / 4) - 1] = book_interesting;
134 }
135 }
136 else if (ch == '=')
137 {
138 book_flags[i][((j + 1) / 4) - 1] = book_solid;
139 tagmode = TRUE;
140 }
141 else if ((ch == ' ') || (ch == '\t'))
142 {
143 /* skip spaces and tabs */
144 tagmode = FALSE;
145 }
146 else if (ch == '/') /* start comment */
147 {
148 commentmode = TRUE;
149 }
150 else if (j < 160 && i < 4000) /* middle of book line */
151 {
152 book[i][j++] = ch;
153 tagmode = FALSE;
154 }
155 /* If j >= 100, then the book line was too long. The rest will be
156 read, but ignored, and will be null-character terminated when a
157 '\n' is read. If i >= 2000, then there are too many book lines.
158 The remaining lines will be read, but ignored. */
159 }
160 }
161
162 num_book_lines = i;
163
164 fclose(f_book);
165
166 return TRUE;
167
168 }
169
choose_book_move(void)170 move_s choose_book_move (void) {
171
172 /* Since the book is sorted alphabetically, we can use strncpy, and hope
173 to get early exits once we've found the first few moves in the book.
174 Once we choose a book move, we'll make a variable indicate where
175 it was found, so we can start our search for the next move there. */
176
177 static int last_book_move = 0;
178 int book_match = FALSE;
179 int i, j, num_moves, random_number, num_replies;
180 char possible_move[5], coord_move[5];
181 move_s book_replies[4000], moves[400];
182 char force_move = FALSE;
183 int ic;
184
185 srand(time(0));
186
187 if (!book_ply)
188 last_book_move = 0;
189
190 num_replies = 0;
191 gen(&moves[0]);
192 num_moves = numb_moves;
193
194 for (i = last_book_move; i < num_book_lines; i++) {
195 /* check to see if opening line matches up to current book_ply: */
196 if (!strncmp(opening_history, book[i], (book_ply * 4)) || (!book_ply)) {
197 /* if book move is legal, add it to possible list of book moves */
198
199 if ((book_flags[i][book_ply] != book_never)
200 && (book_flags[i][book_ply] != book_murky))
201 {
202 if (book_flags[i][book_ply] == book_always)
203 {
204 if (force_move != TRUE)
205 {
206 /* found 1st ! move -> remove normal ones */
207 force_move = TRUE;
208 num_replies = 0;
209 }
210 }
211
212 if ((force_move != TRUE) ||
213 ((force_move == TRUE) &&
214 (book_flags[i][book_ply] == book_always)))
215 {
216 strncpy(possible_move, book[i] + (book_ply * 4), 4);
217 possible_move[4] = '\0';
218
219 for (j = 0; j < num_moves; j++)
220 {
221 comp_to_coord(moves[j], coord_move);
222
223 if (!strcmp(possible_move, coord_move))
224 {
225 ic = in_check();
226 make(&moves[0], j);
227 if (check_legal(&moves[0], j, ic))
228 {
229 book_replies[num_replies++] = moves[j];
230 book_match = TRUE;
231 }
232 unmake(&moves[0], j);
233 }
234 }
235 }
236 }
237 }
238 /* we can exit the search for a book move early, if we've no longer
239 have a match, but we have found at least one match */
240 if (!book_match && num_replies)
241 break;
242 }
243
244 /* now, if we have some book replies, pick our move randomly from
245 book_replies: */
246 if (!num_replies)
247 return dummy;
248
249 printf("Book moves: %d\n", num_replies);
250
251 random_number = rand() % num_replies;
252 return book_replies[random_number];
253
254 }
255
256