summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/plugins/chessbox/chessbox_pgn.c702
-rw-r--r--apps/plugins/chessbox/chessbox_pgn.h67
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"
191int loghandler;
192
193struct plugin_api* rb;
194
195short kn_offs[8][2] = {{2,1},{2,-1},{-2,1},{-2,-1},{1,2},{1,-2},{-1,2},{-1,-2}};
196short rk_offs[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
197short bp_offs[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}};
198
199/* global vars for pl_malloc() */
200void *bufptr = NULL;
201ssize_t bufleft;
202
203/* simple function to "allocate" memory in pluginbuffer.
204 * (borrowed from dict.c)
205 */
206void *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() */
223void pl_malloc_init(void)
224{
225 bufptr = rb->plugin_get_buffer((size_t *)&bufleft);
226}
227
228void 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
263unsigned 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
280unsigned 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
296char 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
327void 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
522char * 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 ---- */
541struct 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
596struct 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
640void 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 */
24struct 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 */
41struct 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 */
57struct 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 */
62struct 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 */
67void pgn_parse_game(struct plugin_api* api, const char* filename, struct pgn_game_node* selected_game);