1 /* move.c
2
3 GNU Chess frontend
4
5 Copyright (C) 2001-2020 Free Software Foundation, Inc.
6
7 GNU Chess is based on the two research programs
8 Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22
23 Contact Info:
24 bug-gnu-chess@gnu.org
25 cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include "common.h"
33
MakeMove(int side,int * move)34 void MakeMove (int side, int *move)
35 /**************************************************************************
36 *
37 * To make a move on the board and update the various game information.
38 *
39 **************************************************************************/
40 {
41 BitBoard *a;
42 int f, t, fpiece, tpiece;
43 int rookf, rookt, epsq, sq;
44 int xside;
45 GameRec *g;
46
47 xside = 1^side;
48 f = FROMSQ(*move);
49 t = TOSQ(*move);
50 fpiece = cboard[f];
51 tpiece = cboard[t];
52 a = &board.b[side][fpiece];
53 CLEARBIT (*a, f);
54 SETBIT (*a, t);
55 CLEARBIT (board.blockerr90, r90[f]);
56 SETBIT (board.blockerr90, r90[t]);
57 CLEARBIT (board.blockerr45, r45[f]);
58 SETBIT (board.blockerr45, r45[t]);
59 CLEARBIT (board.blockerr315, r315[f]);
60 SETBIT (board.blockerr315, r315[t]);
61 cboard[f] = empty;
62 cboard[t] = fpiece;
63 GameCnt++;
64 g = &Game[GameCnt];
65 g->epsq = board.ep;
66 g->bflag = board.flag;
67 g->Game50 = Game50;
68 g->hashkey = HashKey;
69 g->phashkey = PawnHashKey;
70 g->mvboard = Mvboard[t];
71 g->comments = NULL;
72 Mvboard[t] = Mvboard[f]+1;
73 Mvboard[f] = 0;
74 if (board.ep > -1)
75 HashKey ^= ephash[board.ep];
76 HashKey ^= hashcode[side][fpiece][f];
77 HashKey ^= hashcode[side][fpiece][t];
78 if (fpiece == king)
79 board.king[side] = t;
80 if (fpiece == pawn)
81 {
82 PawnHashKey ^= hashcode[side][pawn][f];
83 PawnHashKey ^= hashcode[side][pawn][t];
84 }
85
86 if (tpiece != 0) /* Capture */
87 {
88 ExchCnt[side]++;
89 CLEARBIT (board.b[xside][tpiece], t);
90 *move |= (tpiece << 15);
91 HashKey ^= hashcode[xside][tpiece][t];
92 if (tpiece == pawn)
93 PawnHashKey ^= hashcode[xside][pawn][t];
94 board.material[xside] -= Value[tpiece];
95 if (tpiece != pawn)
96 board.pmaterial[xside] -= Value[tpiece];
97 }
98
99 if (*move & PROMOTION) /* Promotion */
100 {
101 SETBIT (board.b[side][PROMOTEPIECE (*move)], t);
102 CLEARBIT (*a, t);
103 cboard[t] = PROMOTEPIECE (*move);
104 HashKey ^= hashcode[side][pawn][t];
105 HashKey ^= hashcode[side][cboard[t]][t];
106 PawnHashKey ^= hashcode[side][pawn][t];
107 board.material[side] += (Value[cboard[t]] - ValueP);
108 board.pmaterial[side] += Value[cboard[t]];
109 }
110
111 if (*move & ENPASSANT) /* En passant */
112 {
113 ExchCnt[side]++;
114 epsq = board.ep + (side == white ? - 8 : 8);
115 CLEARBIT (board.b[xside][pawn], epsq);
116 CLEARBIT (board.blockerr90, r90[epsq]);
117 CLEARBIT (board.blockerr45, r45[epsq]);
118 CLEARBIT (board.blockerr315, r315[epsq]);
119 cboard[epsq] = empty;
120 HashKey ^= hashcode[xside][pawn][epsq];
121 PawnHashKey ^= hashcode[xside][pawn][epsq];
122 board.material[xside] -= ValueP;
123 }
124 if (*move & (CAPTURE | CASTLING) || fpiece == pawn)
125 Game50 = GameCnt;
126
127 if (*move & CASTLING) /* Castling */
128 {
129 if (t & 0x04) /* King side */
130 {
131 rookf = t + 1;
132 rookt = t - 1;
133 }
134 else /* Queen side */
135 {
136 rookf = t - 2;
137 rookt = t + 1;
138 }
139 a = &board.b[side][rook];
140 CLEARBIT (*a, rookf);
141 SETBIT (*a, rookt);
142 CLEARBIT (board.blockerr90, r90[rookf]);
143 SETBIT (board.blockerr90, r90[rookt]);
144 CLEARBIT (board.blockerr45, r45[rookf]);
145 SETBIT (board.blockerr45, r45[rookt]);
146 CLEARBIT (board.blockerr315, r315[rookf]);
147 SETBIT (board.blockerr315, r315[rookt]);
148 cboard[rookf] = empty;
149 cboard[rookt] = rook;
150 Mvboard[rookf] = 0;
151 Mvboard[rookt] = 1;
152 HashKey ^= hashcode[side][rook][rookf];
153 HashKey ^= hashcode[side][rook][rookt];
154 board.castled[side] = true;
155 }
156
157 /* If king or rook move, clear castle flag. */
158 if (side == white)
159 {
160 if (fpiece == king && board.flag & WCASTLE)
161 {
162 if (board.flag & WKINGCASTLE)
163 HashKey ^= WKCastlehash;
164 if (board.flag & WQUEENCASTLE)
165 HashKey ^= WQCastlehash;
166 board.flag &= ~WCASTLE;
167 }
168 else if (fpiece == rook)
169 {
170 if (f == H1)
171 {
172 if (board.flag & WKINGCASTLE)
173 HashKey ^= WKCastlehash;
174 board.flag &= ~WKINGCASTLE;
175 }
176 else if (f == A1)
177 {
178 if (board.flag & WQUEENCASTLE)
179 HashKey ^= WQCastlehash;
180 board.flag &= ~WQUEENCASTLE;
181 }
182 }
183 if (tpiece == rook)
184 {
185 if (t == H8)
186 {
187 if (board.flag & BKINGCASTLE)
188 HashKey ^= BKCastlehash;
189 board.flag &= ~BKINGCASTLE;
190 }
191 else if (t == A8)
192 {
193 if (board.flag & BQUEENCASTLE)
194 HashKey ^= BQCastlehash;
195 board.flag &= ~BQUEENCASTLE;
196 }
197 }
198 }
199 else
200 {
201 if (fpiece == king && board.flag & BCASTLE)
202 {
203 if (board.flag & BKINGCASTLE)
204 HashKey ^= BKCastlehash;
205 if (board.flag & BQUEENCASTLE)
206 HashKey ^= BQCastlehash;
207 board.flag &= ~BCASTLE;
208 }
209 else if (fpiece == rook)
210 {
211 if (f == H8)
212 {
213 if (board.flag & BKINGCASTLE)
214 HashKey ^= BKCastlehash;
215 board.flag &= ~BKINGCASTLE;
216 }
217 else if (f == A8)
218 {
219 if (board.flag & BQUEENCASTLE)
220 HashKey ^= BQCastlehash;
221 board.flag &= ~BQUEENCASTLE;
222 }
223 }
224 if (tpiece == rook)
225 {
226 if (t == H1)
227 {
228 if (board.flag & WKINGCASTLE)
229 HashKey ^= WKCastlehash;
230 board.flag &= ~WKINGCASTLE;
231 }
232 else if (t == A1)
233 {
234 if (board.flag & WQUEENCASTLE)
235 HashKey ^= WQCastlehash;
236 board.flag &= ~WQUEENCASTLE;
237 }
238 }
239 }
240
241
242 /* If pawn move 2 squares, set ep passant square. */
243 if (fpiece == pawn && abs(f-t) == 16)
244 {
245 sq = (f + t) / 2;
246 board.ep = sq;
247 HashKey ^= ephash[sq];
248 }
249 else
250 board.ep = -1;
251
252 board.side = xside;
253 HashKey ^= Sidehash;
254 UpdateFriends ();
255
256 /* Update game record */
257 g->move = *move;
258 return;
259 }
260
261
262
UnmakeMove(int side,int * move)263 void UnmakeMove (int side, int *move)
264 /****************************************************************************
265 *
266 * To unmake a move on the board and update the various game information.
267 * Note that if side is black, then black is about to move, but we will be
268 * undoing a move by white, not black.
269 *
270 ****************************************************************************/
271 {
272 BitBoard *a;
273 int f, t, fpiece, cpiece;
274 int rookf, rookt, epsq;
275 int xside;
276 GameRec *g;
277
278 side = 1^side;
279 xside = 1^side;
280 f = FROMSQ(*move);
281 t = TOSQ(*move);
282 fpiece = cboard[t];
283 cpiece = CAPTUREPIECE (*move);
284 a = &board.b[side][fpiece];
285 CLEARBIT (*a, t);
286 SETBIT (*a, f);
287 CLEARBIT (board.blockerr90, r90[t]);
288 SETBIT (board.blockerr90, r90[f]);
289 CLEARBIT (board.blockerr45, r45[t]);
290 SETBIT (board.blockerr45, r45[f]);
291 CLEARBIT (board.blockerr315, r315[t]);
292 SETBIT (board.blockerr315, r315[f]);
293 cboard[f] = cboard[t];
294 cboard[t] = empty;
295 g = &Game[GameCnt];
296 Mvboard[f] = Mvboard[t]-1;
297 Mvboard[t] = g->mvboard;
298 if (fpiece == king)
299 board.king[side] = f;
300
301 /* if capture, put back the captured piece */
302 if (*move & CAPTURE)
303 {
304 ExchCnt[side]--;
305 SETBIT (board.b[xside][cpiece], t);
306 SETBIT (board.blockerr90, r90[t]);
307 SETBIT (board.blockerr45, r45[t]);
308 SETBIT (board.blockerr315, r315[t]);
309 cboard[t] = cpiece;
310 board.material[xside] += Value[cpiece];
311 if (cpiece != pawn)
312 board.pmaterial[xside] += Value[cpiece];
313 }
314
315 /* Undo promotion */
316 if (*move & PROMOTION)
317 {
318 CLEARBIT (*a, f);
319 SETBIT (board.b[side][pawn], f);
320 cboard[f] = pawn;
321 board.material[side] += (ValueP - Value[PROMOTEPIECE (*move)]);
322 board.pmaterial[side] -= Value[PROMOTEPIECE (*move)];
323 }
324
325 /* Undo enpassant */
326 if (*move & ENPASSANT)
327 {
328 ExchCnt[side]--;
329 epsq = (side == white ? g->epsq - 8 : g->epsq + 8);
330 SETBIT (board.b[xside][pawn], epsq);
331 SETBIT (board.blockerr90, r90[epsq]);
332 SETBIT (board.blockerr45, r45[epsq]);
333 SETBIT (board.blockerr315, r315[epsq]);
334 cboard[epsq] = pawn;
335 board.material[xside] += ValueP;
336 }
337
338 /* if castling, undo rook move */
339 if (*move & CASTLING)
340 {
341 if (t & 0x04) /* King side */
342 {
343 rookf = t + 1;
344 rookt = t - 1;
345 }
346 else /* Queen side */
347 {
348 rookf = t - 2;
349 rookt = t + 1;
350 }
351 a = &board.b[side][rook];
352 CLEARBIT (*a, rookt);
353 SETBIT (*a, rookf);
354 CLEARBIT (board.blockerr90, r90[rookt]);
355 SETBIT (board.blockerr90, r90[rookf]);
356 CLEARBIT (board.blockerr45, r45[rookt]);
357 SETBIT (board.blockerr45, r45[rookf]);
358 CLEARBIT (board.blockerr315, r315[rookt]);
359 SETBIT (board.blockerr315, r315[rookf]);
360 cboard[rookf] = rook;
361 cboard[rookt] = empty;
362 Mvboard[rookf] = 0;
363 Mvboard[rookt] = 0;
364 board.castled[side] = false;
365 }
366
367 UpdateFriends ();
368 board.side = side;
369 board.ep = g->epsq;
370 board.flag = g->bflag;
371 HashKey = g->hashkey;
372 PawnHashKey = g->phashkey;
373 Game50 = g->Game50;
374 GameCnt--;
375 return;
376 }
377
378
SANMove(int move,int ply)379 void SANMove (int move, int ply)
380 /****************************************************************************
381 *
382 * Convert the move to a SAN format. GenMoves (ply) needs to be called
383 * by the calling routine for this to work.
384 *
385 ****************************************************************************/
386 {
387 int side;
388 int piece, ambiguous;
389 int f, t;
390 BitBoard b;
391 leaf *node1;
392 char *s;
393
394 side = board.side;
395 s = SANmv;
396 f = FROMSQ(move);
397 t = TOSQ(move);
398 /* Check some special moves like castling */
399 if (move & CASTLING)
400 {
401 if (t == 6 || t == 62)
402 strcpy (s, "O-O");
403 else
404 strcpy (s, "O-O-O");
405 return;
406 }
407
408 /****************************************************************************
409 *
410 * Here split the code into 2 parts for clarity sake. First part deals
411 * with pawn moves only, 2nd part only piece moves. However before doing
412 * that, see if the move is ambiguous.
413 *
414 ****************************************************************************/
415
416 /* AMBIGUITY CHECK */
417 piece = cboard[f];
418 side = board.side;
419 b = board.b[side][piece];
420 ambiguous = false;
421 node1 = TreePtr[ply];
422 if (nbits (b) > 1)
423 {
424 /*
425 * Scan the movelist to see if another same-type piece is
426 * also moving to that particular to-square.
427 */
428 for (node1 = TreePtr[ply]; node1 < TreePtr[ply + 1]; node1++)
429 {
430 if (FROMSQ(node1->move) == f)
431 continue; /* original piece, skip */
432 if (TOSQ(node1->move) != t)
433 continue; /* diff to-square, skip */
434 if (cboard[FROMSQ(node1->move)] != piece)
435 continue; /* diff piece */
436 ambiguous = true;
437 break;
438 }
439 }
440
441 if (piece == pawn)
442 {
443 /* Capture or enpassant */
444 if (cboard[t] != 0 || board.ep == t)
445 {
446 *s++ = algbrfile [ROW (f)];
447 *s++ = 'x';
448 }
449 strcpy (s, algbr[t]);
450 s += 2;
451
452 /* Promotion */
453 if (move & PROMOTION)
454 {
455 *s++ = '=';
456 *s++ = notation[PROMOTEPIECE (move)];
457 }
458 }
459 else /* its not pawn */
460 {
461 *s++ = notation[piece];
462 if (ambiguous)
463 {
464 if (ROW (f) == ROW (FROMSQ(node1->move)))
465 *s++ = algbrrank[RANK (f)];
466 else
467 *s++ = algbrfile[ROW (f)];
468 }
469 if (cboard[t] != 0) /* capture */
470 *s++ = 'x';
471 strcpy (s, algbr[t]);
472 s += 2;
473 }
474
475 /* See if it is a checking or mating move */
476 MakeMove (side, &move);
477 if (SqAtakd (board.king[1^side], side))
478 {
479 TreePtr[ply+2] = TreePtr[ply+1];
480 GenCheckEscapes (ply+1);
481 if (TreePtr[ply+1] == TreePtr[ply+2])
482 *s++ = '#';
483 else
484 *s++ = '+';
485 GenCnt -= TreePtr[ply+2] - TreePtr[ply+1];
486 }
487 UnmakeMove (1^side, &move);
488
489 *s = '\0';
490 return;
491 }
492
493
494 #define ASCIITOFILE(a) ((a) - 'a')
495 #define ASCIITORANK(a) ((a) - '1')
496 #define ASCIITOSQ(a,b) (ASCIITOFILE(a)) + (ASCIITORANK(b)) * 8
497 #define ATOH(a) ((a) >= 'a' && (a) <= 'h')
498 #define ITO8(a) ((a) >= '1' && (a) <= '8')
499
piece_id(const char c)500 inline int piece_id(const char c)
501 {
502 /* Given c, what is the piece id. This only takes one char, which
503 * isn't enough to handle two-character names (common in Russian text
504 * and old English notation that used Kt), but we're not supposed to
505 * see such text here anyway. This will
506 * accept "P" for pawn, and it used to accept many lowercase chars
507 * (but not "b" for Bishop). However, lowercase chars are no longer
508 * accepted, since they are not allowed by the Fruit engine. */
509 switch (c)
510 {
511 case 'N':
512 return knight;
513 case 'B':
514 return bishop;
515 case 'R':
516 return rook;
517 case 'Q':
518 return queen;
519 case 'K':
520 return king;
521 case 'P':
522 return pawn;
523 }
524 return empty;
525 }
526
527
528
ValidateMove(char * s,char * cleanMove)529 leaf * ValidateMove (char *s, char *cleanMove)
530 /*************************************************************************
531 *
532 * This routine takes a string and check to see if it is a legal move.
533 * Note. At the moment, we accept 2 types of moves notation.
534 * 1. e2e4 format. 2. SAN format. (e4)
535 *
536 **************************************************************************/
537 {
538 short f, t, side, rank, file, fileto;
539 short piece, piece2, kount;
540 char promote;
541 char mvstr[MAXSTR], *p;
542 BitBoard b, b2;
543 leaf *n1, *n2;
544
545 /* User input could be longer than MAXSTR */
546 if ( strlen(s) >= MAXSTR ) {
547 s[MAXSTR-1] = '\0';
548 }
549
550 TreePtr[2] = TreePtr[1];
551 GenMoves (1);
552 FilterIllegalMoves (1);
553 side = board.side;
554
555 /************************************************************************
556 * The thing to do now is to clean up the move string. This
557 * gets rid of things like 'x', '+', '=' and so forth.
558 ************************************************************************/
559 p = mvstr;
560 do
561 {
562 if (*s != 'x' && *s != '+' && *s != '=' && !isspace(*s))
563 *p++ = *s;
564 } while (*s++ != '\0' );
565
566 /* Flush castles that check */
567 if (mvstr[strlen(mvstr)-1] == '+' || mvstr[strlen(mvstr)-1] == '#' ||
568 mvstr[strlen(mvstr)-1] == '=') mvstr[strlen(mvstr)-1] = '\000';
569 if (cleanMove) strcpy(cleanMove, mvstr);
570
571 /* Check for castling */
572 if (strcmp (mvstr, "O-O") == 0 || strcmp (mvstr, "o-o") == 0 ||
573 strcmp (mvstr, "0-0") == 0)
574 {
575 if (cleanMove) strcpy(cleanMove, "O-O");
576 if (side == white)
577 {
578 f = 4; t = 6;
579 }
580 else
581 {
582 f = 60; t = 62;
583 }
584 return (IsInMoveList (1, f, t, ' '));
585 }
586
587 if (strcmp (mvstr, "O-O-O") == 0 || strcmp (mvstr, "o-o-o") == 0 ||
588 strcmp (mvstr, "0-0-0") == 0)
589 {
590 if (cleanMove) strcpy(cleanMove, "O-O-O");
591 if (side == white)
592 {
593 f = 4; t = 2;
594 }
595 else
596 {
597 f = 60; t = 58;
598 }
599 return (IsInMoveList (1, f, t, ' '));
600 }
601
602 /* Test to see if it is e2e4 type notation */
603 if (ATOH (mvstr[0]) && ITO8 (mvstr[1]) && ATOH (mvstr[2]) &&
604 ITO8 (mvstr[3]))
605 {
606 f = ASCIITOSQ (mvstr[0], mvstr[1]);
607 t = ASCIITOSQ (mvstr[2], mvstr[3]);
608 piece = (strlen (mvstr) == 5 ? mvstr[4] : ' ');
609 return (IsInMoveList (1, f, t, piece));
610 }
611
612
613 /***********************************************************************
614 * Its a SAN notation move. More headache!
615 * We generate all the legal moves and start comparing them with
616 * the input move.
617 ***********************************************************************/
618 if (ATOH (mvstr[0])) /* pawn move */
619 {
620 if (ITO8 (mvstr[1])) /* e4 type */
621 {
622 t = ASCIITOSQ (mvstr[0], mvstr[1]);
623 f = t + (side == white ? -8 : 8);
624 /* Add Sanity Check */
625 if ( f > 0 && f < 64 ) {
626 if (BitPosArray[f] & board.b[side][pawn])
627 {
628 if (mvstr[2] != '\0')
629 return (IsInMoveList (1, f, t, mvstr[2]));
630 else
631 return (IsInMoveList (1, f, t, ' '));
632 }
633 f = t + (side == white ? -16 : 16);
634 if ( f > 0 && f < 64 ) {
635 if (BitPosArray[f] & board.b[side][pawn])
636 return (IsInMoveList (1, f, t, ' '));
637 } /* End bound check +/- 16 */
638 } /* End bound check +/- 8 */
639 }
640 else if (ATOH (mvstr[1]) && ITO8 (mvstr[2])) /* ed4 type */
641 {
642 t = ASCIITOSQ (mvstr[1], mvstr[2]);
643 rank = ASCIITORANK (mvstr[2]) + (side == white ? -1 : 1);
644 f = rank * 8 + ASCIITOFILE (mvstr[0]);
645 piece = (strlen (mvstr) == 4 ? mvstr[3] : ' ');
646 return (IsInMoveList (1, f, t, piece));
647 }
648 else if (ATOH (mvstr[1])) /* ed type */
649 {
650 file = ASCIITOFILE (mvstr[0]);
651 fileto = ASCIITOFILE (mvstr[1]);
652 b = board.b[side][pawn] & FileBit[file];
653 if (side == white)
654 b = b >> (fileto < file ? 7 : 9);
655 else
656 b = b << (fileto < file ? 9 : 7);
657 if (board.ep > -1)
658 b = b & (board.friends[1^side] | BitPosArray[board.ep]);
659 else
660 b = b & (board.friends[1^side]);
661 switch (nbits (b))
662 {
663 case 0 : return ((leaf *) NULL);
664 case 1 : t = leadz (b);
665 f = t - (side == white ? 8 : -8) + (file - fileto);
666 piece = (strlen (mvstr) == 3 ? mvstr[2] : ' ');
667 return (IsInMoveList (1, f, t, piece));
668 default :
669 printf ("Ambiguous move: %s %s\n",s,mvstr);
670 ShowBoard();
671 /*
672 getchar();
673 */
674 return ((leaf *) NULL);
675 }
676 }
677
678 }
679 else if ((piece = piece_id(mvstr[0])) != empty &&
680 (piece_id(mvstr[1]) == empty)) /* Is a piece move */
681 {
682 /* Since piece_id accepts P as pawns, this will correctly
683 * handle malformed commands like Pe4 */
684
685 b = board.b[side][piece];
686 t = -1;
687 if (ITO8 (mvstr[1])) /* N1d2 type move */
688 {
689 rank = ASCIITORANK (mvstr[1]);
690 b &= RankBit[rank];
691 t = ASCIITOSQ (mvstr[2], mvstr[3]);
692 }
693 else if (ATOH (mvstr[1]) && ATOH (mvstr[2])) /* Nbd2 type move */
694 {
695 file = ASCIITOFILE (mvstr[1]);
696 b &= FileBit[file];
697 t = ASCIITOSQ (mvstr[2], mvstr[3]);
698 }
699 else if (ATOH (mvstr[1]) && ITO8 (mvstr[2])) /* Nd2 type move */
700 {
701 t = ASCIITOSQ (mvstr[1], mvstr[2]);
702 }
703
704 kount = 0;
705 n1 = n2 = (leaf *) NULL;
706 while (b)
707 {
708 f = leadz (b);
709 CLEARBIT (b, f);
710 if ((n1 = IsInMoveList (1, f, t, ' ')) != (leaf *) NULL )
711 {
712 n2 = n1;
713 kount++;
714 }
715 }
716 if (kount > 1)
717 {
718 printf ("Ambiguous move: %s %s\n",s,mvstr);
719 ShowBoard();
720 /*
721 getchar();
722 */
723 return ((leaf *) NULL);
724 }
725 else if (kount == 0)
726 return ((leaf *) NULL);
727 else
728 return (n2);
729 }
730 else if (((piece = piece_id(mvstr[0])) != empty) &&
731 ((piece2 = piece_id(mvstr[1])) != empty) &&
732 ( (mvstr[2] == '\0') ||
733 ((piece_id(mvstr[2]) != empty) && mvstr[3] == '\0')))
734 { /* KxP format */
735 promote = ' ';
736 if (piece_id(mvstr[2] != empty)) {
737 promote = mvstr[2];
738 }
739 kount = 0;
740 n1 = n2 = (leaf *) NULL;
741 b = board.b[side][piece];
742 while (b)
743 {
744 f = leadz (b);
745 CLEARBIT (b, f);
746 b2 = board.b[1^side][piece2];
747 while (b2)
748 {
749 t = leadz (b2);
750 CLEARBIT (b2, t);
751 printf("Trying %s: ", AlgbrMove(MOVE(f,t)));
752 if ((n1 = IsInMoveList (1, f, t, promote)) != (leaf *) NULL)
753 {
754 n2 = n1;
755 kount++;
756 printf("Y ");
757 }
758 else printf("N ");
759 }
760 }
761 if (kount > 1)
762 {
763 printf ("Ambiguous move: %s %s\n",s,mvstr);
764 ShowBoard();
765 /*
766 getchar();
767 */
768 return ((leaf *) NULL);
769 }
770 else if (kount == 0)
771 return ((leaf *) NULL);
772 else
773 return (n2);
774
775 }
776
777 /* Fall through. Nothing worked, return that no move was performed. */
778 return ((leaf *) NULL);
779 }
780
781
IsInMoveList(int ply,int f,int t,char piece)782 leaf * IsInMoveList (int ply, int f, int t, char piece)
783 /**************************************************************************
784 *
785 * Checks to see if from and to square can be found in the movelist
786 * and is legal.
787 *
788 **************************************************************************/
789 {
790 leaf *node;
791
792 for (node = TreePtr[ply]; node < TreePtr[ply + 1]; node++)
793 {
794 if ((int) (node->move & 0x0FFF) == MOVE(f,t) &&
795 toupper(piece) == notation[PROMOTEPIECE (node->move)])
796 return (node);
797 }
798 return ((leaf *) NULL);
799 }
800
801
AlgbrMove(int move)802 char *AlgbrMove (int move)
803 /*****************************************************************************
804 *
805 * Convert an int move format to algebraic format of g1f3.
806 *
807 *****************************************************************************/
808 {
809 int f, t;
810 static char s[6];
811
812 f = FROMSQ(move);
813 t = TOSQ(move);
814 strcpy (s, algbr[f]);
815 strcpy (s+2, algbr[t]);
816 if (move & PROMOTION)
817 {
818 if (flags & XBOARD)
819 s[4] = lnotation[PROMOTEPIECE (move)];
820 else
821 s[4] = notation[PROMOTEPIECE (move)];
822 s[5] = '\0';
823 }
824 else
825 s[4] = '\0';
826 return (s);
827 }
828
829