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