diff options
Diffstat (limited to 'apps/plugins')
-rw-r--r-- | apps/plugins/chessbox/chessbox_pgn.c | 702 | ||||
-rw-r--r-- | apps/plugins/chessbox/chessbox_pgn.h | 67 |
2 files changed, 769 insertions, 0 deletions
diff --git a/apps/plugins/chessbox/chessbox_pgn.c b/apps/plugins/chessbox/chessbox_pgn.c new file mode 100644 index 0000000000..0cdd8d82e5 --- /dev/null +++ b/apps/plugins/chessbox/chessbox_pgn.c | |||
@@ -0,0 +1,702 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 Mauricio Peccorini | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "chessbox_pgn.h" | ||
21 | #include "plugin.h" | ||
22 | |||
23 | /* button definitions */ | ||
24 | #if (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD) | ||
25 | #define CB_SELECT BUTTON_SELECT | ||
26 | #define CB_UP BUTTON_MENU | ||
27 | #define CB_DOWN BUTTON_PLAY | ||
28 | #define CB_LEFT BUTTON_LEFT | ||
29 | #define CB_RIGHT BUTTON_RIGHT | ||
30 | #define CB_PLAY (BUTTON_SELECT | BUTTON_PLAY) | ||
31 | #define CB_LEVEL (BUTTON_SELECT | BUTTON_RIGHT) | ||
32 | #define CB_RESTART (BUTTON_SELECT | BUTTON_LEFT) | ||
33 | #define CB_MENU (BUTTON_SELECT | BUTTON_MENU) | ||
34 | |||
35 | #define CB_SCROLL_UP (BUTTON_SCROLL_FWD|BUTTON_REPEAT) | ||
36 | #define CB_SCROLL_DOWN (BUTTON_SCROLL_BACK|BUTTON_REPEAT) | ||
37 | #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) | ||
38 | #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) | ||
39 | |||
40 | #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD | ||
41 | #define CB_SELECT BUTTON_SELECT | ||
42 | #define CB_UP BUTTON_UP | ||
43 | #define CB_DOWN BUTTON_DOWN | ||
44 | #define CB_LEFT BUTTON_LEFT | ||
45 | #define CB_RIGHT BUTTON_RIGHT | ||
46 | #define CB_PLAY BUTTON_PLAY | ||
47 | #define CB_LEVEL BUTTON_REC | ||
48 | #define CB_RESTART (BUTTON_SELECT | BUTTON_PLAY) | ||
49 | #define CB_MENU BUTTON_POWER | ||
50 | |||
51 | #define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT) | ||
52 | #define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT) | ||
53 | #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) | ||
54 | #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) | ||
55 | |||
56 | #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) | ||
57 | #define CB_SELECT BUTTON_SELECT | ||
58 | #define CB_UP BUTTON_UP | ||
59 | #define CB_DOWN BUTTON_DOWN | ||
60 | #define CB_LEFT BUTTON_LEFT | ||
61 | #define CB_RIGHT BUTTON_RIGHT | ||
62 | #define CB_PLAY BUTTON_ON | ||
63 | #define CB_LEVEL BUTTON_MODE | ||
64 | #define CB_RESTART BUTTON_REC | ||
65 | #define CB_MENU BUTTON_OFF | ||
66 | |||
67 | #define CB_RC_QUIT BUTTON_RC_STOP | ||
68 | |||
69 | #define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT) | ||
70 | #define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT) | ||
71 | #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) | ||
72 | #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) | ||
73 | |||
74 | #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD | ||
75 | #define CB_SELECT BUTTON_SELECT | ||
76 | #define CB_UP BUTTON_UP | ||
77 | #define CB_DOWN BUTTON_DOWN | ||
78 | #define CB_LEFT BUTTON_LEFT | ||
79 | #define CB_RIGHT BUTTON_RIGHT | ||
80 | #define CB_PLAY BUTTON_PLAY | ||
81 | #define CB_LEVEL BUTTON_EQ | ||
82 | #define CB_MENU BUTTON_MODE | ||
83 | |||
84 | #define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT) | ||
85 | #define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT) | ||
86 | #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) | ||
87 | #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) | ||
88 | |||
89 | #elif CONFIG_KEYPAD == RECORDER_PAD | ||
90 | #define CB_SELECT BUTTON_PLAY | ||
91 | #define CB_UP BUTTON_UP | ||
92 | #define CB_DOWN BUTTON_DOWN | ||
93 | #define CB_LEFT BUTTON_LEFT | ||
94 | #define CB_RIGHT BUTTON_RIGHT | ||
95 | #define CB_PLAY BUTTON_ON | ||
96 | #define CB_LEVEL BUTTON_F1 | ||
97 | #define CB_RESTART BUTTON_F3 | ||
98 | #define CB_MENU BUTTON_OFF | ||
99 | |||
100 | #define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT) | ||
101 | #define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT) | ||
102 | #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) | ||
103 | #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) | ||
104 | |||
105 | #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD | ||
106 | #define CB_SELECT BUTTON_SELECT | ||
107 | #define CB_UP BUTTON_UP | ||
108 | #define CB_DOWN BUTTON_DOWN | ||
109 | #define CB_LEFT BUTTON_LEFT | ||
110 | #define CB_RIGHT BUTTON_RIGHT | ||
111 | #define CB_PLAY BUTTON_ON | ||
112 | #define CB_LEVEL BUTTON_F1 | ||
113 | #define CB_RESTART BUTTON_F3 | ||
114 | #define CB_MENU BUTTON_OFF | ||
115 | |||
116 | #define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT) | ||
117 | #define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT) | ||
118 | #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) | ||
119 | #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) | ||
120 | |||
121 | #elif CONFIG_KEYPAD == ONDIO_PAD | ||
122 | #define CB_SELECT_PRE BUTTON_MENU | ||
123 | #define CB_SELECT (BUTTON_MENU|BUTTON_REL) | ||
124 | #define CB_UP BUTTON_UP | ||
125 | #define CB_DOWN BUTTON_DOWN | ||
126 | #define CB_LEFT BUTTON_LEFT | ||
127 | #define CB_RIGHT BUTTON_RIGHT | ||
128 | #define CB_PLAY_PRE BUTTON_MENU | ||
129 | #define CB_PLAY (BUTTON_MENU|BUTTON_REPEAT) | ||
130 | #define CB_LEVEL (BUTTON_MENU|BUTTON_OFF) | ||
131 | #define CB_RESTART (BUTTON_MENU|BUTTON_LEFT) | ||
132 | #define CB_MENU BUTTON_OFF | ||
133 | |||
134 | #define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT) | ||
135 | #define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT) | ||
136 | #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) | ||
137 | #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) | ||
138 | |||
139 | #elif (CONFIG_KEYPAD == GIGABEAT_PAD) | ||
140 | #define CB_SELECT BUTTON_SELECT | ||
141 | #define CB_UP BUTTON_UP | ||
142 | #define CB_DOWN BUTTON_DOWN | ||
143 | #define CB_LEFT BUTTON_LEFT | ||
144 | #define CB_RIGHT BUTTON_RIGHT | ||
145 | #define CB_PLAY BUTTON_POWER | ||
146 | #define CB_LEVEL BUTTON_MENU | ||
147 | #define CB_MENU BUTTON_A | ||
148 | |||
149 | #define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT) | ||
150 | #define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT) | ||
151 | #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) | ||
152 | #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) | ||
153 | |||
154 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD | ||
155 | #define CB_SELECT BUTTON_REW | ||
156 | #define CB_UP BUTTON_SCROLL_UP | ||
157 | #define CB_DOWN BUTTON_SCROLL_DOWN | ||
158 | #define CB_LEFT BUTTON_LEFT | ||
159 | #define CB_RIGHT BUTTON_RIGHT | ||
160 | #define CB_PLAY BUTTON_PLAY | ||
161 | #define CB_LEVEL BUTTON_FF | ||
162 | #define CB_RESTART (BUTTON_REW | BUTTON_PLAY) | ||
163 | #define CB_MENU BUTTON_POWER | ||
164 | |||
165 | #define CB_SCROLL_UP (BUTTON_SCROLL_UP|BUTTON_REPEAT) | ||
166 | #define CB_SCROLL_DOWN (BUTTON_SCROLL_DOWN|BUTTON_REPEAT) | ||
167 | #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) | ||
168 | #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) | ||
169 | |||
170 | #elif CONFIG_KEYPAD == SANSA_E200_PAD | ||
171 | #define CB_SELECT BUTTON_SELECT | ||
172 | #define CB_UP BUTTON_UP | ||
173 | #define CB_DOWN BUTTON_DOWN | ||
174 | #define CB_LEFT BUTTON_LEFT | ||
175 | #define CB_RIGHT BUTTON_RIGHT | ||
176 | #define CB_PLAY (BUTTON_SELECT | BUTTON_RIGHT) | ||
177 | #define CB_LEVEL BUTTON_REC | ||
178 | #define CB_RESTART (BUTTON_SELECT | BUTTON_REPEAT) | ||
179 | #define CB_MENU BUTTON_POWER | ||
180 | |||
181 | #define CB_SCROLL_UP (BUTTON_SCROLL_UP|BUTTON_REPEAT) | ||
182 | #define CB_SCROLL_DOWN (BUTTON_SCROLL_DOWN|BUTTON_REPEAT) | ||
183 | #define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) | ||
184 | #define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) | ||
185 | |||
186 | #else | ||
187 | #error CHESSBOX: Unsupported keypad | ||
188 | #endif | ||
189 | |||
190 | #define LOG_FILE PLUGIN_DIR "/chessbox.log" | ||
191 | int loghandler; | ||
192 | |||
193 | struct plugin_api* rb; | ||
194 | |||
195 | short kn_offs[8][2] = {{2,1},{2,-1},{-2,1},{-2,-1},{1,2},{1,-2},{-1,2},{-1,-2}}; | ||
196 | short rk_offs[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; | ||
197 | short bp_offs[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}}; | ||
198 | |||
199 | /* global vars for pl_malloc() */ | ||
200 | void *bufptr = NULL; | ||
201 | ssize_t bufleft; | ||
202 | |||
203 | /* simple function to "allocate" memory in pluginbuffer. | ||
204 | * (borrowed from dict.c) | ||
205 | */ | ||
206 | void *pl_malloc(ssize_t size) | ||
207 | { | ||
208 | void *ptr; | ||
209 | ptr = bufptr; | ||
210 | |||
211 | if (bufleft < size) | ||
212 | { | ||
213 | return NULL; | ||
214 | } | ||
215 | else | ||
216 | { | ||
217 | bufptr += size; | ||
218 | return ptr; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | /* init function for pl_malloc() */ | ||
223 | void pl_malloc_init(void) | ||
224 | { | ||
225 | bufptr = rb->plugin_get_buffer((size_t *)&bufleft); | ||
226 | } | ||
227 | |||
228 | void process_tag(struct pgn_game_node* game, char* buffer){ | ||
229 | char tag_type[20]; | ||
230 | char tag_value[255]; | ||
231 | short pos=0, pos2=0; | ||
232 | while (buffer[pos+1] != ' '){ | ||
233 | tag_type[pos] = buffer[pos+1]; | ||
234 | pos++; | ||
235 | } | ||
236 | tag_type[pos] = '\0'; | ||
237 | pos+=3; | ||
238 | while (buffer[pos] != '"'){ | ||
239 | tag_value[pos2] = buffer[pos]; | ||
240 | pos++; pos2++; | ||
241 | } | ||
242 | |||
243 | /* truncate tag values that are too large */ | ||
244 | if (pos2 > 19){ | ||
245 | pos2 = 19; | ||
246 | } | ||
247 | tag_value[pos2] = '\0'; | ||
248 | |||
249 | if (rb->strcmp(tag_type,"White") == 0){ | ||
250 | rb->strcpy(game->white_player, tag_value); | ||
251 | } | ||
252 | if (rb->strcmp(tag_type,"Black") == 0){ | ||
253 | rb->strcpy(game->black_player, tag_value); | ||
254 | } | ||
255 | if (rb->strcmp(tag_type,"Result") == 0){ | ||
256 | rb->strcpy(game->result, tag_value); | ||
257 | } | ||
258 | if (rb->strcmp(tag_type,"Date") == 0){ | ||
259 | rb->strcpy(game->game_date, tag_value); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | unsigned short get_next_token(const char* line_buffer, unsigned short initial_pos, | ||
264 | char* token_buffer){ | ||
265 | unsigned short pos, token_pos=0; | ||
266 | for (pos = initial_pos;line_buffer[pos] == ' ' || line_buffer[pos] == '.';pos++); | ||
267 | do { | ||
268 | token_buffer[token_pos] = line_buffer[pos]; | ||
269 | pos++; token_pos++; | ||
270 | } while (line_buffer[pos] != ' ' && line_buffer[pos] != '.' | ||
271 | && line_buffer[pos] != '\0'); | ||
272 | /* ignore annotations */ | ||
273 | while (token_buffer[token_pos-1] == '!' || token_buffer[token_pos-1] == '?'){ | ||
274 | token_pos--; | ||
275 | } | ||
276 | token_buffer[token_pos] = '\0'; | ||
277 | return pos; | ||
278 | } | ||
279 | |||
280 | unsigned short piece_from_pgn(char pgn_piece){ | ||
281 | switch (pgn_piece){ | ||
282 | case 'R': | ||
283 | return rook; | ||
284 | case 'N': | ||
285 | return knight; | ||
286 | case 'B': | ||
287 | return bishop; | ||
288 | case 'Q': | ||
289 | return queen; | ||
290 | case 'K': | ||
291 | return king; | ||
292 | } | ||
293 | return no_piece; | ||
294 | } | ||
295 | |||
296 | char pgn_from_piece(unsigned short piece, unsigned short color){ | ||
297 | char pgn_piece = ' '; | ||
298 | switch (piece){ | ||
299 | case pawn: | ||
300 | pgn_piece = 'P'; | ||
301 | break; | ||
302 | case rook: | ||
303 | pgn_piece = 'R'; | ||
304 | break; | ||
305 | case knight: | ||
306 | pgn_piece = 'N'; | ||
307 | break; | ||
308 | case bishop: | ||
309 | pgn_piece = 'B'; | ||
310 | break; | ||
311 | case queen: | ||
312 | pgn_piece = 'Q'; | ||
313 | break; | ||
314 | case king: | ||
315 | pgn_piece = 'K'; | ||
316 | break; | ||
317 | case no_piece: | ||
318 | pgn_piece = ' '; | ||
319 | break; | ||
320 | } | ||
321 | if (color == black && pgn_piece != ' '){ | ||
322 | pgn_piece += 32; | ||
323 | } | ||
324 | return pgn_piece; | ||
325 | } | ||
326 | |||
327 | void pgn_to_coords(struct pgn_ply_node* ply){ | ||
328 | unsigned short str_length = rb->strlen(ply->pgn_text); | ||
329 | char str[10]; | ||
330 | rb->strcpy(str,ply->pgn_text); | ||
331 | ply->column_from = 0xFF; | ||
332 | ply->row_from = 0xFF; | ||
333 | ply->column_to = 0xFF; | ||
334 | ply->row_to = 0xFF; | ||
335 | ply->taken_piece = no_piece; | ||
336 | ply->promotion_piece = no_piece; | ||
337 | ply->enpassant = false; | ||
338 | ply->castle = false; | ||
339 | ply->promotion = false; | ||
340 | unsigned short i, j, piece; | ||
341 | bool found = false; | ||
342 | |||
343 | if (str_length >= 3 && (str[0] == 'O' || str[0] == '0') && str[1] == '-' | ||
344 | && (str[2] == 'O' || str[2] == '0')) { | ||
345 | /* castling */ | ||
346 | ply->castle = true; | ||
347 | if (str_length >= 5 && str[3] == '-' && (str[4] == 'O' || str[4] == '0')){ | ||
348 | /* castle queenside */ | ||
349 | if (ply->player == white){ | ||
350 | ply->row_from = 0; ply->column_from = 4; | ||
351 | ply->row_to = 0; ply->column_to = 2; | ||
352 | /* update the rook's position, the king's position will be updated later */ | ||
353 | board[locn[0][3]] = rook; color[locn[0][3]] = white; | ||
354 | board[locn[0][0]] = no_piece; color[locn[0][0]] = neutral; | ||
355 | } else { | ||
356 | ply->row_from = 7; ply->column_from = 4; | ||
357 | ply->row_to = 7; ply->column_to = 2; | ||
358 | board[locn[7][3]] = rook; color[locn[7][3]] = black; | ||
359 | board[locn[7][0]] = no_piece; color[locn[7][0]] = neutral; | ||
360 | } | ||
361 | } else { | ||
362 | /* castle kingside */ | ||
363 | if (ply->player == white){ | ||
364 | ply->row_from = 0; ply->column_from = 4; | ||
365 | ply->row_to = 0; ply->column_to = 6; | ||
366 | board[locn[0][5]] = rook; color[locn[0][5]] = white; | ||
367 | board[locn[0][7]] = no_piece; color[locn[0][7]] = neutral; | ||
368 | } else { | ||
369 | ply->row_from = 7; ply->column_from = 4; | ||
370 | ply->row_to = 7; ply->column_to = 6; | ||
371 | board[locn[7][5]] = rook; color[locn[7][5]] = black; | ||
372 | board[locn[7][7]] = no_piece; color[locn[7][7]] = neutral; | ||
373 | } | ||
374 | } | ||
375 | } else if (str[0] >= 'a' && str[0] <= 'h'){ | ||
376 | /* pawns */ | ||
377 | ply->column_from = str[0] - 'a'; | ||
378 | if (str[1] == 'x'){ | ||
379 | ply->row_from = str[3] - '1' + ((ply->player==white)?-1:1); | ||
380 | ply->row_to = str[3] - '1'; | ||
381 | ply->column_to = str[2] - 'a'; | ||
382 | if (board[locn[ply->row_to][ply->column_to]] == no_piece){ | ||
383 | /* en-passant, remove the pawn */ | ||
384 | ply->enpassant = true; | ||
385 | board[locn[ply->row_from][ply->column_to]] = no_piece; | ||
386 | color[locn[ply->row_from][ply->column_to]] = neutral; | ||
387 | ply->taken_piece = pawn; | ||
388 | } else { | ||
389 | ply->taken_piece = board[locn[ply->row_to][ply->column_to]]; | ||
390 | } | ||
391 | } else { | ||
392 | ply->column_to = ply->column_from; | ||
393 | ply->row_from = str[1] - '1' + ((ply->player==white)?-1:1); | ||
394 | ply->row_to = str[1] - '1'; | ||
395 | } | ||
396 | if (board[locn[ply->row_from][ply->column_from]] == no_piece){ | ||
397 | /* the pawn moved two squares */ | ||
398 | ply->row_from += ((ply->player==white)?-1:1); | ||
399 | } | ||
400 | if (ply->row_to == 7 || ply->row_to == 0){ | ||
401 | /* promotion */ | ||
402 | if (str[2] == '='){ | ||
403 | ply->promotion_piece = piece_from_pgn(str[3]); | ||
404 | } else { | ||
405 | ply->promotion_piece = piece_from_pgn(str[5]); | ||
406 | } | ||
407 | /* change the piece in the original position and wait | ||
408 | * for the code at the end to move it | ||
409 | */ | ||
410 | board[locn[ply->row_from][ply->column_from]] = ply->promotion_piece; | ||
411 | } | ||
412 | } else { | ||
413 | /* the other pieces */ | ||
414 | piece = piece_from_pgn(str[0]); | ||
415 | if (str[2] == 'x'){ | ||
416 | /* taken a piece and move was ambiguous */ | ||
417 | ply->column_to = str[3] - 'a'; | ||
418 | ply->row_to = str[4] - '1'; | ||
419 | ply->taken_piece = board[locn[ply->row_to][ply->column_to]]; | ||
420 | if (str[1] >= 'a' && str[1] <= 'h') { | ||
421 | ply->column_from = str[1] - 'a'; | ||
422 | } else { | ||
423 | ply->row_from = str[1] - '1'; | ||
424 | } | ||
425 | } else if (str[1] == 'x') { | ||
426 | /* taken a piece */ | ||
427 | ply->column_to = str[2] - 'a'; | ||
428 | ply->row_to = str[3] - '1'; | ||
429 | ply->taken_piece = board[locn[ply->row_to][ply->column_to]]; | ||
430 | } else if (str_length >= 4 && str[3] >= '0' && str[3] <= '9'){ | ||
431 | /* no piece taken and move was ambiguous */ | ||
432 | ply->column_to = str[2] - 'a'; | ||
433 | ply->row_to = str[3] - '1'; | ||
434 | if (str[1] >= 'a' && str[1] <= 'h') { | ||
435 | ply->column_from = str[1] - 'a'; | ||
436 | } else { | ||
437 | ply->row_from = str[1] - '1'; | ||
438 | } | ||
439 | } else { | ||
440 | /* regular move */ | ||
441 | ply->column_to = str[1] - 'a'; | ||
442 | ply->row_to = str[2] - '1'; | ||
443 | } | ||
444 | if (piece == knight) { | ||
445 | for (i=0;i<8;i++){ | ||
446 | if (ply->row_to + kn_offs[i][0] >= 0 && ply->row_to + kn_offs[i][0] <= 7 | ||
447 | && ply->column_to + kn_offs[i][1] >= 0 && ply->column_to + kn_offs[i][1] <= 7 | ||
448 | && board[locn[ply->row_to + kn_offs[i][0]][ply->column_to + kn_offs[i][1]]] == knight | ||
449 | && color[locn[ply->row_to + kn_offs[i][0]][ply->column_to + kn_offs[i][1]]] == ply->player | ||
450 | && (ply->row_from == 0xFF || ply->row_from == ply->row_to + kn_offs[i][0]) | ||
451 | && (ply->column_from == 0xFF || ply->column_from == ply->column_to + kn_offs[i][1])) { | ||
452 | ply->row_from = ply->row_to + kn_offs[i][0]; | ||
453 | ply->column_from = ply->column_to + kn_offs[i][1]; | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | if (piece == rook || piece == queen || piece == king){ | ||
458 | for (i=0;i<4;i++){ | ||
459 | j = 1; | ||
460 | found = false; | ||
461 | while (ply->row_to+(j*rk_offs[i][0]) >= 0 && ply->row_to+(j*rk_offs[i][0]) <= 7 && | ||
462 | ply->column_to+(j*rk_offs[i][1]) >= 0 && ply->column_to+(j*rk_offs[i][1]) <= 7){ | ||
463 | if (board[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] != no_piece) { | ||
464 | if (board[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] == piece && | ||
465 | color[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] == ply->player && | ||
466 | (ply->row_from == 0xFF || ply->row_from == ply->row_to+(j*rk_offs[i][0])) && | ||
467 | (ply->column_from == 0xFF || ply->column_from == ply->column_to+(j*rk_offs[i][1]))) { | ||
468 | ply->row_from = ply->row_to+(j*rk_offs[i][0]); | ||
469 | ply->column_from = ply->column_to+(j*rk_offs[i][1]); | ||
470 | found = true; | ||
471 | } | ||
472 | break; | ||
473 | } | ||
474 | j++; | ||
475 | } | ||
476 | if (found) { | ||
477 | break; | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | if (piece == bishop || ((piece == queen || piece == king) && !found)){ | ||
482 | for (i=0;i<4;i++){ | ||
483 | j = 1; | ||
484 | found = false; | ||
485 | while (ply->row_to+(j*bp_offs[i][0]) >= 0 && ply->row_to+(j*bp_offs[i][0]) <= 7 && | ||
486 | ply->column_to+(j*bp_offs[i][1]) >= 0 && ply->column_to+(j*bp_offs[i][1]) <= 7){ | ||
487 | if (board[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] != no_piece) { | ||
488 | if (board[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] == piece && | ||
489 | color[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] == ply->player && | ||
490 | (ply->row_from == 0xFF || ply->row_from == ply->row_to+(j*bp_offs[i][0])) && | ||
491 | (ply->column_from == 0xFF || ply->column_from == ply->column_to+(j*bp_offs[i][1]))) { | ||
492 | ply->row_from = ply->row_to+(j*bp_offs[i][0]); | ||
493 | ply->column_from = ply->column_to+(j*bp_offs[i][1]); | ||
494 | found = true; | ||
495 | } | ||
496 | break; | ||
497 | } | ||
498 | j++; | ||
499 | } | ||
500 | if (found) { | ||
501 | break; | ||
502 | } | ||
503 | } | ||
504 | } | ||
505 | } | ||
506 | |||
507 | /* leave a very complete log of the parsing of the game while it gets stable */ | ||
508 | for (i=0;i<8;i++){ | ||
509 | for (j=0;j<8;j++) { | ||
510 | rb->fdprintf(loghandler,"%c",pgn_from_piece(board[locn[7-i][j]],color[locn[7-i][j]])); | ||
511 | } | ||
512 | rb->fdprintf(loghandler,"\n"); | ||
513 | } | ||
514 | |||
515 | /* update the board */ | ||
516 | board[locn[ply->row_to][ply->column_to]] = board[locn[ply->row_from][ply->column_from]]; | ||
517 | color[locn[ply->row_to][ply->column_to]] = color[locn[ply->row_from][ply->column_from]]; | ||
518 | board[locn[ply->row_from][ply->column_from]] = no_piece; | ||
519 | color[locn[ply->row_from][ply->column_from]] = neutral; | ||
520 | } | ||
521 | |||
522 | char * get_game_text(int selected_item, void *data, char *buffer){ | ||
523 | int i; | ||
524 | struct pgn_game_node *temp_node = (struct pgn_game_node *)data; | ||
525 | char text_buffer[50]; | ||
526 | |||
527 | for (i=0;i<selected_item && temp_node != NULL;i++){ | ||
528 | temp_node = temp_node->next_node; | ||
529 | } | ||
530 | if (temp_node == NULL){ | ||
531 | return NULL; | ||
532 | } | ||
533 | rb->snprintf(text_buffer, 50,"%s vs. %s (%s)", temp_node->white_player, | ||
534 | temp_node->black_player, temp_node->game_date); | ||
535 | |||
536 | rb->strcpy(buffer, text_buffer); | ||
537 | return buffer; | ||
538 | } | ||
539 | |||
540 | /* ---- api functions ---- */ | ||
541 | struct pgn_game_node* pgn_list_games(struct plugin_api* api,const char* filename){ | ||
542 | int fhandler; | ||
543 | char line_buffer[128]; | ||
544 | struct pgn_game_node size_node, *first_game = NULL, *curr_node = NULL, *temp_node; | ||
545 | unsigned short game_count = 1; | ||
546 | int line_count = 0; | ||
547 | bool header_start = true, game_start = false; | ||
548 | rb = api; | ||
549 | |||
550 | if ( (fhandler = rb->open(filename, O_RDONLY)) == 0 ) return NULL; | ||
551 | |||
552 | if (bufptr == NULL){ | ||
553 | pl_malloc_init(); | ||
554 | } | ||
555 | while (rb->read_line(fhandler, line_buffer, sizeof line_buffer) > 0){ | ||
556 | line_count++; | ||
557 | /* looking for a game header */ | ||
558 | if (header_start) { | ||
559 | /* a new game header is found */ | ||
560 | if (line_buffer[0] == '['){ | ||
561 | temp_node = (struct pgn_game_node *)pl_malloc(sizeof size_node); | ||
562 | temp_node->next_node = NULL; | ||
563 | if (curr_node == NULL) { | ||
564 | first_game = curr_node = temp_node; | ||
565 | } else { | ||
566 | curr_node->next_node = temp_node; | ||
567 | curr_node = temp_node; | ||
568 | } | ||
569 | process_tag(curr_node, line_buffer); | ||
570 | curr_node->game_number = game_count; | ||
571 | curr_node->pgn_line = 0; | ||
572 | game_count++; | ||
573 | header_start = false; | ||
574 | game_start = true; | ||
575 | } | ||
576 | } else { | ||
577 | if (line_buffer[0] == '['){ | ||
578 | process_tag(curr_node, line_buffer); | ||
579 | } else if (line_buffer[0] == '\r' || line_buffer[0] == '\n' || line_buffer[0] == '\0'){ | ||
580 | if (game_start) { | ||
581 | game_start = false; | ||
582 | } else { | ||
583 | header_start = true; | ||
584 | } | ||
585 | } else { | ||
586 | if (curr_node->pgn_line == 0) { | ||
587 | curr_node->pgn_line = line_count; | ||
588 | } | ||
589 | } | ||
590 | } | ||
591 | } | ||
592 | rb->close(fhandler); | ||
593 | return first_game; | ||
594 | } | ||
595 | |||
596 | struct pgn_game_node* pgn_show_game_list(struct plugin_api* api, struct pgn_game_node* first_game){ | ||
597 | int curr_selection = 0; | ||
598 | int button; | ||
599 | struct gui_synclist games_list; | ||
600 | int i; | ||
601 | struct pgn_game_node *temp_node = first_game; | ||
602 | |||
603 | rb=api; | ||
604 | |||
605 | for (i=0;temp_node != NULL;i++){ | ||
606 | temp_node = temp_node->next_node; | ||
607 | } | ||
608 | |||
609 | |||
610 | rb->gui_synclist_init(&games_list, &get_game_text, first_game, false, 1); | ||
611 | rb->gui_synclist_set_title(&games_list, "Games", NOICON); | ||
612 | rb->gui_synclist_set_icon_callback(&games_list, NULL); | ||
613 | rb->gui_synclist_set_nb_items(&games_list, i); | ||
614 | rb->gui_synclist_limit_scroll(&games_list, true); | ||
615 | rb->gui_synclist_select_item(&games_list, 0); | ||
616 | |||
617 | while (true) { | ||
618 | rb->gui_syncstatusbar_draw(rb->statusbars, true); | ||
619 | rb->gui_synclist_draw(&games_list); | ||
620 | curr_selection = rb->gui_synclist_get_sel_pos(&games_list); | ||
621 | button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); | ||
622 | if (rb->gui_synclist_do_button(&games_list,button,LIST_WRAP_OFF)){ | ||
623 | continue; | ||
624 | } | ||
625 | switch (button) { | ||
626 | case ACTION_STD_OK: | ||
627 | temp_node = first_game; | ||
628 | for (i=0;i<curr_selection && temp_node != NULL;i++){ | ||
629 | temp_node = temp_node->next_node; | ||
630 | } | ||
631 | return temp_node; | ||
632 | break; | ||
633 | case ACTION_STD_CANCEL: | ||
634 | return NULL; | ||
635 | break; | ||
636 | } | ||
637 | } | ||
638 | } | ||
639 | |||
640 | void pgn_parse_game(struct plugin_api* api, const char* filename, struct pgn_game_node* selected_game){ | ||
641 | struct pgn_ply_node size_ply, *first_ply = NULL, *temp_ply = NULL, *curr_node = NULL; | ||
642 | int fhandler, i; | ||
643 | char line_buffer[128]; | ||
644 | char token_buffer[10]; | ||
645 | unsigned short pos; | ||
646 | unsigned short curr_player = white; | ||
647 | rb = api; | ||
648 | |||
649 | fhandler = rb->open(filename, O_RDONLY); | ||
650 | |||
651 | /* seek the line where the pgn of the selected game starts */ | ||
652 | for (i=1;i<selected_game->pgn_line;i++){ | ||
653 | rb->read_line(fhandler, line_buffer, sizeof line_buffer); | ||
654 | } | ||
655 | |||
656 | loghandler = rb->open(LOG_FILE, O_WRONLY | O_CREAT); | ||
657 | |||
658 | GNUChess_Initialize(); | ||
659 | |||
660 | while (rb->read_line(fhandler, line_buffer, sizeof line_buffer) > 0){ | ||
661 | if (line_buffer[0] == '\r' || line_buffer[0] == '\n' || line_buffer[0] == '\0'){ | ||
662 | break; | ||
663 | } | ||
664 | pos = 0; | ||
665 | while (pos < rb->strlen(line_buffer)){ | ||
666 | pos = get_next_token(line_buffer, pos, token_buffer); | ||
667 | if ((token_buffer[0] >= 'A' && token_buffer[0] <= 'Z') | ||
668 | || (token_buffer[0] >= 'a' && token_buffer[0] <= 'z') | ||
669 | || (token_buffer[0] == '0' && token_buffer[2] != '1')){ | ||
670 | temp_ply = (struct pgn_ply_node *)pl_malloc(sizeof size_ply); | ||
671 | temp_ply->player = curr_player; | ||
672 | curr_player = (curr_player==white)?black:white; | ||
673 | rb->strcpy(temp_ply->pgn_text, token_buffer); | ||
674 | pgn_to_coords(temp_ply); | ||
675 | temp_ply->prev_node = NULL; | ||
676 | temp_ply->next_node = NULL; | ||
677 | if (first_ply == NULL) { | ||
678 | first_ply = curr_node = temp_ply; | ||
679 | } else { | ||
680 | curr_node->next_node = temp_ply; | ||
681 | temp_ply->prev_node = curr_node; | ||
682 | curr_node = temp_ply; | ||
683 | } | ||
684 | rb->fdprintf(loghandler,"player: %u; pgn: %s; from: %u,%u; to: %u,%u; taken: %u.\n", | ||
685 | temp_ply->player, temp_ply->pgn_text, temp_ply->row_from, temp_ply->column_from, | ||
686 | temp_ply->row_to, temp_ply->column_to, temp_ply->taken_piece); | ||
687 | } | ||
688 | } | ||
689 | } | ||
690 | |||
691 | rb->close(loghandler); | ||
692 | |||
693 | /* additional dummy ply to represent end of file without loosing the previous node's pointer */ | ||
694 | if (first_ply != NULL){ | ||
695 | temp_ply = (struct pgn_ply_node *)pl_malloc(sizeof size_ply); | ||
696 | temp_ply->player = neutral; | ||
697 | temp_ply->prev_node = curr_node; | ||
698 | curr_node->next_node = temp_ply; | ||
699 | } | ||
700 | selected_game->first_ply = first_ply; | ||
701 | rb->close(fhandler); | ||
702 | } | ||
diff --git a/apps/plugins/chessbox/chessbox_pgn.h b/apps/plugins/chessbox/chessbox_pgn.h new file mode 100644 index 0000000000..541bbc8b81 --- /dev/null +++ b/apps/plugins/chessbox/chessbox_pgn.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 Mauricio Peccorini | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "plugin.h" | ||
21 | #include "gnuchess.h" | ||
22 | |||
23 | /* structure to represent the plies */ | ||
24 | struct pgn_ply_node { | ||
25 | unsigned short player; | ||
26 | char pgn_text[9]; | ||
27 | unsigned short row_from; | ||
28 | unsigned short column_from; | ||
29 | unsigned short row_to; | ||
30 | unsigned short column_to; | ||
31 | unsigned short taken_piece; | ||
32 | unsigned short promotion_piece; | ||
33 | bool enpassant; | ||
34 | bool castle; | ||
35 | bool promotion; | ||
36 | struct pgn_ply_node* prev_node; | ||
37 | struct pgn_ply_node* next_node; | ||
38 | }; | ||
39 | |||
40 | /* structure to list the games */ | ||
41 | struct pgn_game_node { | ||
42 | unsigned short game_number; | ||
43 | char white_player[20]; | ||
44 | char black_player[20]; | ||
45 | char game_date[11]; | ||
46 | char result[8]; | ||
47 | int pgn_line; | ||
48 | struct pgn_ply_node* first_ply; | ||
49 | struct pgn_game_node* next_node; | ||
50 | }; | ||
51 | |||
52 | /* Return the list of games in a PGN file. | ||
53 | * Parsing of the games themselves is postponed until | ||
54 | * the user selects a game, that obviously saves processing | ||
55 | * and speeds up response when the user selects the file | ||
56 | */ | ||
57 | struct pgn_game_node* pgn_list_games(struct plugin_api* api, const char* filename); | ||
58 | |||
59 | /* Show the list of games found in a file and allow the user | ||
60 | * to select a game to be parsed and showed | ||
61 | */ | ||
62 | struct pgn_game_node* pgn_show_game_list(struct plugin_api* api, struct pgn_game_node* first_game); | ||
63 | |||
64 | /* Parse the pgn string of a game and assign it to the move | ||
65 | * list in the structure | ||
66 | */ | ||
67 | void pgn_parse_game(struct plugin_api* api, const char* filename, struct pgn_game_node* selected_game); | ||