1 #include "chess.h"
2 #include "data.h"
3 /* last modified 05/08/14 */
4 /*
5  *******************************************************************************
6  *                                                                             *
7  *   SetBoard() is used to set up the board in any position desired.  It uses  *
8  *   a forsythe-like string of characters to describe the board position.      *
9  *                                                                             *
10  *   The standard piece codes p,n,b,r,q,k are used to denote the type of piece *
11  *   on a square, upper/lower case are used to indicate the side (program/     *
12  *   opponent) of the piece.                                                   *
13  *                                                                             *
14  *   The pieces are entered with square a8 first, then b8, ... until the full  *
15  *   8th rank is completed.  A "/" terminates that rank.  This is repeated for *
16  *   each of the 8 ranks, with the last (1st) rank not needing a terminating   *
17  *   "/".  For empty squares, a number between 1 and 8 can be used to indicate *
18  *   the number of adjacent empty squares.                                     *
19  *                                                                             *
20  *   That board description must be followed by a "b" or "w" to indicate which *
21  *   side is on move.                                                          *
22  *                                                                             *
23  *   Next, up to 4 characters are used to indicate which side can castle and   *
24  *   to which side.  An uppercase K means white can castle kingside, while a   *
25  *   lowercase q means black can castle queenside.                             *
26  *                                                                             *
27  *   Finally, if there is an enpassant capture possible (the last move was a   *
28  *   double pawn move and there was an enemy pawn that could capture it.  The  *
29  *   square is the square the capturing pawn ends up on.                       *
30  *                                                                             *
31  *           K2R/PPP////q/5ppp/7k/ b - -                                       *
32  *                                                                             *
33  *   this assumes that k represents a white king and -q represents a black     *
34  *   queen.                                                                    *
35  *                                                                             *
36  *                            k  *  *  r  *  *  *  *                           *
37  *                            p  p  p  *  *  *  *  *                           *
38  *                            *  *  *  *  *  *  *  *                           *
39  *                            *  *  *  *  *  *  *  *                           *
40  *                            *  *  *  *  *  *  *  *                           *
41  *                           -q  *  *  *  *  *  *  *                           *
42  *                            *  *  *  *  * -p -p -p                           *
43  *                            *  *  *  *  *  *  * -k                           *
44  *                                                                             *
45  *******************************************************************************
46  */
SetBoard(TREE * tree,int nargs,char * args[],int special)47 void SetBoard(TREE * tree, int nargs, char *args[], int special) {
48   int twtm, i, match, num, pos, square, tboard[64];
49   int bcastle, ep, wcastle, error = 0, whichsq;
50   char input[80];
51   static const char bdinfo[] =
52       { 'k', 'q', 'r', 'b', 'n', 'p', '*', 'P', 'N', 'B',
53     'R', 'Q', 'K', '*', '1', '2', '3', '4',
54     '5', '6', '7', '8', '/'
55   };
56   static const char status[13] =
57       { 'K', 'Q', 'k', 'q', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
58     'h', ' '
59   };
60   static const int firstsq[8] = { 56, 48, 40, 32, 24, 16, 8, 0 };
61 
62   if (special)
63     strcpy(input, initial_position);
64   else
65     strcpy(input, args[0]);
66   for (i = 0; i < 64; i++)
67     tboard[i] = 0;
68 /*
69  ************************************************************
70  *                                                          *
71  *  Scan the input string searching for pieces, numbers     *
72  *  [empty squares], slashes [end-of-rank] and a blank      *
73  *  [end of board, start of castle status].                 *
74  *                                                          *
75  ************************************************************
76  */
77   whichsq = 0;
78   square = firstsq[whichsq];
79   num = 0;
80   for (pos = 0; pos < (int) strlen(args[0]); pos++) {
81     for (match = 0; match < 23 && args[0][pos] != bdinfo[match]; match++);
82     if (match > 22)
83       break;
84 /*
85  "/" -> end of this rank.
86  */
87     else if (match == 22) {
88       num = 0;
89       if (whichsq > 6)
90         break;
91       square = firstsq[++whichsq];
92     }
93 /*
94  "1-8" -> empty squares.
95  */
96     else if (match >= 14) {
97       num += match - 13;
98       square += match - 13;
99       if (num > 8) {
100         printf("more than 8 squares on one rank\n");
101         error = 1;
102         break;
103       }
104       continue;
105     }
106 /*
107  piece codes.
108  */
109     else {
110       if (++num > 8) {
111         printf("more than 8 squares on one rank\n");
112         error = 1;
113         break;
114       }
115       tboard[square++] = match - 6;
116     }
117   }
118 /*
119  ************************************************************
120  *                                                          *
121  *  Now extract (a) side to move [w/b], (b) castle status   *
122  *  [KkQq for white/black king-side ok, white/black queen-  *
123  *  side ok], (c) enpassant target square.                  *
124  *                                                          *
125  ************************************************************
126  */
127   twtm = 0;
128   ep = 0;
129   wcastle = 0;
130   bcastle = 0;
131 /*
132  ************************************************************
133  *                                                          *
134  *  Side to move.                                           *
135  *                                                          *
136  ************************************************************
137  */
138   if (args[1][0] == 'w')
139     twtm = 1;
140   else if (args[1][0] == 'b')
141     twtm = 0;
142   else {
143     printf("side to move is bad\n");
144     error = 1;
145   }
146 /*
147  ************************************************************
148  *                                                          *
149  *  Castling/enpassant status.                              *
150  *                                                          *
151  ************************************************************
152  */
153   if (nargs > 2 && strlen(args[2])) {
154     if (strcmp(args[2], "-")) {
155       for (pos = 0; pos < (int) strlen(args[2]); pos++) {
156         for (match = 0; (match < 13) && (args[2][pos] != status[match]);
157             match++);
158         if (match == 0)
159           wcastle += 1;
160         else if (match == 1)
161           wcastle += 2;
162         else if (match == 2)
163           bcastle += 1;
164         else if (match == 3)
165           bcastle += 2;
166         else if (args[2][0] != '-') {
167           printf("castling status is bad.\n");
168           error = 1;
169         }
170       }
171     }
172   }
173   if (nargs > 3 && strlen(args[3])) {
174     if (strcmp(args[3], "-")) {
175       if (args[3][0] >= 'a' && args[3][0] <= 'h' && args[3][1] > '0' &&
176           args[3][1] < '9') {
177         ep = (args[3][1] - '1') * 8 + args[3][0] - 'a';
178       } else if (args[3][0] != '-') {
179         printf("enpassant status is bad.\n");
180         error = 1;
181       }
182     }
183   }
184   for (i = 0; i < 64; i++)
185     PcOnSq(i) = tboard[i];
186   Castle(0, white) = wcastle;
187   Castle(0, black) = bcastle;
188   EnPassant(0) = 0;
189   if (ep) {
190     do {
191       if (twtm && Rank(ep) == RANK6 && PcOnSq(ep - 8) == -pawn) {
192         if (File(ep) != 7 && PcOnSq(ep - 7) == pawn)
193           break;
194         if (File(ep) != 0 && PcOnSq(ep - 9) == pawn)
195           break;
196       } else if (!twtm && Rank(ep) == RANK3 && PcOnSq(ep + 8) == pawn) {
197         if (File(ep) != 0 && PcOnSq(ep + 7) == -pawn)
198           break;
199         if (File(ep) != 7 && PcOnSq(ep + 9) == -pawn)
200           break;
201       } else {
202         ep = 0;
203       }
204       if (!ep) {
205         printf("enpassant status is bad.\n");
206         ep = 0;
207         error = 1;
208       }
209     } while (0);
210     EnPassant(0) = ep;
211   }
212 /*
213  ************************************************************
214  *                                                          *
215  *  Now check the castling status status to make sure that  *
216  *  the board is in a state that matches.                   *
217  *                                                          *
218  ************************************************************
219  */
220   if (((Castle(0, white) & 2) && (PcOnSq(A1) != rook))
221       || ((Castle(0, white) & 1) && (PcOnSq(H1) != rook))
222       || ((Castle(0, black) & 2) && (PcOnSq(A8) != -rook))
223       || ((Castle(0, black) & 1) && (PcOnSq(H8) != -rook))) {
224     printf("ERROR-- castling status does not match board position\n");
225     error = 1;
226   }
227 /*
228  ************************************************************
229  *                                                          *
230  *  Now set the bitboards so that error tests can be done.  *
231  *                                                          *
232  ************************************************************
233  */
234   SetChessBitBoards(tree);
235 /*
236  ************************************************************
237  *                                                          *
238  *  Now check the position for a sane position, which means *
239  *  no more than 8 pawns, no more than 10 knights, bishops  *
240  *  or rooks, no more than 9 queens, no pawns on 1st or 8th *
241  *  rank, etc.                                              *
242  *                                                          *
243  ************************************************************
244  */
245   game_wtm = twtm;
246   error += InvalidPosition(tree);
247   if (!error) {
248     if (log_file)
249       DisplayChessBoard(log_file, tree->position);
250     rep_index = 0;
251     tree->rep_list[0] = HashKey;
252     Reversible(0) = 0;
253     if (!special) {
254       last_mate_score = 0;
255       InitializeKillers();
256       last_pv.pathd = 0;
257       last_pv.pathl = 0;
258       tree->pv[0].pathd = 0;
259       tree->pv[0].pathl = 0;
260       moves_out_of_book = 0;
261     }
262   } else {
263     if (special)
264       Print(4095, "bad string = \"%s\"\n", initial_position);
265     else
266       Print(4095, "bad string = \"%s\"\n", args[0]);
267     InitializeChessBoard(tree);
268     Print(4095, "Illegal position, using normal initial chess position\n");
269   }
270 }
271