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 28char book[4000][161]; 29char book_flags[4000][41]; 30int num_book_lines; 31int book_ply; 32int use_book; 33char 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 41int 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 170move_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((unsigned)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