81f2d37c9bea5e08e63a096177986d1e19c22ea3
[capablanca.git] / lasker-2.2.3 / src / movecheck.c
1 /*
2    Copyright (c) 1993 Richard V. Nash.
3    Copyright (c) 2000 Dan Papasian
4    Copyright (C) Andrew Tridgell 2002
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /* Simply tests if the input string is a move or not. */
24 /* If it matches patterns below */
25 /* Add to this list as you improve the move parser */
26 /* MS_COMP e2e4 */
27 /* MS_COMPDASH e2-e4 */
28 /* MS_CASTLE o-o, o-o-o */
29 /* Not done yet */
30 /* MS_ALG e4, Nd5 Ncd5 */
31 int is_move(const char *mstr)
32 {
33   int len = strlen(mstr);
34   if ((len > 3) && (mstr[len - 2] == '='))
35     len -= 2;
36
37   /* remove the 'mates' marker */
38   if (mstr[len - 1] == '#')
39     len--;
40
41   if (len == 4) {               /* Test for e2e4 */
42     if (isfile(mstr[0]) && isrank(mstr[1]) &&
43         isfile(mstr[2]) && isrank(mstr[3])) {
44       return MS_COMP;
45     }
46   }
47   if (len == 5) {               /* Test for e2-e4 */
48     if (isfile(mstr[0]) && isrank(mstr[1]) &&
49         (mstr[2] == '-') &&
50         isfile(mstr[3]) && isrank(mstr[4])) {
51       return MS_COMPDASH;
52     }
53   }
54   if (len == 3) {               /* Test for o-o */
55     if ((mstr[0] == 'o') && (mstr[1] == '-') && (mstr[2] == 'o')) {
56       return MS_KCASTLE;
57     }
58     if ((mstr[0] == 'O') && (mstr[1] == '-') && (mstr[2] == 'O')) {
59       return MS_KCASTLE;
60     }
61     if ((mstr[0] == '0') && (mstr[1] == '-') && (mstr[2] == '0')) {
62       return MS_KCASTLE;
63     }
64   }
65   if (len == 2) {               /* Test for oo */
66     if ((mstr[0] == 'o') && (mstr[1] == 'o')) {
67       return MS_KCASTLE;
68     }
69     if ((mstr[0] == 'O') && (mstr[1] == 'O')) {
70       return MS_KCASTLE;
71     }
72     if ((mstr[0] == '0') && (mstr[1] == '0')) {
73       return MS_KCASTLE;
74     }
75   }
76   if (len == 5) {               /* Test for o-o-o */
77     if ((mstr[0] == 'o') && (mstr[1] == '-') && (mstr[2] == 'o') && (mstr[3] == '-') && (mstr[4] == 'o')) {
78       return MS_QCASTLE;
79     }
80     if ((mstr[0] == 'O') && (mstr[1] == '-') && (mstr[2] == 'O') && (mstr[3] == '-') && (mstr[4] == 'O')) {
81       return MS_QCASTLE;
82     }
83     if ((mstr[0] == '0') && (mstr[1] == '-') && (mstr[2] == '0') && (mstr[3] == '-') && (mstr[4] == '0')) {
84       return MS_QCASTLE;
85     }
86   }
87   if (len == 3) {               /* Test for ooo */
88     if ((mstr[0] == 'o') && (mstr[1] == 'o') && (mstr[2] == 'o')) {
89       return MS_QCASTLE;
90     }
91     if ((mstr[0] == 'O') && (mstr[1] == 'O') && (mstr[2] == 'O')) {
92       return MS_QCASTLE;
93     }
94     if ((mstr[0] == '0') && (mstr[1] == '0') && (mstr[2] == '0')) {
95       return MS_QCASTLE;
96     }
97   }
98   return alg_is_move(mstr);
99 }
100
101
102 int NextPieceLoop(board_t b, int *f, int *r, int color)
103 {
104   for (;;) {
105     (*r) = (*r) + 1;
106     if (*r > 7) {
107       *r = 0;
108       *f = *f + 1;
109       if (*f > 7)
110         break;
111     }
112     if ((b[*f][*r] != NOPIECE) && iscolor(b[*f][*r], color))
113       return 1;
114   }
115   return 0;
116 }
117
118 int InitPieceLoop(board_t b, int *f, int *r, int color)
119 {
120   *f = 0;
121   *r = -1;
122   return 1;
123 }
124
125 /* All of the routines assume that the obvious problems have been checked */
126 /* See legal_move() */
127 static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int tr )
128 {
129   if (ff == tf) {
130     if (gs->board[tf][tr] != NOPIECE) return 0;
131     if (gs->onMove == WHITE) {
132       if (tr - fr == 1) return 1;
133       if ((fr == 1) && (tr - fr == 2) && gs->board[ff][2]==NOPIECE) return 1;
134     } else {
135       if (fr - tr == 1) return 1;
136       if ((fr == 6) && (fr - tr == 2) && gs->board[ff][5]==NOPIECE) return 1;
137     }
138     return 0;
139   }
140   if (ff != tf) { /* Capture ? */
141     if ((ff - tf != 1) && (tf - ff != 1)) return 0;
142     if ((fr - tr != 1) && (tr - fr != 1)) return 0;
143     if (gs->onMove == WHITE) {
144       if (fr > tr) return 0;
145       if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],BLACK))
146         return 1;
147       if (gs->ep_possible[0][ff] == 1) {
148         if ((tf==ff+1) && (gs->board[ff+1][fr] == B_PAWN)) return 1;
149       } else if (gs->ep_possible[0][ff] == -1) {
150         if ((tf==ff-1) && (gs->board[ff-1][fr] == B_PAWN)) return 1;
151       }
152     } else {
153       if (tr > fr) return 0;
154       if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],WHITE))
155         return 1;
156       if (gs->ep_possible[1][ff] == 1) {
157         if ((tf==ff+1) && (gs->board[ff+1][fr] == W_PAWN)) return 1;
158       } else if (gs->ep_possible[1][ff] == -1) {
159         if ((tf==ff-1) && (gs->board[ff-1][fr] == W_PAWN)) return 1;
160       }
161     }
162   }
163   return 0;
164 }
165
166 static int legal_knight_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
167 {
168   int dx, dy;
169
170   dx = ff - tf;
171   dy = fr - tr;
172   if (abs(dx) == 2) {
173     if (abs(dy) == 1)
174       return 1;
175   }
176   if (abs(dy) == 2) {
177     if (abs(dx) == 1)
178       return 1;
179   }
180   return 0;
181 }
182
183 static int legal_bishop_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
184 {
185   int dx, dy, x, y;
186   int startx, starty;
187   int count;
188   int incx, incy;
189
190   if (ff > tf) {
191     dx = ff - tf;
192     incx = -1;
193   } else {
194     dx = tf - ff;
195     incx = 1;
196   }
197   startx = ff + incx;
198   if (fr > tr) {
199     dy = fr - tr;
200     incy = -1;
201   } else {
202     dy = tr - fr;
203     incy = 1;
204   }
205   starty = fr + incy;
206   if (dx != dy)
207     return 0;                   /* Not diagonal */
208   if (dx == 1)
209     return 1;                   /* One square, ok */
210   count = dx - 1;
211   for (x = startx, y = starty; count; x += incx, y += incy, count--) {
212     if (gs->board[x][y] != NOPIECE)
213       return 0;
214   }
215   return 1;
216 }
217
218 static int legal_rook_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
219 {
220   int i;
221   int start, stop;
222
223   if (ff == tf) {
224     if (abs(fr - tr) == 1)
225       return 1;
226     if (fr < tr) {
227       start = fr + 1;
228       stop = tr - 1;
229     } else {
230       start = tr + 1;
231       stop = fr - 1;
232     }
233     for (i = start; i <= stop; i++) {
234       if (gs->board[ff][i] != NOPIECE)
235         return 0;
236     }
237     return 1;
238   } else if (fr == tr) {
239     if (abs(ff - tf) == 1)
240       return 1;
241     if (ff < tf) {
242       start = ff + 1;
243       stop = tf - 1;
244     } else {
245       start = tf + 1;
246       stop = ff - 1;
247     }
248     for (i = start; i <= stop; i++) {
249       if (gs->board[i][fr] != NOPIECE)
250         return 0;
251     }
252     return 1;
253   } else {
254     return 0;
255   }
256 }
257
258 static int legal_queen_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
259 {
260   return legal_rook_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr);
261 }
262
263 /* Ckeck, if square (kf,kr) is attacked by enemy piece.
264  * Used in castling from/through check testing.
265  */
266
267 /* new one from soso: */
268 static int is_square_attacked (struct game_state_t *gs, int kf, int kr)
269 {
270   struct game_state_t fakeMove;
271
272   fakeMove = *gs;
273   fakeMove.board[4][kr] = NOPIECE;
274   fakeMove.board[kf][kr] = KING | fakeMove.onMove;
275   fakeMove.onMove = CToggle (fakeMove.onMove);
276   if (in_check(&fakeMove)) return 1;
277     else return 0;
278 }
279
280 /* old one:
281 static int is_square_attacked(struct game_state_t * gs, int kf, int kr)
282 {
283   int f, r;
284   gs->onMove = CToggle(gs->onMove);
285
286   for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
287        NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
288     if (legal_move(gs, f, r, kf, kr)) {
289       gs->onMove = CToggle(gs->onMove);
290       return 1;
291     }
292   }
293   gs->onMove = CToggle(gs->onMove);
294   return 0;
295 }
296 */
297
298 static int legal_king_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
299 {
300   if (gs->onMove == WHITE) {
301     /* King side castling */
302     if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 6) && !gs->wkmoved
303         && (!gs->wkrmoved) && (gs->board[5][0] == NOPIECE) &&
304         (gs->board[6][0] == NOPIECE) && (gs->board[7][0] == W_ROOK) &&
305         (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 5, 0))) {
306       return 1;
307     }
308     /* Queen side castling */
309     if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 2) && !gs->wkmoved
310         && (!gs->wqrmoved) && (gs->board[3][0] == NOPIECE) &&
311         (gs->board[2][0] == NOPIECE) && (gs->board[1][0] == NOPIECE) &&
312         (gs->board[0][0] == W_ROOK) &&
313         (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 3, 0))) {
314       return 1;
315     }
316   } else {                      /* Black */
317     /* King side castling */
318     if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 6) && !gs->bkmoved
319         && (!gs->bkrmoved) && (gs->board[5][7] == NOPIECE) &&
320         (gs->board[6][7] == NOPIECE) && (gs->board[7][7] == B_ROOK) &&
321         (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 5, 7))) {
322       return 1;
323     }
324     /* Queen side castling */
325     if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 2) && (!gs->bkmoved)
326         && (!gs->bqrmoved) && (gs->board[3][7] == NOPIECE) &&
327         (gs->board[2][7] == NOPIECE) && (gs->board[1][7] == NOPIECE) &&
328         (gs->board[0][7] == B_ROOK) &&
329         (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 3, 7))) {
330       return 1;
331     }
332   }
333   if (abs(ff - tf) > 1)
334     return 0;
335   if (abs(fr - tr) > 1)
336     return 0;
337   return 1;
338 }
339
340 static void add_pos(int tof, int tor, int *posf, int *posr, int *numpos)
341 {
342   posf[*numpos] = tof;
343   posr[*numpos] = tor;
344   (*numpos)++;
345 }
346
347 static void possible_pawn_moves(struct game_state_t * gs,
348                                   int onf, int onr,
349                                   int *posf, int *posr, int *numpos)
350 {
351   if (gs->onMove == WHITE) {
352     if (gs->board[onf][onr + 1] == NOPIECE) {
353       add_pos(onf, onr + 1, posf, posr, numpos);
354       if ((onr == 1) && (gs->board[onf][onr + 2] == NOPIECE))
355         add_pos(onf, onr + 2, posf, posr, numpos);
356     }
357     if ((onf > 0) && (gs->board[onf - 1][onr + 1] != NOPIECE) &&
358         (iscolor(gs->board[onf - 1][onr + 1], BLACK)))
359       add_pos(onf - 1, onr + 1, posf, posr, numpos);
360     if ((onf < 7) && (gs->board[onf + 1][onr + 1] != NOPIECE) &&
361         (iscolor(gs->board[onf + 1][onr + 1], BLACK)))
362       add_pos(onf + 1, onr + 1, posf, posr, numpos);
363     if (gs->ep_possible[0][onf] == -1)
364       add_pos(onf - 1, onr + 1, posf, posr, numpos);
365     if (gs->ep_possible[0][onf] == 1)
366       add_pos(onf + 1, onr + 1, posf, posr, numpos);
367   } else {
368     if (gs->board[onf][onr - 1] == NOPIECE) {
369       add_pos(onf, onr - 1, posf, posr, numpos);
370       if ((onr == 6) && (gs->board[onf][onr - 2] == NOPIECE))
371         add_pos(onf, onr - 2, posf, posr, numpos);
372     }
373     if ((onf > 0) && (gs->board[onf - 1][onr - 1] != NOPIECE) &&
374         (iscolor(gs->board[onf - 1][onr - 1], WHITE)))
375       add_pos(onf - 1, onr - 1, posf, posr, numpos);
376 /* loon: changed what looks like a typo, here's the original line:
377       add_pos(onf - 1, onr + 1, posf, posr, numpos);
378 */
379     if ((onf < 7) && (gs->board[onf + 1][onr - 1] != NOPIECE) &&
380         (iscolor(gs->board[onf + 1][onr - 1], WHITE)))
381       add_pos(onf + 1, onr - 1, posf, posr, numpos);
382     if (gs->ep_possible[1][onf] == -1)
383       add_pos(onf - 1, onr - 1, posf, posr, numpos);
384     if (gs->ep_possible[1][onf] == 1)
385       add_pos(onf + 1, onr - 1, posf, posr, numpos);
386   }
387 }
388
389 static void possible_knight_moves(struct game_state_t * gs,
390                                     int onf, int onr,
391                                     int *posf, int *posr, int *numpos)
392 {
393   static int knightJumps[8][2] = {{-1, 2}, {1, 2}, {2, -1}, {2, 1},
394   {-1, -2}, {1, -2}, {-2, 1}, {-2, -1}};
395   int f, r;
396   int j;
397
398   for (j = 0; j < 8; j++) {
399     f = knightJumps[j][0] + onf;
400     r = knightJumps[j][1] + onr;
401     if ((f < 0) || (f > 7))
402       continue;
403     if ((r < 0) || (r > 7))
404       continue;
405     if ((gs->board[f][r] == NOPIECE) ||
406         (iscolor(gs->board[f][r], CToggle(gs->onMove))))
407       add_pos(f, r, posf, posr, numpos);
408   }
409 }
410
411 static void possible_bishop_moves(struct game_state_t * gs,
412                                     int onf, int onr,
413                                     int *posf, int *posr, int *numpos)
414 {
415   int f, r;
416
417   /* Up Left */
418   f = onf;
419   r = onr;
420   for (;;) {
421     f--;
422     r++;
423     if ((f < 0) || (f > 7))
424       break;
425     if ((r < 0) || (r > 7))
426       break;
427     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
428       break;
429     add_pos(f, r, posf, posr, numpos);
430     if (gs->board[f][r] != NOPIECE)
431       break;
432   }
433   /* Up Right */
434   f = onf;
435   r = onr;
436   for (;;) {
437     f++;
438     r++;
439     if ((f < 0) || (f > 7))
440       break;
441     if ((r < 0) || (r > 7))
442       break;
443     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
444       break;
445     add_pos(f, r, posf, posr, numpos);
446     if (gs->board[f][r] != NOPIECE)
447       break;
448   }
449   /* Down Left */
450   f = onf;
451   r = onr;
452   for (;;) {
453     f--;
454     r--;
455     if ((f < 0) || (f > 7))
456       break;
457     if ((r < 0) || (r > 7))
458       break;
459     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
460       break;
461     add_pos(f, r, posf, posr, numpos);
462     if (gs->board[f][r] != NOPIECE)
463       break;
464   }
465   /* Down Right */
466   f = onf;
467   r = onr;
468   for (;;) {
469     f++;
470     r--;
471     if ((f < 0) || (f > 7))
472       break;
473     if ((r < 0) || (r > 7))
474       break;
475     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
476       break;
477     add_pos(f, r, posf, posr, numpos);
478     if (gs->board[f][r] != NOPIECE)
479       break;
480   }
481 }
482
483 static void possible_rook_moves(struct game_state_t * gs,
484                                   int onf, int onr,
485                                   int *posf, int *posr, int *numpos)
486 {
487   int f, r;
488
489   /* Left */
490   f = onf;
491   r = onr;
492   for (;;) {
493     f--;
494     if ((f < 0) || (f > 7))
495       break;
496     if ((r < 0) || (r > 7))
497       break;
498     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
499       break;
500     add_pos(f, r, posf, posr, numpos);
501     if (gs->board[f][r] != NOPIECE)
502       break;
503   }
504   /* Right */
505   f = onf;
506   r = onr;
507   for (;;) {
508     f++;
509     if ((f < 0) || (f > 7))
510       break;
511     if ((r < 0) || (r > 7))
512       break;
513     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
514       break;
515     add_pos(f, r, posf, posr, numpos);
516     if (gs->board[f][r] != NOPIECE)
517       break;
518   }
519   /* Up */
520   f = onf;
521   r = onr;
522   for (;;) {
523     r++;
524     if ((f < 0) || (f > 7))
525       break;
526     if ((r < 0) || (r > 7))
527       break;
528     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
529       break;
530     add_pos(f, r, posf, posr, numpos);
531     if (gs->board[f][r] != NOPIECE)
532       break;
533   }
534   /* Down */
535   f = onf;
536   r = onr;
537   for (;;) {
538     r--;
539     if ((f < 0) || (f > 7))
540       break;
541     if ((r < 0) || (r > 7))
542       break;
543     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
544       break;
545     add_pos(f, r, posf, posr, numpos);
546     if (gs->board[f][r] != NOPIECE)
547       break;
548   }
549 }
550
551 static void possible_queen_moves(struct game_state_t * gs,
552                                    int onf, int onr,
553                                    int *posf, int *posr, int *numpos)
554 {
555   possible_rook_moves(gs, onf, onr, posf, posr, numpos);
556   possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
557 }
558
559 static void possible_king_moves(struct game_state_t * gs,
560                                   int onf, int onr,
561                                   int *posf, int *posr, int *numpos)
562 {
563   static int kingJumps[8][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 1},
564   {0, 1}, {1, 1}, {-1, 0}, {1, 0}};
565   int f, r;
566   int j;
567
568   for (j = 0; j < 8; j++) {
569     f = kingJumps[j][0] + onf;
570     r = kingJumps[j][1] + onr;
571     if ((f < 0) || (f > 7))
572       continue;
573     if ((r < 0) || (r > 7))
574       continue;
575     if ((gs->board[f][r] == NOPIECE) ||
576         (iscolor(gs->board[f][r], CToggle(gs->onMove))))
577       add_pos(f, r, posf, posr, numpos);
578   }
579 }
580
581 /* Doesn't check for check */
582 int legal_move(struct game_state_t * gs,
583                int fFile, int fRank,
584                int tFile, int tRank)
585 {
586   int move_piece;
587   int legal;
588
589   if (fFile == ALG_DROP) {
590     move_piece = fRank;
591     if (move_piece == KING)
592       return 0;
593     if (gs->holding[gs->onMove==WHITE ? 0 : 1][move_piece-1] == 0)
594       return 0;
595     if (gs->board[tFile][tRank] != NOPIECE)
596       return 0;
597     if (move_piece == PAWN && (tRank == 0 || tRank == 7))
598       return 0;
599     return 1;
600   } else {
601     move_piece = piecetype(gs->board[fFile][fRank]);
602   }
603   if (gs->board[fFile][fRank] == NOPIECE)
604     return 0;
605   if (!iscolor(gs->board[fFile][fRank], gs->onMove))    /* Wrong color */
606     return 0;
607   if ((gs->board[tFile][tRank] != NOPIECE) &&
608       iscolor(gs->board[tFile][tRank], gs->onMove))     /* Can't capture own */
609     return 0;
610   if ((fFile == tFile) && (fRank == tRank))     /* Same square */
611     return 0;
612   switch (move_piece) {
613   case PAWN:
614     legal = legal_pawn_move(gs, fFile, fRank, tFile, tRank);
615     break;
616   case KNIGHT:
617     legal = legal_knight_move(gs, fFile, fRank, tFile, tRank);
618     break;
619   case BISHOP:
620     legal = legal_bishop_move(gs, fFile, fRank, tFile, tRank);
621     break;
622   case ROOK:
623     legal = legal_rook_move(gs, fFile, fRank, tFile, tRank);
624     break;
625   case QUEEN:
626     legal = legal_queen_move(gs, fFile, fRank, tFile, tRank);
627     break;
628   case KING:
629     legal = legal_king_move(gs, fFile, fRank, tFile, tRank);
630     break;
631   default:
632     return 0;
633     break;
634   }
635   return legal;
636 }
637
638 #define DROP_CHAR '@'
639
640 /* This fills in the rest of the mt structure once it is determined that
641  * the move is legal. Returns MOVE_ILLEGAL if move leaves you in check */
642 static int move_calculate(struct game_state_t * gs, struct move_t * mt, int promote)
643 {
644   struct game_state_t fakeMove;
645
646   mt->pieceCaptured = gs->board[mt->toFile][mt->toRank];
647   mt->enPassant = 0;            /* Don't know yet, let execute move take care
648                                    of it */
649   if (mt->fromFile == ALG_DROP) {
650     mt->piecePromotionTo = NOPIECE;
651     sprintf(mt->moveString, "%s/%c%c-%c%d",
652             wpstring[mt->fromRank],
653                 DROP_CHAR, DROP_CHAR,
654             mt->toFile + 'a', mt->toRank + 1);
655   } else {
656   if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&
657       ((mt->toRank == 0) || (mt->toRank == 7))) {
658     mt->piecePromotionTo = promote |
659       (colorval(gs->board[mt->fromFile][mt->fromRank]));
660   } else {
661     mt->piecePromotionTo = NOPIECE;
662   }
663   if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&
664    ((mt->fromRank - mt->toRank == 2) || (mt->toRank - mt->fromRank == 2))) {
665     mt->doublePawn = mt->fromFile;
666   } else {
667     mt->doublePawn = -1;
668   }
669   if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&
670       (mt->fromFile == 4) && (mt->toFile == 2)) {
671     sprintf(mt->moveString, "o-o-o");
672   } else if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&
673              (mt->fromFile == 4) && (mt->toFile == 6)) {
674     sprintf(mt->moveString, "o-o");
675   } else {
676     sprintf(mt->moveString, "%s/%c%d-%c%d",
677             wpstring[piecetype(gs->board[mt->fromFile][mt->fromRank])],
678             mt->fromFile + 'a', mt->fromRank + 1,
679             mt->toFile + 'a', mt->toRank + 1);
680   }
681   }
682   /* Replace this with an algabraic de-parser */
683
684   sprintf(mt->algString, alg_unparse(gs, mt));
685   fakeMove = *gs;
686   /* Calculates enPassant also */
687   execute_move(&fakeMove, mt, 0);
688
689   /* Does making this move leave ME in check? */
690   if (in_check(&fakeMove))
691     return MOVE_ILLEGAL;
692   /* IanO: bughouse variants: drop cannot be check/checkmate */
693
694   return MOVE_OK;
695 }
696
697 int legal_andcheck_move(struct game_state_t * gs,
698                         int fFile, int fRank,
699                         int tFile, int tRank)
700 {
701   struct move_t mt;
702   if (!legal_move(gs, fFile, fRank, tFile, tRank))
703     return 0;
704   mt.color = gs->onMove;
705   mt.fromFile = fFile;
706   mt.fromRank = fRank;
707   mt.toFile = tFile;
708   mt.toRank = tRank;
709   /* This should take into account a pawn promoting to another piece */
710   if (move_calculate(gs, &mt, QUEEN) == MOVE_OK)
711     return 1;
712   else
713     return 0;
714 }
715
716 /* in_check: checks if the side that is NOT about to move is in check 
717  */
718 int in_check(struct game_state_t * gs)
719 {
720   int f, r;
721   int kf = -1, kr = -1;
722
723   /* Find the king */
724   if (gs->onMove == WHITE) {
725     for (f = 0; f < 8 && kf < 0; f++)
726       for (r = 0; r < 8 && kf < 0; r++)
727         if (gs->board[f][r] == B_KING) {
728           kf = f;
729           kr = r;
730         }
731   } else {
732     for (f = 0; f < 8 && kf < 0; f++)
733       for (r = 0; r < 8 && kf < 0; r++)
734         if (gs->board[f][r] == W_KING) {
735           kf = f;
736           kr = r;
737         }
738   }
739   if (kf < 0) {
740     d_printf( "CHESSD: Error game with no king!\n");
741     return 0;
742   }
743   for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
744        NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
745     if (legal_move(gs, f, r, kf, kr)) { /* In Check? */
746       return 1;
747     }
748   }
749   return 0;
750 }
751
752 int has_legal_move(struct game_state_t * gs)
753 {
754   int i;
755   int f, r;
756   int kf = 0, kr = 0;
757   int possiblef[500], possibler[500];
758   int numpossible = 0;
759
760   for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
761        NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
762     switch (piecetype(gs->board[f][r])) {
763     case PAWN:
764       possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible);
765       break;
766     case KNIGHT:
767       possible_knight_moves(gs, f, r, possiblef, possibler, &numpossible);
768       break;
769     case BISHOP:
770       possible_bishop_moves(gs, f, r, possiblef, possibler, &numpossible);
771       break;
772     case ROOK:
773       possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible);
774       break;
775     case QUEEN:
776       possible_queen_moves(gs, f, r, possiblef, possibler, &numpossible);
777       break;
778     case KING:
779       kf = f;
780       kr = r;
781       possible_king_moves(gs, f, r, possiblef, possibler, &numpossible);
782       break;
783     }
784     if (numpossible >= 500) {
785       d_printf( "CHESSD: Possible move overrun\n");
786     }
787     for (i = 0; i < numpossible; i++)
788       if (legal_andcheck_move(gs, f, r, possiblef[i], possibler[i])) {
789         return 1;
790       }
791   }
792
793   /* IanO:  if we got here, then kf and kr must be set */
794   if (gs->gameNum >=0 && game_globals.garray[gs->gameNum].link >= 0) {
795     /* bughouse: potential drops as check interpositions */
796     gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]++;
797     for (f=kf-1; f<=kf+1; f++) for (r=kr-1; r<=kr+1; r++) {
798       if (f>=0 && f<8 && r>=0 && r<8 && gs->board[f][r] == NOPIECE) {
799         /* try a drop next to the king */
800         if (legal_andcheck_move(gs, ALG_DROP, QUEEN, f, r)) {
801           gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;
802           return 1;
803         }
804       }
805     }
806     gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;
807   }
808
809   return 0;
810 }
811
812 /* This will end up being a very complicated function */
813 int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int promote)
814 {
815   int type = is_move(mstr);
816   int result;
817
818   mt->piecePromotionTo = NOPIECE;
819   mt->color = gs->onMove;
820   switch (type) {
821   case MS_NOTMOVE:
822     return MOVE_ILLEGAL;
823     break;
824   case MS_COMP:
825     mt->fromFile = mstr[0] - 'a';
826     mt->fromRank = mstr[1] - '1';
827     mt->toFile = mstr[2] - 'a';
828     mt->toRank = mstr[3] - '1';
829     break;
830   case MS_COMPDASH:
831     mt->fromFile = mstr[0] - 'a';
832     mt->fromRank = mstr[1] - '1';
833     mt->toFile = mstr[3] - 'a';
834     mt->toRank = mstr[4] - '1';
835     break;
836   case MS_KCASTLE:
837     mt->fromFile = 4;
838     mt->toFile = 6;
839     if (gs->onMove == WHITE) {
840       mt->fromRank = 0;
841       mt->toRank = 0;
842     } else {
843       mt->fromRank = 7;
844       mt->toRank = 7;
845     }
846     break;
847   case MS_QCASTLE:
848     mt->fromFile = 4;
849     mt->toFile = 2;
850     if (gs->onMove == WHITE) {
851       mt->fromRank = 0;
852       mt->toRank = 0;
853     } else {
854       mt->fromRank = 7;
855       mt->toRank = 7;
856     }
857     break;
858   case MS_ALG:
859     /* Fills in the mt structure */
860     if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK)
861       return result;
862     break;
863   default:
864     return MOVE_ILLEGAL;
865     break;
866   }
867   if (!legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)) {
868     return MOVE_ILLEGAL;
869   }
870
871   if (mt->piecePromotionTo != NOPIECE) {
872           promote = piecetype(mt->piecePromotionTo);
873   }
874
875   return move_calculate(gs, mt, promote);
876 }
877
878 /* Returns MOVE_OK, MOVE_NOMATERIAL, MOVE_CHECKMATE, or MOVE_STALEMATE */
879 /* check_game_status prevents recursion */
880 int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_status)
881 {
882   int movedPiece;
883   int tookPiece;
884   int i, j, foobar;
885
886   if (mt->fromFile == ALG_DROP) {
887     movedPiece = mt->fromRank;
888     tookPiece = NOPIECE;
889     gs->holding[gs->onMove==WHITE ? 0 : 1][movedPiece-1]--;
890     gs->board[mt->toFile][mt->toRank] = movedPiece | gs->onMove;
891     if (gs->gameNum >= 0)
892       gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
893   } else {
894   movedPiece = gs->board[mt->fromFile][mt->fromRank];
895   tookPiece = gs->board[mt->toFile][mt->toRank];
896   if (mt->piecePromotionTo == NOPIECE) {
897     gs->board[mt->toFile][mt->toRank] = gs->board[mt->fromFile][mt->fromRank];
898   } else {
899     gs->board[mt->toFile][mt->toRank] = mt->piecePromotionTo | gs->onMove;
900   }
901   gs->board[mt->fromFile][mt->fromRank] = NOPIECE;
902   /* Check if irreversable */
903   if ((piecetype(movedPiece) == PAWN) || (tookPiece != NOPIECE)) {
904     if (gs->gameNum >= 0)
905       gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
906   }
907   /* Check if this move is en-passant */
908   if ((piecetype(movedPiece) == PAWN) && (mt->fromFile != mt->toFile) &&
909       (tookPiece == NOPIECE)) {
910     if (gs->onMove == WHITE) {
911       mt->pieceCaptured = B_PAWN;
912     } else {
913       mt->pieceCaptured = W_PAWN;
914     }
915     if (mt->fromFile > mt->toFile) {
916       mt->enPassant = -1;
917     } else {
918       mt->enPassant = 1;
919     }
920     gs->board[mt->toFile][mt->fromRank] = NOPIECE;
921   }
922   /* Check en-passant flags for next moves */
923   for (i = 0; i < 8; i++) {
924     gs->ep_possible[0][i] = 0;
925     gs->ep_possible[1][i] = 0;
926   }
927 /* Added by Sparky 3/16/95
928
929    From soso@Viktoria.drp.fmph.uniba.sk Thu Mar 16 13:08:51 1995
930    Subject: Re: To DAV: enpassant prob. again
931    To: chess@caissa.onenet.net (ICS)
932    Date: Thu, 16 Mar 1995 20:06:20 +0100 (MET)
933
934    Yeah !
935    There was bug in other part of code:
936
937    movecheck.c , line about 800:
938
939      if (gs->onMove == WHITE) {
940         if ((mt->toFile+1 < 7 ) ....  should be : (mt->toFile < 7 ) }
941 */
942
943   if ((piecetype(movedPiece) == PAWN) &&
944    ((mt->fromRank == mt->toRank + 2) || (mt->fromRank + 2 == mt->toRank))) {
945     /* Should turn on enpassent flag if possible */
946     if (gs->onMove == WHITE) {
947       if ((mt->toFile < 7) && gs->board[mt->toFile + 1][3] == B_PAWN) {
948         gs->ep_possible[1][mt->toFile + 1] = -1;
949       }
950       if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][3] == B_PAWN) {
951         gs->ep_possible[1][mt->toFile - 1] = 1;
952       }
953     } else {
954       if ((mt->toFile < 7) && gs->board[mt->toFile + 1][4] == W_PAWN) {
955         gs->ep_possible[0][mt->toFile + 1] = -1;
956       }
957       if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][4] == W_PAWN) {
958         gs->ep_possible[0][mt->toFile - 1] = 1;
959       }
960     }
961   }
962   if ((piecetype(movedPiece) == ROOK) && (mt->fromFile == 0)) {
963     if ((mt->fromRank == 0) && (gs->onMove == WHITE))
964       gs->wqrmoved = 1;
965     if ((mt->fromRank == 7) && (gs->onMove == BLACK))
966       gs->bqrmoved = 1;
967   }
968   if ((piecetype(movedPiece) == ROOK) && (mt->fromFile == 7)) {
969     if ((mt->fromRank == 0) && (gs->onMove == WHITE))
970       gs->wkrmoved = 1;
971     if ((mt->fromRank == 7) && (gs->onMove == BLACK))
972       gs->bkrmoved = 1;
973   }
974   if (piecetype(movedPiece) == KING) {
975     if (gs->onMove == WHITE)
976       gs->wkmoved = 1;
977     else
978       gs->bkmoved = 1;
979   }
980   if ((piecetype(movedPiece) == KING) &&
981       ((mt->fromFile == 4) && ((mt->toFile == 6)))) {   /* Check for KS castling */
982     gs->board[5][mt->toRank] = gs->board[7][mt->toRank];
983     gs->board[7][mt->toRank] = NOPIECE;
984   }
985   if ((piecetype(movedPiece) == KING) &&
986       ((mt->fromFile == 4) && ((mt->toFile == 2)))) {   /* Check for QS castling */
987     gs->board[3][mt->toRank] = gs->board[0][mt->toRank];
988     gs->board[0][mt->toRank] = NOPIECE;
989   }
990   }
991   if (gs->onMove == BLACK)
992     gs->moveNum++;
993
994   if (check_game_status) {
995     /* Does this move result in check? */
996     if (in_check(gs)) {
997       /* Check for checkmate */
998       gs->onMove = CToggle(gs->onMove);
999       if (!has_legal_move(gs))
1000         return MOVE_CHECKMATE;
1001     } else {
1002       /* Check for stalemate */
1003       gs->onMove = CToggle(gs->onMove);
1004       if (!has_legal_move(gs))
1005         return MOVE_STALEMATE;
1006 /* loon: check for insufficient mating material, first try */
1007       foobar = 0;
1008       for (i=0; i<8; i++) {
1009         for (j=0; j<8; j++) {
1010           switch(piecetype(gs->board[i][j])) {
1011             case KNIGHT:
1012             case BISHOP:
1013               foobar++;
1014               break;
1015             case KING:
1016             case NOPIECE:
1017               break;
1018             default:
1019               foobar = 2;
1020               break;
1021           }
1022         }
1023       }
1024       if (foobar < 2)
1025         return MOVE_NOMATERIAL;
1026     }
1027   } else {
1028     gs->onMove = CToggle(gs->onMove);
1029   }
1030   return MOVE_OK;
1031 }
1032
1033 int backup_move(int g, int mode)
1034 {
1035   struct game_state_t *gs;
1036   struct move_t *m, *m1;
1037   int now, i;
1038
1039   if (game_globals.garray[g].link >= 0) /*IanO: not implemented for bughouse yet */
1040     return MOVE_ILLEGAL;
1041   if (game_globals.garray[g].numHalfMoves < 1)
1042     return MOVE_ILLEGAL;
1043   gs = &game_globals.garray[g].game_state;
1044   m = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] : 
1045                          &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];
1046   if (m->toFile < 0) {
1047     return MOVE_ILLEGAL;
1048   }
1049   gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank];
1050   if (m->piecePromotionTo != NOPIECE) {
1051     gs->board[m->fromFile][m->fromRank] = PAWN |
1052       colorval(gs->board[m->fromFile][m->fromRank]);
1053   }
1054   /******************
1055      When takeback a _first_ move of rook, the ??rmoved variable
1056      must be cleared . To check, if the move is first, we should
1057      scan moveList.
1058   *******************/
1059   if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) {
1060     if (m->color == WHITE) {
1061       if ((m->fromFile == 0) && (m->fromRank == 0)) {
1062         for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1063           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1064           if ((m1->fromFile == 0) && (m1->fromRank == 0))
1065             break;
1066         }
1067         if (i == game_globals.garray[g].numHalfMoves - 1)
1068           gs->wqrmoved = 0;
1069       }
1070       if ((m->fromFile == 7) && (m->fromRank == 0)) {
1071         for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1072           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1073           if ((m1->fromFile == 7) && (m1->fromRank == 0))
1074             break;
1075         }
1076         if (i == game_globals.garray[g].numHalfMoves - 1)
1077           gs->wkrmoved = 0;
1078       }
1079     } else {
1080       if ((m->fromFile == 0) && (m->fromRank == 7)) {
1081         for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1082           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1083           if ((m1->fromFile == 0) && (m1->fromRank == 0))
1084             break;
1085         }
1086         if (i == game_globals.garray[g].numHalfMoves - 1)
1087           gs->bqrmoved = 0;
1088       }
1089       if ((m->fromFile == 7) && (m->fromRank == 7)) {
1090         for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1091           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1092           if ((m1->fromFile == 7) && (m1->fromRank == 0))
1093             break;
1094         }
1095         if (i == game_globals.garray[g].numHalfMoves - 1)
1096           gs->bkrmoved = 0;
1097       }
1098     }
1099   }
1100   if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) {
1101     gs->board[m->toFile][m->toRank] = m->pieceCaptured;
1102
1103     if (m->toFile - m->fromFile == 2) {
1104       gs->board[7][m->fromRank] = ROOK |
1105         colorval(gs->board[m->fromFile][m->fromRank]);
1106       gs->board[5][m->fromRank] = NOPIECE;
1107
1108       /********
1109          If takeback a castling, the appropriates ??moved variables
1110          must be cleared
1111       ********/
1112       if (m->color == WHITE) {
1113         gs->wkmoved = 0;
1114         gs->wkrmoved = 0;
1115       } else {
1116         gs->bkmoved = 0;
1117         gs->bkrmoved = 0;
1118       }
1119       goto cleanupMove;
1120     }
1121     if (m->fromFile - m->toFile == 2) {
1122       gs->board[0][m->fromRank] = ROOK |
1123         colorval(gs->board[m->fromFile][m->fromRank]);
1124       gs->board[3][m->fromRank] = NOPIECE;
1125
1126       /**********
1127          If takeback a castling, the appropriate ??moved variables
1128          must be cleared
1129       ***********/
1130       if (m->color == WHITE) {
1131         gs->wkmoved = 0;
1132         gs->wqrmoved = 0;
1133       } else {
1134         gs->bkmoved = 0;
1135         gs->bqrmoved = 0;
1136       }
1137       goto cleanupMove;
1138     }
1139     /******************
1140        When takeback a _first_ move of king (not the castling),
1141        the ?kmoved variable must be cleared . To check, if the move is first,
1142        we should scan moveList.
1143     *******************/
1144
1145     if (m->color == WHITE) {
1146
1147       if ((m->fromFile == 4) && (m->fromRank == 0)) {
1148         for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1149           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1150           if ((m1->fromFile == 4) && (m1->fromRank == 0))
1151             break;
1152         }
1153         if (i == game_globals.garray[g].numHalfMoves - 1)
1154           gs->wkmoved = 0;
1155       }
1156     } else {
1157       if ((m->fromFile == 4) && (m->fromRank == 7)) {
1158         for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
1159           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
1160           if ((m1->fromFile == 4) && (m1->fromRank == 7))
1161             break;
1162         }
1163         if (i == game_globals.garray[g].numHalfMoves - 1)
1164           gs->bkmoved = 0;
1165       }
1166     }
1167   }
1168   if (m->enPassant) {           /* Do enPassant */
1169     gs->board[m->toFile][m->fromRank] = PAWN |
1170       (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE ? BLACK : WHITE);
1171     gs->board[m->toFile][m->toRank] = NOPIECE;
1172     /* Should set the enpassant array, but I don't care right now */
1173     goto cleanupMove;
1174   }
1175   gs->board[m->toFile][m->toRank] = m->pieceCaptured;
1176 cleanupMove:
1177   if (game_globals.garray[g].status != GAME_EXAMINE) {
1178     game_update_time(g);
1179   }
1180   game_globals.garray[g].numHalfMoves--;
1181   if (game_globals.garray[g].status != GAME_EXAMINE) {
1182     if (game_globals.garray[g].wInitTime) {     /* Don't update times in untimed games */
1183       now = tenth_secs();
1184
1185       if (m->color == WHITE) {
1186         if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) {  /* white uses timeseal? */      
1187           game_globals.garray[g].wRealTime += (m->tookTime * 100); 
1188           game_globals.garray[g].wRealTime -= (game_globals.garray[g].wIncrement * 100);
1189           game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
1190           if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* opp uses timeseal? */
1191             game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
1192           } else {    /* opp has no timeseal */
1193             game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1194           }
1195         } else {  /* white has no timeseal */
1196           game_globals.garray[g].wTime += m->tookTime;
1197           game_globals.garray[g].wTime -= game_globals.garray[g].wIncrement;
1198           if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* opp uses timeseal? */
1199             game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
1200           } else {    /* opp has no timeseal */
1201             game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1202           }
1203         }
1204       } else {
1205         if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) {  /* black uses timeseal? */
1206           game_globals.garray[g].bRealTime += (m->tookTime * 100);
1207           game_globals.garray[g].bRealTime -= (game_globals.garray[g].wIncrement * 100);
1208           game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
1209           if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* opp uses timeseal? */
1210             game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
1211           } else {    /* opp has no timeseal */
1212             game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1213           }
1214         } else {  /* black has no timeseal */
1215           game_globals.garray[g].bTime += m->tookTime;
1216           if (!game_globals.garray[g].bIncrement)
1217             game_globals.garray[g].bTime -= game_globals.garray[g].wIncrement;
1218           else
1219             game_globals.garray[g].bTime -= game_globals.garray[g].bIncrement;
1220           if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* opp uses timeseal? */
1221             game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
1222           } else {    /* opp has no timeseal */
1223             game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
1224           }
1225         }
1226       }
1227
1228       if (game_globals.garray[g].numHalfMoves == 0)
1229         game_globals.garray[g].timeOfStart = now;
1230       game_globals.garray[g].lastMoveTime = now;
1231       game_globals.garray[g].lastDecTime = now;
1232     }
1233   }
1234   if (gs->onMove == BLACK)
1235     gs->onMove = WHITE;
1236   else {
1237     gs->onMove = BLACK;
1238     gs->moveNum--;
1239   }
1240
1241   /******* Here begins the patch : ********************************
1242      Takeback of last move is done already, it's time to update enpassant
1243      array.  (patch from Soso, added by Sparky 3/17/95)
1244   ********/
1245
1246   if (game_globals.garray[g].numHalfMoves > 0) {
1247     m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] : 
1248                             &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];
1249     if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) {
1250       if ((m1->toRank - m1->fromRank) == 2) {
1251         if ((m1->toFile < 7) && gs->board[m1->toFile + 1][3] == B_PAWN) {
1252           gs->ep_possible[1][m1->toFile + 1] = -1;
1253         }
1254         if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][3] == B_PAWN) {
1255           gs->ep_possible[1][m1->toFile - 1] = 1;
1256         }
1257       }
1258       if ((m1->toRank - m1->fromRank) == -2) {
1259         if ((m1->toFile < 7) && gs->board[m1->toFile + 1][4] == W_PAWN) {
1260           gs->ep_possible[0][m1->toFile + 1] = -1;
1261         }
1262         if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][4] == W_PAWN) {
1263           gs->ep_possible[0][m1->toFile - 1] = 1;
1264         }
1265       }
1266     }
1267   }
1268   /************** and here's the end **************/
1269   return MOVE_OK;
1270 }
1271
1272
1273
1274