Added support for eco codes, for setting variables and various cleanups.
[rattatechess.git] / move_notation.cpp
blob79166fe6a22cfcd646a970e6e8fbc81da9d96de9
1 /***************************************************************************
2 move_notation.h - Convert move from and to string
3 -------------------
4 begin : Mon Oct 08 2007
5 copyright : (C) 2007 by Maurizio Monge
6 email : monge@linuz.sns.it
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include <string.h>
19 #include "board.h"
22 static int char_to_piece(char c)
24 switch(c)
26 case 'K': case 'k': return KING;
27 case 'Q': case 'q': return QUEEN;
28 case 'R': case 'r': return ROOK;
29 case 'B': case 'b': return BISHOP;
30 case 'N': case 'n': return KNIGHT;
31 case 'P': case 'p': return PAWN;
34 return -1;
38 /* reads a string and if possible understands a move */
39 Move Board::move_from_string(const char* s)
41 int piece = -1;
42 int from_x = -1;
43 int from_y = -1;
44 int to_x = -1;
45 int to_y = -1;
46 int promote = -1;
47 int comment_1 = 0;
48 int comment_2 = strlen(s);
49 int pos = 0;
50 Move retv = Move::None();
52 /* parse O-O-O */
53 if(!strncmp(s, "0-0-0", 5) || !strncmp(s, "O-O-O", 5) || !strncmp(s, "o-o-o", 5) )
55 comment_1 = 5;
57 Move moves[250];
58 int num_moves = find_moves(moves);
60 for(int i=0;i<num_moves;i++)
61 if(moves[i].flags == CASTLEQUEENSIDE)
63 retv = moves[i];
64 goto do_return;
67 return Move::Illegal();
70 /* parse O-O. Note that O-O-O matches the expr for O-O, so it must be tested after */
71 if(!strncmp(s, "0-0", 3) || !strncmp(s, "O-O", 3) || !strncmp(s, "o-o", 3) )
73 comment_1 = 3;
75 Move moves[250];
76 int num_moves = find_moves(moves);
78 for(int i=0;i<num_moves;i++)
79 if(moves[i].flags == CASTLEKINGSIDE)
81 retv = moves[i];
82 goto do_return;
85 return Move::Illegal();
88 /* parse a SAN */
89 if(s[pos]>='A' && s[pos]<='Z' && (piece=char_to_piece(s[pos])) != -1)
90 pos++;
91 if(s[pos]>='a' && s[pos]<='h')
92 to_x = s[pos++] - 'a';
93 if(s[pos]>='1' && s[pos]<='8')
94 to_y = s[pos++] - '1';
95 if(s[pos]=='-' || s[pos]=='x')
96 pos++;
97 if(s[pos]>='A' && s[pos]<='Z' && char_to_piece(s[pos]) != -1)
98 pos++;
99 if(s[pos]>='a' && s[pos]<='h')
101 from_x = to_x;
102 to_x = s[pos++] - 'a';
104 if(s[pos]>='1' && s[pos]<='8')
106 from_y = to_y;
107 to_y = s[pos++] - '1';
109 if(s[pos]=='=')
110 pos++;
111 if((promote=char_to_piece(s[pos])) != -1)
112 pos++;
114 if(to_x != -1 && to_y != -1)
116 if(piece==-1 && (from_x==-1 || from_y==-1))
117 piece = PAWN;
119 comment_1 = pos;
121 /* find a unique matching move */
122 Move moves[250];
123 int num_moves = find_moves(moves);
125 // print_board();
126 // printf("piece=%d from_x=%d from_y=%d to_x=%d to_y=%d promote=%d\n",
127 // piece, from_x, from_y, to_x, to_y, promote);
129 for(int i=0;i<num_moves;i++)
131 // char buf[64];
132 // move_to_alg(buf, &moves[i]);
133 // printf("%s piece=%d from_x=%d from_y=%d to_x=%d to_y=%d promote=%d\n", buf,
134 // PIECE_OF(data[moves[i].from]), X(moves[i].from), Y(moves[i].from),
135 // X(moves[i].to), Y(moves[i].to), moves[i].flags);
136 if( (piece == -1 || piece == PIECE_OF(data[moves[i].from])) &&
137 (from_x == -1 || from_x == X(moves[i].from)) &&
138 (from_y == -1 || from_y == Y(moves[i].from)) &&
139 (to_x == X(moves[i].to)) &&
140 (to_y == Y(moves[i].to)) &&
141 (moves[i].flags<PROMOTE_FIRST || moves[i].flags>PROMOTE_LAST || moves[i].flags-PROMOTE0 == promote) )
143 if(retv != Move::None())
144 return Move::Ambiguous();
145 else
146 retv = moves[i];
150 if(retv == Move::None())
151 return Move::Illegal();
153 goto do_return;
156 return Move::None();
158 do_return:
159 retv.val = 0;
160 for(int i=comment_1; i<comment_2; i++)
161 if(s[i] == '!')
162 retv.val++;
163 else if(s[i] == '?')
164 retv.val--;
166 return retv;
169 //converts a move to the dummy notation (e2e4,g7h8q,...)
170 char* Board::move_to_coord(char* string, const Move& mv)
172 char* str = string;
173 *(str++) = 'a' + X(mv.from);
174 *(str++) = '1' + Y(mv.from);
175 *(str++) = 'a' + X(mv.to);
176 *(str++) = '1' + Y(mv.to);
178 /* promotion */
179 if(mv.flags > PROMOTE0)
180 *(str++) = piecename[ mv.flags-PROMOTE0 ]^0x20;
181 *(str++)='\0';
182 return string;
185 /* converts a move into the standard algebraic notation
186 the current board must be the board before the move is done.
187 mv must be a valid move in the current position! */
188 char* Board::move_to_alg(char* string, const Move& mv)
190 char* str=string;
192 if(mv.flags==CASTLEKINGSIDE)
194 *(str++)='O';
195 *(str++)='-';
196 *(str++)='O';
198 else if(mv.flags==CASTLEQUEENSIDE)
200 *(str++)='O';
201 *(str++)='-';
202 *(str++)='O';
203 *(str++)='-';
204 *(str++)='O';
206 else
208 Move moves[250];
209 int num_moves = find_moves(moves);
210 unsigned char piece=data[mv.from];
212 if(PIECE_OF(piece)!=PAWN)
214 /* mark here how the move could be ambiguous */
215 bool ambig = false;
216 bool samecol=false;
217 bool samerow=false;
219 *(str++)=Board::piecename[PIECE_OF(piece)];
221 for(int i=0;i<num_moves;i++)
223 //check for ambiguity
224 if(piece == data[moves[i].from] //same piece?
225 && moves[i].to == mv.to //same target?
226 && moves[i].from != mv.from) //but not same move?
228 ambig = true;
229 if(X(moves[i].from)==X(mv.from))
230 samecol=true;
231 if(Y(moves[i].from)==Y(mv.from))
232 samerow=true;
236 if(ambig)
238 if(!samecol || samerow)
239 *(str++)='a' + X(mv.from);
240 if(samecol)
241 *(str++)='1' + Y(mv.from);
244 if((mv.capture) || mv.flags==ENPASSANT)
246 if(PIECE_OF(piece)==PAWN)
247 *(str++)='a' + X(mv.from);
248 *(str++)='x';
251 *(str++)='a' + X(mv.to);
252 *(str++)='1' + Y(mv.to);
254 if(mv.flags > PROMOTE0)
256 *(str++) = '=';
257 *(str++) = Board::piecename[ mv.flags-PROMOTE0 ];
260 /* is this move a check(mate)? */
261 SaveBuf tmp;
262 do_move(mv, tmp);
263 if(under_attack( king_pos[IS_WHITE(color_to_move)],
264 other_color) )
266 Move mv_tmp[250];
267 int n = find_moves(mv_tmp);
269 if(n==0)
270 *(str++)='#';
271 else
272 *(str++)='+';
274 undo_move(mv, tmp);
275 *(str++)='\0';
276 return string;