1 #include "chess.h"
2 #include "data.h"
3 /* last modified 02/24/14 */
4 /*
5  *******************************************************************************
6  *                                                                             *
7  *   OutputMove() is responsible for converting the internal move format to a  *
8  *   string that can be displayed.  First, it simply converts the from/to      *
9  *   squares to fully-qualified algebraic (which includes O-O and O-O-O for    *
10  *   castling moves).  Next, we try several "shortcut" forms and call          *
11  *   input_move(silent=1) to let it silently check the move for uniqueness.    *
12  *   as soon as we get a non-ambiguous move, we return that text string.       *
13  *                                                                             *
14  *******************************************************************************
15  */
OutputMove(TREE * RESTRICT tree,int ply,int wtm,int move)16 char *OutputMove(TREE * RESTRICT tree, int ply, int wtm, int move) {
17   static char text_move[10], new_text[10];
18   unsigned *mvp;
19   char *text = text_move;
20   static const char piece_names[7] = { ' ', 'P', 'N', 'B', 'R', 'Q', 'K' };
21 /*
22  ************************************************************
23  *                                                          *
24  *  Special case for null-move which will only be used in a *
25  *  search trace which dumps the entire tree.               *
26  *                                                          *
27  ************************************************************
28  */
29   if (move == 0) {
30     strcpy(text, "null");
31     return text;
32   }
33   do {
34 /*
35  ************************************************************
36  *                                                          *
37  *  Check for castling moves first.                         *
38  *                                                          *
39  ************************************************************
40  */
41     if ((Piece(move) == king) && (Abs(From(move) - To(move)) == 2)) {
42       if (wtm) {
43         if (To(move) == 2)
44           strcpy(text_move, "O-O-O");
45         else
46           strcpy(text_move, "O-O");
47       } else {
48         if (To(move) == 58)
49           strcpy(text_move, "O-O-O");
50         else
51           strcpy(text_move, "O-O");
52       }
53       break;
54     }
55 /*
56  ************************************************************
57  *                                                          *
58  *  Not a castling move.  Convert the move to a fully-      *
59  *  qualified algebraic move as a starting point.           *
60  *                                                          *
61  ************************************************************
62  */
63     text = new_text;
64     if ((int) Piece(move) > pawn)
65       *text++ = piece_names[Piece(move)];
66     *text++ = File(From(move)) + 'a';
67     *text++ = Rank(From(move)) + '1';
68     if (Captured(move))
69       *text++ = 'x';
70     *text++ = File(To(move)) + 'a';
71     *text++ = Rank(To(move)) + '1';
72     if (Promote(move)) {
73       *text++ = '=';
74       *text++ = piece_names[Promote(move)];
75     }
76     *text = '\0';
77     strcpy(text_move, new_text);
78     if (output_format > 0)
79       break;
80 /*
81  ************************************************************
82  *                                                          *
83  *  Now we try some short forms.  If this is a pawn move    *
84  *  (first character is "P") and the move is not a capture  *
85  *  move, we can try just the destination square (Pe2e4     *
86  *  becomes e4).                                            *
87  *                                                          *
88  ************************************************************
89  */
90     if (Piece(move) == pawn) {
91       if (!Captured(move)) {
92         strcpy(text_move, new_text + 2);
93         if (InputMove(tree, ply, wtm, 1, 0, text_move))
94           break;
95       }
96 /*
97  ************************************************************
98  *                                                          *
99  *  If this is a pawn and it is capturing something, try    *
100  *  the usual pawn capture format (Pe4xd5 becomes exd5).    *
101  *                                                          *
102  ************************************************************
103  */
104       text_move[0] = new_text[0];
105       strcpy(text_move + 1, new_text + 2);
106       if (InputMove(tree, ply, wtm, 1, 0, text_move))
107         break;
108 /*
109  ************************************************************
110  *                                                          *
111  *  It is a pawn move and we can't find a shorter form, so  *
112  *  leave it as a fully-qualified move and go with it as    *
113  *  is.  (this will not normally happen).                   *
114  *                                                          *
115  ************************************************************
116  */
117       strcpy(text_move, new_text);
118       break;
119     }
120 /*
121  ************************************************************
122  *                                                          *
123  *  If the move is a normal piece move, and does not        *
124  *  capture anything, we try the piece + destination format *
125  *  first (Ng1f3 becomes Nf3).                              *
126  *                                                          *
127  ************************************************************
128  */
129     if (!Captured(move)) {
130       text_move[0] = new_text[0];
131       strcpy(text_move + 1, new_text + 3);
132       if (InputMove(tree, ply, wtm, 1, 0, text_move))
133         break;
134 /*
135  ************************************************************
136  *                                                          *
137  *  If that is ambiguous, we will try two alternatives:     *
138  *  (1) add in the origin file;  (2) add in the origin rank *
139  *  (Ng1f3 becomes Ngf3 or N1f3).                           *
140  *                                                          *
141  ************************************************************
142  */
143       text_move[0] = new_text[0];
144       text_move[1] = new_text[1];
145       strcpy(text_move + 2, new_text + 3);
146       if (InputMove(tree, ply, wtm, 1, 0, text_move))
147         break;
148       text_move[0] = new_text[0];
149       strcpy(text_move + 1, new_text + 2);
150       if (InputMove(tree, ply, wtm, 1, 0, text_move))
151         break;
152 /*
153  ************************************************************
154  *                                                          *
155  *  Nothing worked, so we go with the fully-qualified move. *
156  *                                                          *
157  ************************************************************
158  */
159       strcpy(text_move, new_text);
160       break;
161     } else {
162 /*
163  ************************************************************
164  *                                                          *
165  *  If this is a capture, we try the short form of a        *
166  *  capture move (Ng1xf3 becomes Nxf3)                      *
167  *                                                          *
168  ************************************************************
169  */
170       text_move[0] = new_text[0];
171       strcpy(text_move + 1, new_text + 3);
172       if (InputMove(tree, ply, wtm, 1, 0, text_move))
173         break;
174 /*
175  ************************************************************
176  *                                                          *
177  *  If that didn't work, we try adding in the origin file   *
178  *  or the origin rank (Ng1xf3 becomes Ngxf3 or N1xf3).     *
179  *                                                          *
180  ************************************************************
181  */
182       text_move[0] = new_text[0];
183       text_move[1] = new_text[1];
184       strcpy(text_move + 2, new_text + 3);
185       if (InputMove(tree, ply, wtm, 1, 0, text_move))
186         break;
187       text_move[0] = new_text[0];
188       strcpy(text_move + 1, new_text + 2);
189       if (InputMove(tree, ply, wtm, 1, 0, text_move))
190         break;
191 /*
192  ************************************************************
193  *                                                          *
194  *  Nothing worked, return the fully-qualified move.        *
195  *                                                          *
196  ************************************************************
197  */
198       strcpy(text_move, new_text);
199       break;
200     }
201   } while (0);
202 /*
203  ************************************************************
204  *                                                          *
205  *  If the move is a check, or mate, append either "+" or   *
206  *  "#" as appropriate.                                     *
207  *                                                          *
208  ************************************************************
209  */
210   if (output_format == 0) {
211     text = text_move + strlen(text_move);
212     tree->status[MAXPLY] = tree->status[ply];
213     MakeMove(tree, MAXPLY, wtm, move);
214     if (Check(Flip(wtm))) {
215       mvp =
216           GenerateCheckEvasions(tree, MAXPLY + 1, Flip(wtm),
217           tree->move_list + 4800);
218       if (mvp == (tree->move_list + 4800))
219         *text++ = '#';
220       else
221         *text++ = '+';
222     }
223     UnmakeMove(tree, MAXPLY, wtm, move);
224     *text = 0;
225   }
226   return text_move;
227 }
228