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