Check-in modifications made by HGM so far
[capablanca.git] / lasker-2.2.3 / src / setup.c
1 /*
2    This program is free software; you can redistribute it and/or modify
3    it under the terms of the GNU General Public License as published by
4    the Free Software Foundation; either version 2 of the License, or
5    (at your option) any later version.
6    
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11    
12    You should have received a copy of the GNU General Public License
13    along with this program; if not, write to the Free Software
14    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17 /* setup.c 
18
19  Contains stuff for setting up boards in examine mode
20
21 */
22
23 #include "includes.h"
24
25 static int check_valid_square(char* square)
26 {
27  if (strlen (square) == 2) {
28    if ( (square[0] <= 'a') && (square[0] >= 'h')
29      && (square[1] <= '1') && (square [1] >= '8') )
30      return 0;
31    return 1; 
32  } else
33    return 0;
34 }
35
36 /* Check the position is valid
37   ie two kings - one white one black
38   ie no pawns on 1st or 8th ranks
39   only the king that is to move may be in check,
40   checkmate and stalemate */
41
42 static int validate_position (int p,struct game_state_t *b)
43 {
44  int r,f,check;
45  int white_k = 0;
46  int black_k = 0;
47
48   for (f = 0; (f < b->files); f++) {
49     for (r = 0; (r < b->ranks); r++) {
50       if (b->board[f][r] == W_KING) {
51          white_k += 1;
52          if (white_k == 2) {
53            pprintf (p,"You can only have one white king.\n");
54            return 0;
55          }
56       }
57       if (b->board[f][r] == B_KING) {
58          black_k += 1;
59          if (black_k == 2) {
60            pprintf (p,"You can only have one black king.\n");
61            return 0;
62          }
63       }
64       if (((b->board[f][r] == W_PAWN) || (b->board[f][r] == B_PAWN)) &&
65          ((r == 0) || (r == b->ranks-1))) {
66          pprintf (p,"Pawns cannot be placed on the first or eighth rank.\n");
67          return 0;
68       }
69     }
70   }
71   if (!white_k) {
72     pprintf (p,"There is no white king.\n");
73     return 0;
74   }
75   if (!black_k) {
76     pprintf (p,"There is no black king.\n");
77     return 0;
78   }
79   if (b->onMove == WHITE) { pprintf(p, "WHITE to move\n"); }
80   else if (b->onMove == BLACK) { pprintf(p, "BLACK to move\n"); }
81   else pprintf(p, "ERROR!!\n");
82   check = in_check(b);
83   if (check) {
84     pprintf (p,"Only the player to move may be in check.\n");
85     return 0;
86   }
87   if (!has_legal_move(b)) {
88     b->onMove = CToggle(b->onMove);
89     if (in_check(b)) {
90       pprintf (p, "%s is checkmated.\n",
91                    b->onMove == WHITE  ?  "BLACK"  :  "WHITE");
92     } else {
93       pprintf (p, "%s is stalemated.\n",
94                    b->onMove == WHITE  ?  "BLACK"  :  "WHITE");
95     }
96     b->onMove = CToggle(b->onMove);
97   }
98   return 1; /* valid position */
99 }
100
101 int com_setup (int p,param_list param)
102 {
103  struct player *pp = &player_globals.parray[p];
104  int gamenum;
105
106  if ((pp->game <0) || (game_globals.garray[pp->game].status != GAME_SETUP)) {
107    if (param[0].type == TYPE_NULL) {
108        if (pp->game >= 0)
109          if  (game_globals.garray[pp->game].status == GAME_EXAMINE) {
110            game_free (pp->game);
111            game_globals.garray[pp->game].status = GAME_SETUP;
112            game_globals.garray[pp->game].numHalfMoves = 0;
113            game_globals.garray[pp->game].totalHalfMoves = 0;
114            game_globals.garray[pp->game].revertHalfMove = 0;
115            pprintf (p,"Entering examine(setup) mode.\n");
116            return COM_OK;
117          }
118      pcommand (p,"examine setup");
119      return COM_OK_NOPROMPT;
120    } else {
121    pprintf(p, "You are not setting up a position.\n");
122    return COM_OK;
123    }
124  }
125  gamenum = game_globals.garray[pp->game].game_state.gameNum;
126  if (param[0].type != TYPE_NULL) {
127    if (!strcmp("clear",param[0].val.word)) {
128      board_clear(&(game_globals.garray[pp->game].game_state));
129      game_globals.garray[pp->game].game_state.gameNum = gamenum; 
130      send_board_to(pp->game, p);
131      pprintf (p,"Board cleared.\n"); 
132      return COM_OK;
133    } else if (!strcmp("start",param[0].val.word)) {
134      board_standard(&(game_globals.garray[pp->game].game_state));
135      game_globals.garray[pp->game].game_state.gameNum = gamenum;
136      send_board_to(pp->game, p);
137      pprintf (p,"Board set up as starting position.\n");
138      return COM_OK;
139    } else if (!strcmp("fen",param[0].val.word) && param[1].type != TYPE_NULL) {
140      FEN_to_board(param[1].val.string, &(game_globals.garray[pp->game].game_state));
141      game_globals.garray[pp->game].game_state.gameNum = gamenum;
142      send_board_to(pp->game, p);
143      pprintf (p,"Board set up by FEN.\n");
144      return COM_OK;
145    } else if (!strcmp("done",param[0].val.word)) {
146      if (validate_position (p,&(game_globals.garray[pp->game].game_state))) {
147        game_globals.garray[pp->game].status = GAME_EXAMINE;
148        pprintf(p,"Game is validated - entering examine mode.\n");
149        MakeFENpos(pp->game, game_globals.garray[pp->game].FENstartPos);
150      } else
151        pprintf(p,"The position is not valid - staying in setup mode.\n");
152      return COM_OK;
153    } else { /* try to load a category of board */
154      char *board = param[1].val.word;
155      if (param[1].type == TYPE_NULL) board = "0";
156      game_globals.garray[pp->game].FENstartPos[0] = 0; // [HGM] new shuffle
157        if (!board_init (pp->game,&(game_globals.garray[pp->game].game_state),param[0].val.word,board)) {
158          game_globals.garray[pp->game].game_state.gameNum = gamenum;
159          if(!strcmp(board,"0"))
160            sprintf(game_globals.garray[pp->game].variant, "%s",param[0].val.word);
161          else
162            sprintf(game_globals.garray[pp->game].variant, "%s/%s",param[0].val.word,board);
163          send_board_to(pp->game, p);
164          pprintf (p,"Board set up as %s %s.\n",param[0].val.word,board);
165        } else {
166          pprintf (p,"Board %s %s is unavailable.\n",param[0].val.word,board);
167          game_globals.garray[pp->game].game_state.gameNum = gamenum;
168        }
169        return COM_OK;
170      
171    }
172  }
173  pprintf (p, "You have supplied an incorrect parameter to setup.\n");
174  return COM_OK;
175 }
176
177 int com_tomove (int p,param_list param)
178 {
179  struct player *pp = &player_globals.parray[p];
180  if ((pp->game <0) || (game_globals.garray[pp->game].status != GAME_SETUP)) {
181    if (pp->game >= 0)
182      if (game_globals.garray[pp->game].status == GAME_EXAMINE) {
183        pprintf (p,"This game is active - type 'setup' to allow editing.\n");
184        return COM_OK;
185      }
186    pprintf(p, "You are not setting up a position.\n");
187    return COM_OK;
188  }
189  if (!strcmp("white",param[0].val.word))
190     game_globals.garray[pp->game].game_state.onMove = WHITE;
191  else if (!strcmp("black",param[0].val.word))
192     game_globals.garray[pp->game].game_state.onMove = BLACK;
193  else {
194    pprintf (p,"Please type: tomove white    or   tomove black\n");
195    return COM_OK;
196  }
197  pcommand (p,"refresh");
198  return COM_OK_NOPROMPT;
199 }
200
201 int com_clrsquare (int p,param_list param)
202 {
203  struct player *pp = &player_globals.parray[p];
204  if ((pp->game <0) || (game_globals.garray[pp->game].status != GAME_SETUP)) {
205    if (pp->game >= 0)
206      if (game_globals.garray[pp->game].status == GAME_EXAMINE) {
207        pprintf (p,"This game is active - type 'setup' to allow editing.\n");
208        return COM_OK;
209      }
210    pprintf(p, "You are not setting up a position.\n");
211    return COM_OK;
212  }
213
214  if (!check_valid_square(param[0].val.word)) {    
215    pprintf (p,"You must specify a square.");
216    return COM_OK;
217  }
218
219  pcommand (p,"x@%s",param[0].val.word);
220  return COM_OK_NOPROMPT;
221 }
222
223 /* allows the following
224
225  x@rf or X@rf - clear a square
226  P@rf - drop a white pawn
227  p@rf - drop a black pawn
228  wp@rf - drop a white pawn
229  bp@rf - drop a black pawn
230   can replace the @ with a * - some people do not have a @ key
231 */
232
233 /* having to check before then after is lame - will change this later */
234 int is_drop(char* dropstr)
235 {
236
237  int len = strlen (dropstr);
238
239  if ((len < 4) || (len > 5))
240    return 0;
241
242 /*check x@e3 */
243
244  if ((dropstr[0] == 'x') || (dropstr[0] == 'X')) {
245    if (!((dropstr[1] == '@') || (dropstr[1] == '*')))
246      return 0;
247    if (!check_valid_square(dropstr+2))
248      return 0;
249
250 /*check wp@e3 */
251
252  } else if (dropstr[0] == 'w') {
253    if (!((dropstr[1] == 'p') || (dropstr[1] == 'r') || (dropstr[1] == 'n') || (dropstr[1] == 'b') || (dropstr[1] == 'q') || (dropstr[1] == 'k')))
254      return 0;
255    if (!((dropstr[2] == '@') || (dropstr[2] == '*')))
256      return 0;
257    if (!check_valid_square(dropstr+3))
258      return 0;
259
260 /* check bp@e3 */
261
262  } else if (len == 5) { /* so b@e2 and bb@e2 aren't confused */
263    if (dropstr[0] == 'b') {
264      if (!((dropstr[1] == 'p') || (dropstr[1] == 'r') || (dropstr[1] == 'n') || (dropstr[1] == 'b') || (dropstr[1] == 'q') || (dropstr[1] == 'k')))
265        return 0;
266      if (!((dropstr[2] == '@') || (dropstr[2] == '*')))
267        return 0;
268      if (!check_valid_square(dropstr+3))
269        return 0;
270      } else return 0; /* Exhausted 5 char possibilities */ 
271
272 /* check p@e3 and P@e3 */
273
274  } else if ((dropstr[0] == 'p') || (dropstr[0] == 'r') || (dropstr[0] == 'n') || (dropstr[0] == 'b') || (dropstr[0] == 'q') || (dropstr[0] == 'k') || 
275        (dropstr[0] == 'P') || (dropstr[0] == 'R') || (dropstr[0] == 'N') || (dropstr[0] == 'B') || (dropstr[0] == 'Q') || (dropstr[0] == 'K')) {
276
277      if (!((dropstr[1] == '@') || (dropstr[1] == '*')))
278       return 0;
279      if (!check_valid_square(dropstr+2))
280        return 0;
281  } else return 0;
282  return 1; /* valid drop */
283 }
284
285 static void getsquare(char* square,int *f, int *r)
286 {
287  *f = square[0] - 'a';
288  *r = square[1] - '1';
289 }
290
291 int attempt_drop(int p,int g,char* dropstr)
292 {
293  int len = strlen (dropstr);
294  int color;
295  int piece = 0;
296  int f;
297  int r;
298
299  if ((len < 4) || (len > 5))
300    return 0;
301
302 /*check x@e3 */
303
304  if ((dropstr[0] == 'x') || (dropstr[0] == 'X')) { /* as x must be clear */
305    getsquare(dropstr+2,&f,&r);
306    piece = NOPIECE;
307
308 /*check wp@e3 */
309
310  } else if (dropstr[0] == 'w') {
311    piece = CharToPiece(dropstr[1], game_globals.garray[g].game_state.variant) & 0x7F;
312    color = WHITE;
313    getsquare(dropstr+3,&f,&r);
314
315 /* check bp@e3 */
316
317  } else  if (len == 5) { /* check length to avoid b@e2 and bb@e2 being confused */
318    if (dropstr[0] == 'b') {
319      piece = CharToPiece(dropstr[1], game_globals.garray[g].game_state.variant) | BLACK;
320      getsquare(dropstr+3,&f,&r);
321    }
322
323 /* check p@e3 and P@e3 */
324
325  } else {
326    if (!((dropstr[1] == '@') || (dropstr[1] == '*')))
327      return 0;
328    else {
329      piece = CharToPiece(dropstr[0], game_globals.garray[g].game_state.variant);
330      getsquare(dropstr+2,&f,&r);
331      }
332  }
333
334  game_globals.garray[g].game_state.board[f][r] = piece;
335  return 1; /* valid drop */
336 }