diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/chessbox/chessbox.c | 42 | ||||
-rw-r--r-- | apps/plugins/chessbox/chessbox_pgn.c | 381 | ||||
-rw-r--r-- | apps/plugins/chessbox/chessbox_pgn.h | 29 | ||||
-rw-r--r-- | apps/plugins/chessbox/gnuchess.c | 37 | ||||
-rw-r--r-- | apps/plugins/chessbox/gnuchess.h | 2 |
5 files changed, 461 insertions, 30 deletions
diff --git a/apps/plugins/chessbox/chessbox.c b/apps/plugins/chessbox/chessbox.c index ab75765885..8e3d889dff 100644 --- a/apps/plugins/chessbox/chessbox.c +++ b/apps/plugins/chessbox/chessbox.c | |||
@@ -672,7 +672,6 @@ void cb_start_viewer(char* filename){ | |||
672 | curr_ply = curr_ply->prev_node; | 672 | curr_ply = curr_ply->prev_node; |
673 | } else { | 673 | } else { |
674 | rb->splash ( 200 , "At the begining of the game" ); | 674 | rb->splash ( 200 , "At the begining of the game" ); |
675 | cb_drawboard(); | ||
676 | break; | 675 | break; |
677 | } | 676 | } |
678 | board[locn[curr_ply->row_from][curr_ply->column_from]] | 677 | board[locn[curr_ply->row_from][curr_ply->column_from]] |
@@ -952,7 +951,8 @@ struct cb_command cb_getcommand (void) { | |||
952 | /* ---- game main loop ---- */ | 951 | /* ---- game main loop ---- */ |
953 | void cb_play_game(void) { | 952 | void cb_play_game(void) { |
954 | struct cb_command command; | 953 | struct cb_command command; |
955 | char move_buffer[10]; | 954 | struct pgn_game_node *game; |
955 | char move_buffer[20]; | ||
956 | 956 | ||
957 | /* init status */ | 957 | /* init status */ |
958 | bool exit = false; | 958 | bool exit = false; |
@@ -961,9 +961,13 @@ void cb_play_game(void) { | |||
961 | 961 | ||
962 | /* init board */ | 962 | /* init board */ |
963 | GNUChess_Initialize(); | 963 | GNUChess_Initialize(); |
964 | |||
965 | /* init PGN history data structures */ | ||
966 | game = pgn_init_game(rb); | ||
964 | 967 | ||
965 | /* restore saved position, if saved */ | 968 | /* restore saved position, if saved */ |
966 | cb_restoreposition(); | 969 | cb_restoreposition(); |
970 | /* TODO: save/restore the PGN history of unfinished games */ | ||
967 | 971 | ||
968 | /* draw the board */ | 972 | /* draw the board */ |
969 | /* I don't like configscreens, start game inmediatly */ | 973 | /* I don't like configscreens, start game inmediatly */ |
@@ -973,17 +977,23 @@ void cb_play_game(void) { | |||
973 | if ( mate ) { | 977 | if ( mate ) { |
974 | rb->splash ( 500 , "Checkmate!" ); | 978 | rb->splash ( 500 , "Checkmate!" ); |
975 | rb->button_get(true); | 979 | rb->button_get(true); |
980 | pgn_store_game(rb, game); | ||
976 | GNUChess_Initialize(); | 981 | GNUChess_Initialize(); |
982 | game = pgn_init_game(rb); | ||
977 | cb_drawboard(); | 983 | cb_drawboard(); |
978 | } | 984 | } |
979 | command = cb_getcommand (); | 985 | command = cb_getcommand (); |
980 | switch (command.type) { | 986 | switch (command.type) { |
981 | case COMMAND_MOVE: | 987 | case COMMAND_MOVE: |
982 | if ( ! VerifyMove ( command.mv_s , 0 , &command.mv ) ) { | 988 | if ( ! VerifyMove (opponent, command.mv_s , 0 , &command.mv, move_buffer ) ) { |
983 | rb->splash ( 50 , "Illegal move!" ); | 989 | rb->splash ( 50 , "Illegal move!" ); |
984 | cb_drawboard(); | 990 | cb_drawboard(); |
985 | } else { | 991 | } else { |
986 | cb_drawboard(); | 992 | cb_drawboard(); |
993 | |||
994 | /* Add the ply to the PGN history (in algebraic notation) */ | ||
995 | pgn_append_ply(rb, game, opponent, move_buffer, mate); | ||
996 | |||
987 | rb->splash ( 0 , "Thinking..." ); | 997 | rb->splash ( 0 , "Thinking..." ); |
988 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 998 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
989 | rb->cpu_boost ( true ); | 999 | rb->cpu_boost ( true ); |
@@ -992,6 +1002,15 @@ void cb_play_game(void) { | |||
992 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 1002 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
993 | rb->cpu_boost ( false ); | 1003 | rb->cpu_boost ( false ); |
994 | #endif | 1004 | #endif |
1005 | /* Add the ply to the PGN history (in algebraic notation) and check | ||
1006 | * for the result of the game which is only calculated in SelectMove | ||
1007 | */ | ||
1008 | if (move_buffer[0] != '\0'){ | ||
1009 | pgn_append_ply(rb, game, computer, move_buffer, mate); | ||
1010 | } else { | ||
1011 | pgn_set_result(rb, game, mate); | ||
1012 | } | ||
1013 | |||
995 | if ( wt_command == COMMAND_QUIT ) { | 1014 | if ( wt_command == COMMAND_QUIT ) { |
996 | exit = true; | 1015 | exit = true; |
997 | break; | 1016 | break; |
@@ -1002,6 +1021,7 @@ void cb_play_game(void) { | |||
1002 | #ifdef COMMAND_RESTART | 1021 | #ifdef COMMAND_RESTART |
1003 | case COMMAND_RESTART: | 1022 | case COMMAND_RESTART: |
1004 | GNUChess_Initialize(); | 1023 | GNUChess_Initialize(); |
1024 | game = pgn_init_game(rb); | ||
1005 | cb_drawboard(); | 1025 | cb_drawboard(); |
1006 | break; | 1026 | break; |
1007 | #endif | 1027 | #endif |
@@ -1017,7 +1037,10 @@ void cb_play_game(void) { | |||
1017 | 1037 | ||
1018 | /* init board */ | 1038 | /* init board */ |
1019 | GNUChess_Initialize(); | 1039 | GNUChess_Initialize(); |
1020 | 1040 | ||
1041 | /* init PGN history data structures */ | ||
1042 | game = pgn_init_game(rb); | ||
1043 | |||
1021 | /* restore saved position, if saved */ | 1044 | /* restore saved position, if saved */ |
1022 | cb_restoreposition(); | 1045 | cb_restoreposition(); |
1023 | 1046 | ||
@@ -1040,6 +1063,16 @@ void cb_play_game(void) { | |||
1040 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 1063 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
1041 | rb->cpu_boost ( false ); | 1064 | rb->cpu_boost ( false ); |
1042 | #endif | 1065 | #endif |
1066 | |||
1067 | /* Add the ply to the PGN history (in algebraic notation) and check | ||
1068 | * for the result of the game which is only calculated in SelectMove | ||
1069 | */ | ||
1070 | if (move_buffer[0] != '\0'){ | ||
1071 | pgn_append_ply(rb, game, computer, move_buffer, mate); | ||
1072 | } else { | ||
1073 | pgn_set_result(rb, game, mate); | ||
1074 | } | ||
1075 | |||
1043 | if ( wt_command == COMMAND_QUIT ) { | 1076 | if ( wt_command == COMMAND_QUIT ) { |
1044 | exit = true; | 1077 | exit = true; |
1045 | break; | 1078 | break; |
@@ -1057,6 +1090,7 @@ void cb_play_game(void) { | |||
1057 | } | 1090 | } |
1058 | 1091 | ||
1059 | cb_saveposition(); | 1092 | cb_saveposition(); |
1093 | /* TODO: save/restore the PGN history of unfinished games */ | ||
1060 | rb->lcd_setfont(FONT_UI); | 1094 | rb->lcd_setfont(FONT_UI); |
1061 | 1095 | ||
1062 | } | 1096 | } |
diff --git a/apps/plugins/chessbox/chessbox_pgn.c b/apps/plugins/chessbox/chessbox_pgn.c index db95210a8d..fb04f6ac38 100644 --- a/apps/plugins/chessbox/chessbox_pgn.c +++ b/apps/plugins/chessbox/chessbox_pgn.c | |||
@@ -188,7 +188,8 @@ | |||
188 | #error CHESSBOX: Unsupported keypad | 188 | #error CHESSBOX: Unsupported keypad |
189 | #endif | 189 | #endif |
190 | 190 | ||
191 | #define LOG_FILE PLUGIN_DIR "/chessbox.log" | 191 | #define PGN_FILE PLUGIN_GAMES_DIR "/chessbox.pgn" |
192 | #define LOG_FILE PLUGIN_GAMES_DIR "/chessbox.log" | ||
192 | int loghandler; | 193 | int loghandler; |
193 | 194 | ||
194 | struct plugin_api* rb; | 195 | struct plugin_api* rb; |
@@ -520,6 +521,180 @@ void pgn_to_coords(struct pgn_ply_node* ply){ | |||
520 | color[locn[ply->row_from][ply->column_from]] = neutral; | 521 | color[locn[ply->row_from][ply->column_from]] = neutral; |
521 | } | 522 | } |
522 | 523 | ||
524 | void coords_to_pgn(struct pgn_ply_node* ply){ | ||
525 | int pos = 0,i,j; | ||
526 | unsigned short moving_piece = board[locn[ply->row_from][ply->column_from]]; | ||
527 | char unambiguous_position; | ||
528 | bool found = false; | ||
529 | char alg_move[5]; | ||
530 | char move_buffer[10]; | ||
531 | short move; | ||
532 | if (moving_piece == king){ | ||
533 | /* check castling */ | ||
534 | if (ply->column_from == 4 && ply->column_to == 6){ | ||
535 | /* castling kingside */ | ||
536 | rb->strcpy(ply->pgn_text,"O-O"); | ||
537 | ply->castle = true; | ||
538 | } else if (ply->column_from == 4 && ply->column_to == 2){ | ||
539 | /* castling queenside */ | ||
540 | rb->strcpy(ply->pgn_text,"O-O-O"); | ||
541 | } else { | ||
542 | if (board[locn[ply->row_to][ply->column_to]] != no_piece){ | ||
543 | rb->snprintf(ply->pgn_text,10,"Kx%c%c",'a'+ply->column_to, | ||
544 | '1'+ply->row_to); | ||
545 | } else { | ||
546 | rb->snprintf(ply->pgn_text,10,"K%c%c",'a'+ply->column_to, | ||
547 | '1'+ply->row_to); | ||
548 | } | ||
549 | } | ||
550 | } else if (moving_piece == pawn){ | ||
551 | if (ply->column_from != ply->column_to){ | ||
552 | /* check enpassant */ | ||
553 | if (board[locn[ply->row_to][ply->column_to]] == no_piece){ | ||
554 | ply->enpassant = true; | ||
555 | } | ||
556 | /* check promotions when taking a piece */ | ||
557 | if (ply->row_to == 0 || ply->row_to == 7) { | ||
558 | ply->promotion = true; | ||
559 | ply->promotion_piece = queen; | ||
560 | rb->snprintf(ply->pgn_text,10,"%cx%c%c=D", 'a'+ply->column_from, | ||
561 | 'a'+ply->column_to,'1'+ply->row_to); | ||
562 | } else { | ||
563 | rb->snprintf(ply->pgn_text,10,"%cx%c%c", 'a'+ply->column_from, | ||
564 | 'a'+ply->column_to,'1'+ply->row_to); | ||
565 | } | ||
566 | } else { | ||
567 | /* check promotions when not taking a piece */ | ||
568 | if (ply->row_to == 0 || ply->row_to == 7) { | ||
569 | ply->promotion = true; | ||
570 | ply->promotion_piece = queen; | ||
571 | rb->snprintf(ply->pgn_text,10,"%c%c=D", 'a'+ply->column_to, | ||
572 | '1'+ply->row_to); | ||
573 | } else { | ||
574 | rb->snprintf(ply->pgn_text,10,"%c%c", 'a'+ply->column_to, | ||
575 | '1'+ply->row_to); | ||
576 | } | ||
577 | } | ||
578 | } else { | ||
579 | /* verify ambiguous moves for the different kinds of pieces */ | ||
580 | unambiguous_position = '\0'; | ||
581 | if (moving_piece == knight){ | ||
582 | for (i=0;i<8;i++){ | ||
583 | if (ply->row_to + kn_offs[i][0] >= 0 && ply->row_to + kn_offs[i][0] <= 7 | ||
584 | && ply->column_to + kn_offs[i][1] >= 0 && ply->column_to + kn_offs[i][1] <= 7 | ||
585 | && board[locn[ply->row_to + kn_offs[i][0]][ply->column_to + kn_offs[i][1]]] == knight | ||
586 | && color[locn[ply->row_to + kn_offs[i][0]][ply->column_to + kn_offs[i][1]]] == ply->player | ||
587 | && (ply->row_to + kn_offs[i][0] != ply->row_from | ||
588 | || ply->column_to + kn_offs[i][1] != ply->column_from)){ | ||
589 | if (ply->row_to + kn_offs[i][0] != ply->row_from){ | ||
590 | unambiguous_position = '1' + ply->row_from; | ||
591 | } else { | ||
592 | unambiguous_position = 'a' + ply->column_from; | ||
593 | } | ||
594 | break; | ||
595 | } | ||
596 | } | ||
597 | } | ||
598 | if (moving_piece == rook || moving_piece == queen){ | ||
599 | found = false; | ||
600 | for (i=0;i<4;i++){ | ||
601 | j=1; | ||
602 | while (ply->row_to+(j*rk_offs[i][0]) >= 0 && ply->row_to+(j*rk_offs[i][0]) <= 7 && | ||
603 | ply->column_to+(j*rk_offs[i][1]) >= 0 && ply->column_to+(j*rk_offs[i][1]) <= 7){ | ||
604 | if (board[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] != no_piece) { | ||
605 | if (board[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] == moving_piece && | ||
606 | color[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] == ply->player && | ||
607 | (ply->row_to+(j*rk_offs[i][0]) != ply->row_from | ||
608 | || ply->column_to+(j*rk_offs[i][1]) != ply->column_from)) { | ||
609 | if (ply->row_to+(j*rk_offs[i][0]) != ply->row_from){ | ||
610 | unambiguous_position = '1' + ply->row_from; | ||
611 | } else { | ||
612 | unambiguous_position = 'a' + ply->column_from; | ||
613 | } | ||
614 | found = true; | ||
615 | } | ||
616 | break; | ||
617 | } | ||
618 | j++; | ||
619 | } | ||
620 | if (found) { | ||
621 | break; | ||
622 | } | ||
623 | } | ||
624 | } | ||
625 | if (moving_piece == bishop || (moving_piece == queen && !found)){ | ||
626 | for (i=0;i<4;i++){ | ||
627 | j=1; | ||
628 | while (ply->row_to+(j*bp_offs[i][0]) >= 0 && ply->row_to+(j*bp_offs[i][0]) <= 7 && | ||
629 | ply->column_to+(j*bp_offs[i][1]) >= 0 && ply->column_to+(j*bp_offs[i][1]) <= 7){ | ||
630 | if (board[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] != no_piece) { | ||
631 | if (board[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] == moving_piece && | ||
632 | color[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] == ply->player && | ||
633 | (ply->row_to+(j*bp_offs[i][0]) != ply->row_from | ||
634 | || ply->column_to+(j*bp_offs[i][1]) != ply->column_from)) { | ||
635 | if (ply->row_to+(j*bp_offs[i][0]) != ply->row_from){ | ||
636 | unambiguous_position = '1' + ply->row_from; | ||
637 | } else { | ||
638 | unambiguous_position = 'a' + ply->column_from; | ||
639 | } | ||
640 | found = true; | ||
641 | } | ||
642 | break; | ||
643 | } | ||
644 | j++; | ||
645 | } | ||
646 | if (found) { | ||
647 | break; | ||
648 | } | ||
649 | } | ||
650 | } | ||
651 | /* generate the first portion of the PGN text | ||
652 | * always as white so all uppercase, black/white considerations | ||
653 | * will be useful for FEN notation but not in this case | ||
654 | */ | ||
655 | if (unambiguous_position == '\0'){ | ||
656 | if (board[locn[ply->row_to][ply->column_to]] != no_piece){ | ||
657 | rb->snprintf(ply->pgn_text,10,"%cx%c%c", | ||
658 | pgn_from_piece(moving_piece,white) , | ||
659 | 'a'+ply->column_to, '1'+ply->row_to); | ||
660 | } else { | ||
661 | rb->snprintf(ply->pgn_text,10,"%c%c%c", | ||
662 | pgn_from_piece(moving_piece,white) , | ||
663 | 'a'+ply->column_to, '1'+ply->row_to); | ||
664 | } | ||
665 | } else { | ||
666 | if (board[locn[ply->row_to][ply->column_to]] != no_piece){ | ||
667 | rb->snprintf(ply->pgn_text,10,"%c%cx%c%c", | ||
668 | pgn_from_piece(moving_piece,white) , | ||
669 | unambiguous_position, 'a'+ply->column_to, | ||
670 | '1'+ply->row_to); | ||
671 | } else { | ||
672 | rb->snprintf(ply->pgn_text,10,"%c%c%c%c", | ||
673 | pgn_from_piece(moving_piece,white) , | ||
674 | unambiguous_position, 'a'+ply->column_to, | ||
675 | '1'+ply->row_to); | ||
676 | } | ||
677 | } | ||
678 | } | ||
679 | /* update the board */ | ||
680 | rb->snprintf(alg_move,5,"%c%c%c%c",'a' + ply->column_from, '1' + ply->row_from, | ||
681 | 'a' + ply->column_to, '1' + ply->row_to); | ||
682 | /* The function returns false if the move is invalid, but since we're | ||
683 | * replaying the game, that should not be posible | ||
684 | */ | ||
685 | VerifyMove (ply->player, alg_move , 0 , &move, move_buffer ); | ||
686 | |||
687 | /* add check/mate indicators */ | ||
688 | for (pos=0;ply->pgn_text[pos] != '\0';pos++); | ||
689 | if (ply->checkmate) { | ||
690 | ply->pgn_text[pos] = '#'; pos++; | ||
691 | ply->pgn_text[pos] = '\0'; pos++; | ||
692 | } else if (move_buffer[4] == '+'){ | ||
693 | ply->pgn_text[pos] = '+'; pos++; | ||
694 | ply->pgn_text[pos] = '\0'; pos++; | ||
695 | } | ||
696 | } | ||
697 | |||
523 | char * get_game_text(int selected_item, void *data, char *buffer){ | 698 | char * get_game_text(int selected_item, void *data, char *buffer){ |
524 | int i; | 699 | int i; |
525 | struct pgn_game_node *temp_node = (struct pgn_game_node *)data; | 700 | struct pgn_game_node *temp_node = (struct pgn_game_node *)data; |
@@ -538,11 +713,21 @@ char * get_game_text(int selected_item, void *data, char *buffer){ | |||
538 | return buffer; | 713 | return buffer; |
539 | } | 714 | } |
540 | 715 | ||
716 | void write_pgn_token(int fhandler, char *buffer, size_t *line_length){ | ||
717 | if (*line_length + rb->strlen(buffer) + 1 > 80){ | ||
718 | rb->fdprintf(fhandler,"\n"); | ||
719 | *line_length = 0; | ||
720 | } | ||
721 | rb->fdprintf(fhandler,"%s ",buffer); | ||
722 | *line_length += (rb->strlen(buffer) + 1); | ||
723 | } | ||
724 | |||
541 | /* ---- api functions ---- */ | 725 | /* ---- api functions ---- */ |
542 | struct pgn_game_node* pgn_list_games(struct plugin_api* api,const char* filename){ | 726 | struct pgn_game_node* pgn_list_games(struct plugin_api* api,const char* filename){ |
543 | int fhandler; | 727 | int fhandler; |
544 | char line_buffer[128]; | 728 | char line_buffer[128]; |
545 | struct pgn_game_node size_node, *first_game = NULL, *curr_node = NULL, *temp_node; | 729 | struct pgn_game_node size_node, *first_game = NULL; |
730 | struct pgn_game_node *curr_node = NULL, *temp_node; | ||
546 | unsigned short game_count = 1; | 731 | unsigned short game_count = 1; |
547 | int line_count = 0; | 732 | int line_count = 0; |
548 | bool header_start = true, game_start = false; | 733 | bool header_start = true, game_start = false; |
@@ -577,7 +762,9 @@ struct pgn_game_node* pgn_list_games(struct plugin_api* api,const char* filename | |||
577 | } else { | 762 | } else { |
578 | if (line_buffer[0] == '['){ | 763 | if (line_buffer[0] == '['){ |
579 | process_tag(curr_node, line_buffer); | 764 | process_tag(curr_node, line_buffer); |
580 | } else if (line_buffer[0] == '\r' || line_buffer[0] == '\n' || line_buffer[0] == '\0'){ | 765 | } else if (line_buffer[0] == '\r' |
766 | || line_buffer[0] == '\n' | ||
767 | || line_buffer[0] == '\0'){ | ||
581 | if (game_start) { | 768 | if (game_start) { |
582 | game_start = false; | 769 | game_start = false; |
583 | } else { | 770 | } else { |
@@ -594,7 +781,8 @@ struct pgn_game_node* pgn_list_games(struct plugin_api* api,const char* filename | |||
594 | return first_game; | 781 | return first_game; |
595 | } | 782 | } |
596 | 783 | ||
597 | struct pgn_game_node* pgn_show_game_list(struct plugin_api* api, struct pgn_game_node* first_game){ | 784 | struct pgn_game_node* pgn_show_game_list(struct plugin_api* api, |
785 | struct pgn_game_node* first_game){ | ||
598 | int curr_selection = 0; | 786 | int curr_selection = 0; |
599 | int button; | 787 | int button; |
600 | struct gui_synclist games_list; | 788 | struct gui_synclist games_list; |
@@ -638,8 +826,10 @@ struct pgn_game_node* pgn_show_game_list(struct plugin_api* api, struct pgn_game | |||
638 | } | 826 | } |
639 | } | 827 | } |
640 | 828 | ||
641 | void pgn_parse_game(struct plugin_api* api, const char* filename, struct pgn_game_node* selected_game){ | 829 | void pgn_parse_game(struct plugin_api* api, const char* filename, |
642 | struct pgn_ply_node size_ply, *first_ply = NULL, *temp_ply = NULL, *curr_node = NULL; | 830 | struct pgn_game_node* selected_game){ |
831 | struct pgn_ply_node size_ply, *first_ply = NULL; | ||
832 | struct pgn_ply_node *temp_ply = NULL, *curr_node = NULL; | ||
643 | int fhandler, i; | 833 | int fhandler, i; |
644 | char line_buffer[128]; | 834 | char line_buffer[128]; |
645 | char token_buffer[10]; | 835 | char token_buffer[10]; |
@@ -682,16 +872,20 @@ void pgn_parse_game(struct plugin_api* api, const char* filename, struct pgn_gam | |||
682 | temp_ply->prev_node = curr_node; | 872 | temp_ply->prev_node = curr_node; |
683 | curr_node = temp_ply; | 873 | curr_node = temp_ply; |
684 | } | 874 | } |
685 | rb->fdprintf(loghandler,"player: %u; pgn: %s; from: %u,%u; to: %u,%u; taken: %u.\n", | 875 | rb->fdprintf(loghandler, |
686 | temp_ply->player, temp_ply->pgn_text, temp_ply->row_from, temp_ply->column_from, | 876 | "player: %u; pgn: %s; from: %u,%u; to: %u,%u; taken: %u.\n", |
687 | temp_ply->row_to, temp_ply->column_to, temp_ply->taken_piece); | 877 | temp_ply->player, temp_ply->pgn_text, temp_ply->row_from, |
878 | temp_ply->column_from, temp_ply->row_to, | ||
879 | temp_ply->column_to, temp_ply->taken_piece); | ||
688 | } | 880 | } |
689 | } | 881 | } |
690 | } | 882 | } |
691 | 883 | ||
692 | rb->close(loghandler); | 884 | rb->close(loghandler); |
693 | 885 | ||
694 | /* additional dummy ply to represent end of file without loosing the previous node's pointer */ | 886 | /* additional dummy ply to represent end of file without |
887 | *loosing the previous node's pointer | ||
888 | */ | ||
695 | if (first_ply != NULL){ | 889 | if (first_ply != NULL){ |
696 | temp_ply = (struct pgn_ply_node *)pl_malloc(sizeof size_ply); | 890 | temp_ply = (struct pgn_ply_node *)pl_malloc(sizeof size_ply); |
697 | temp_ply->player = neutral; | 891 | temp_ply->player = neutral; |
@@ -701,3 +895,170 @@ void pgn_parse_game(struct plugin_api* api, const char* filename, struct pgn_gam | |||
701 | selected_game->first_ply = first_ply; | 895 | selected_game->first_ply = first_ply; |
702 | rb->close(fhandler); | 896 | rb->close(fhandler); |
703 | } | 897 | } |
898 | |||
899 | struct pgn_game_node* pgn_init_game(struct plugin_api* api){ | ||
900 | struct pgn_game_node game_size, *game; | ||
901 | struct pgn_ply_node ply_size, *ply; | ||
902 | struct tm *current_time; | ||
903 | |||
904 | rb = api; | ||
905 | |||
906 | if (bufptr == NULL){ | ||
907 | pl_malloc_init(); | ||
908 | } | ||
909 | |||
910 | /* create an "end of game" dummy ply and assign defaults */ | ||
911 | ply = (struct pgn_ply_node *)pl_malloc(sizeof ply_size); | ||
912 | ply->player = neutral; | ||
913 | ply->pgn_text[0] = '\0'; | ||
914 | ply->prev_node = NULL; | ||
915 | ply->next_node = NULL; | ||
916 | |||
917 | /* create the game and assign defaults */ | ||
918 | game = (struct pgn_game_node *)pl_malloc(sizeof game_size); | ||
919 | game->game_number = 0; | ||
920 | rb->strcpy(game->white_player,"Player"); | ||
921 | rb->strcpy(game->black_player,"GnuChess"); | ||
922 | current_time = rb->get_time(); | ||
923 | if (current_time->tm_year < 100){ | ||
924 | rb->snprintf(game->game_date,11,"????.??.??"); | ||
925 | } else { | ||
926 | rb->snprintf(game->game_date,11,"%4u.%2u.%2u",current_time->tm_year + 1900, | ||
927 | current_time->tm_mon + 1, current_time->tm_mday); | ||
928 | } | ||
929 | rb->strcpy(game->result,"*"); | ||
930 | game->pgn_line = 0; | ||
931 | game->first_ply = ply; | ||
932 | game->next_node = NULL; | ||
933 | |||
934 | return game; | ||
935 | } | ||
936 | |||
937 | void pgn_append_ply(struct plugin_api* api, struct pgn_game_node* game, | ||
938 | unsigned short ply_player, char *move_buffer, bool is_mate){ | ||
939 | struct pgn_ply_node ply_size, *ply, *temp; | ||
940 | |||
941 | rb = api; | ||
942 | |||
943 | ply = (struct pgn_ply_node *)pl_malloc(sizeof ply_size); | ||
944 | ply->player = ply_player; | ||
945 | ply->column_from = move_buffer[0] - 'a'; | ||
946 | ply->row_from = move_buffer[1] - '1'; | ||
947 | ply->column_to = move_buffer[2] - 'a'; | ||
948 | ply->row_to = move_buffer[3] - '1'; | ||
949 | ply->castle = false; | ||
950 | ply->promotion = false; | ||
951 | ply->enpassant = false; | ||
952 | ply->promotion_piece = no_piece; | ||
953 | ply->taken_piece = no_piece; | ||
954 | ply->draw = false; | ||
955 | ply->checkmate = is_mate; | ||
956 | |||
957 | /* move the pointer to the "end of game" marker ply */ | ||
958 | for (temp=game->first_ply;temp->next_node!=NULL;temp=temp->next_node); | ||
959 | |||
960 | /* arrange the pointers to insert the ply before the marker */ | ||
961 | ply->next_node = temp; | ||
962 | ply->prev_node = temp->prev_node; | ||
963 | if (temp->prev_node == NULL){ | ||
964 | game->first_ply = ply; | ||
965 | } else { | ||
966 | temp->prev_node->next_node = ply; | ||
967 | } | ||
968 | temp->prev_node = ply; | ||
969 | } | ||
970 | |||
971 | void pgn_set_result(struct plugin_api* api, struct pgn_game_node* game, | ||
972 | bool is_mate){ | ||
973 | |||
974 | rb = api; | ||
975 | |||
976 | struct pgn_ply_node *ply; | ||
977 | for(ply=game->first_ply;ply->next_node != NULL;ply=ply->next_node); | ||
978 | if (is_mate){ | ||
979 | ply->prev_node->checkmate = true; | ||
980 | } else { | ||
981 | ply->prev_node->draw = true; | ||
982 | } | ||
983 | } | ||
984 | |||
985 | void pgn_store_game(struct plugin_api* api, struct pgn_game_node* game){ | ||
986 | int fhandler; | ||
987 | struct pgn_ply_node *ply; | ||
988 | unsigned ply_count; | ||
989 | size_t line_length=0; | ||
990 | char buffer[10]; | ||
991 | |||
992 | rb = api; | ||
993 | |||
994 | GNUChess_Initialize(); | ||
995 | |||
996 | ply_count=0; | ||
997 | ply=game->first_ply; | ||
998 | while (ply->next_node!=NULL){ | ||
999 | coords_to_pgn(ply); | ||
1000 | if (ply->checkmate){ | ||
1001 | if (ply->player == white){ | ||
1002 | rb->strcpy(game->result,"1-0"); | ||
1003 | } else { | ||
1004 | rb->strcpy(game->result,"0-1"); | ||
1005 | } | ||
1006 | } | ||
1007 | if (ply->draw){ | ||
1008 | rb->strcpy(game->result,"1/2-1/2"); | ||
1009 | } | ||
1010 | ply=ply->next_node; | ||
1011 | ply_count++; | ||
1012 | } | ||
1013 | |||
1014 | fhandler = rb->open(PGN_FILE, O_WRONLY|O_CREAT|O_APPEND); | ||
1015 | |||
1016 | |||
1017 | /* the first 7 tags are mandatory according to the PGN specification so we | ||
1018 | * have to include them even if the values don't make much sense | ||
1019 | */ | ||
1020 | rb->fdprintf(fhandler,"[Event \"Casual Game\"]\n"); | ||
1021 | rb->fdprintf(fhandler,"[Site \"?\"]\n"); | ||
1022 | rb->fdprintf(fhandler,"[Date \"%s\"]\n",game->game_date); | ||
1023 | rb->fdprintf(fhandler,"[Round \"?\"]\n"); | ||
1024 | rb->fdprintf(fhandler,"[White \"%s\"]\n",game->white_player); | ||
1025 | rb->fdprintf(fhandler,"[Black \"%s\"]\n",game->black_player); | ||
1026 | rb->fdprintf(fhandler,"[Result \"%s\"]\n",game->result); | ||
1027 | rb->fdprintf(fhandler,"[PlyCount \"%u\"]\n",ply_count); | ||
1028 | |||
1029 | /* leave a blank line between the tag section and the game section */ | ||
1030 | rb->fdprintf(fhandler,"\n"); | ||
1031 | |||
1032 | /* write the plies in several lines of up to 80 characters */ | ||
1033 | for (ply_count=0, ply=game->first_ply;ply->next_node!=NULL; | ||
1034 | ply=ply->next_node,ply_count++){ | ||
1035 | /* write the move number */ | ||
1036 | if (ply->player == white){ | ||
1037 | rb->snprintf(buffer,10,"%u.",(ply_count/2)+1); | ||
1038 | write_pgn_token(fhandler, buffer, &line_length); | ||
1039 | } | ||
1040 | /* write the actual move */ | ||
1041 | write_pgn_token(fhandler,ply->pgn_text,&line_length); | ||
1042 | /* write the result of the game at the end */ | ||
1043 | if (ply->checkmate){ | ||
1044 | if (ply->player == white){ | ||
1045 | write_pgn_token(fhandler,"1-0",&line_length); | ||
1046 | } else { | ||
1047 | write_pgn_token(fhandler,"0-1",&line_length); | ||
1048 | } | ||
1049 | break; | ||
1050 | } else if (ply->draw){ | ||
1051 | write_pgn_token(fhandler,"1/2-1/2",&line_length); | ||
1052 | break; | ||
1053 | } else if (ply->next_node->player == neutral) { | ||
1054 | /* unknown end of the game */ | ||
1055 | write_pgn_token(fhandler,"*",&line_length); | ||
1056 | break; | ||
1057 | } | ||
1058 | } | ||
1059 | |||
1060 | /* leave a blank line between the tag section and the game section */ | ||
1061 | rb->fdprintf(fhandler,"\n\n"); | ||
1062 | |||
1063 | rb->close(fhandler); | ||
1064 | } | ||
diff --git a/apps/plugins/chessbox/chessbox_pgn.h b/apps/plugins/chessbox/chessbox_pgn.h index e57b45dc5a..c4dd5c671f 100644 --- a/apps/plugins/chessbox/chessbox_pgn.h +++ b/apps/plugins/chessbox/chessbox_pgn.h | |||
@@ -33,6 +33,8 @@ struct pgn_ply_node { | |||
33 | bool enpassant; | 33 | bool enpassant; |
34 | bool castle; | 34 | bool castle; |
35 | bool promotion; | 35 | bool promotion; |
36 | bool checkmate; | ||
37 | bool draw; | ||
36 | struct pgn_ply_node* prev_node; | 38 | struct pgn_ply_node* prev_node; |
37 | struct pgn_ply_node* next_node; | 39 | struct pgn_ply_node* next_node; |
38 | }; | 40 | }; |
@@ -54,14 +56,35 @@ struct pgn_game_node { | |||
54 | * the user selects a game, that obviously saves processing | 56 | * the user selects a game, that obviously saves processing |
55 | * and speeds up response when the user selects the file | 57 | * and speeds up response when the user selects the file |
56 | */ | 58 | */ |
57 | struct pgn_game_node* pgn_list_games(struct plugin_api* api, const char* filename); | 59 | struct pgn_game_node* pgn_list_games(struct plugin_api* api, |
60 | const char* filename); | ||
58 | 61 | ||
59 | /* Show the list of games found in a file and allow the user | 62 | /* Show the list of games found in a file and allow the user |
60 | * to select a game to be parsed and showed | 63 | * to select a game to be parsed and showed |
61 | */ | 64 | */ |
62 | struct pgn_game_node* pgn_show_game_list(struct plugin_api* api, struct pgn_game_node* first_game); | 65 | struct pgn_game_node* pgn_show_game_list(struct plugin_api* api, |
66 | struct pgn_game_node* first_game); | ||
63 | 67 | ||
64 | /* Parse the pgn string of a game and assign it to the move | 68 | /* Parse the pgn string of a game and assign it to the move |
65 | * list in the structure | 69 | * list in the structure |
66 | */ | 70 | */ |
67 | void pgn_parse_game(struct plugin_api* api, const char* filename, struct pgn_game_node* selected_game); | 71 | void pgn_parse_game(struct plugin_api* api, const char* filename, |
72 | struct pgn_game_node* selected_game); | ||
73 | |||
74 | /* Initialize a new game structure with default values and make | ||
75 | * it ready to store the history of a newly played match | ||
76 | */ | ||
77 | struct pgn_game_node* pgn_init_game(struct plugin_api* api); | ||
78 | |||
79 | /* Add a new ply to the game structure based on the positions */ | ||
80 | void pgn_append_ply(struct plugin_api* api, struct pgn_game_node* game, | ||
81 | unsigned short ply_player, char *move_buffer, bool is_mate); | ||
82 | |||
83 | /* Set the result of the game if it was reached during the opponent's ply | ||
84 | */ | ||
85 | void pgn_set_result(struct plugin_api* api, struct pgn_game_node* game, | ||
86 | bool is_mate); | ||
87 | |||
88 | /* Store a complete game in the PGN history file | ||
89 | */ | ||
90 | void pgn_store_game(struct plugin_api* api, struct pgn_game_node* game); | ||
diff --git a/apps/plugins/chessbox/gnuchess.c b/apps/plugins/chessbox/gnuchess.c index e72a489a0d..3574dd6fbe 100644 --- a/apps/plugins/chessbox/gnuchess.c +++ b/apps/plugins/chessbox/gnuchess.c | |||
@@ -1116,10 +1116,9 @@ static short i,alpha,beta,score,tempb,tempc,tempsf,tempst,xside,rpt; | |||
1116 | /*OutputMove();*/ | 1116 | /*OutputMove();*/ |
1117 | 1117 | ||
1118 | short index; | 1118 | short index; |
1119 | for (index=0;index<4;index++){ | 1119 | for (index=0;index<5;index++){ |
1120 | move_buffer[index] = mvstr1[index]; | 1120 | move_buffer[index] = mvstr1[index]; |
1121 | } | 1121 | } |
1122 | move_buffer[index] = '\0'; | ||
1123 | 1122 | ||
1124 | if (score == -9999 || score == 9998) mate = true; | 1123 | if (score == -9999 || score == 9998) mate = true; |
1125 | if (mate) hint = 0; | 1124 | if (mate) hint = 0; |
@@ -2231,26 +2230,30 @@ void SetTimeControl( void ) | |||
2231 | ExitChess(); | 2230 | ExitChess(); |
2232 | }*/ | 2231 | }*/ |
2233 | 2232 | ||
2234 | int VerifyMove(char s[],short iop,unsigned short *mv) | 2233 | int VerifyMove(short player, char s[],short iop,unsigned short *mv, char *move_buffer) |
2235 | 2234 | ||
2236 | /* | 2235 | /* |
2237 | Compare the string 's' to the list of legal moves available for the | 2236 | Compare the string 's' to the list of legal moves available for the |
2238 | opponent. If a match is found, make the move on the board. | 2237 | player. If a match is found, make the move on the board. This was originally |
2238 | fixed for the opponent, but allowing the player to be specified will make | ||
2239 | possible to use GnuChess as a human vs human game verifier. It also allows | ||
2240 | the PGN functions to verify checkmates. | ||
2239 | */ | 2241 | */ |
2240 | 2242 | ||
2241 | { | 2243 | { |
2242 | static short pnt,tempb,tempc,tempsf,tempst,cnt; | 2244 | static short pnt,tempb,tempc,tempsf,tempst,cnt; |
2243 | static struct leaf xnode; | 2245 | static struct leaf xnode; |
2244 | struct leaf *node; | 2246 | struct leaf *node; |
2247 | short opponent_player = (player == white)?black:white; | ||
2245 | 2248 | ||
2246 | *mv = 0; | 2249 | *mv = 0; |
2247 | if (iop == 2) | 2250 | if (iop == 2) |
2248 | { | 2251 | { |
2249 | UnmakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst); | 2252 | UnmakeMove(player,&xnode,&tempb,&tempc,&tempsf,&tempst); |
2250 | return(false); | 2253 | return(false); |
2251 | } | 2254 | } |
2252 | cnt = 0; | 2255 | cnt = 0; |
2253 | MoveList(opponent,2); | 2256 | MoveList(player,2); |
2254 | pnt = TrPnt[2]; | 2257 | pnt = TrPnt[2]; |
2255 | while (pnt < TrPnt[3]) | 2258 | while (pnt < TrPnt[3]) |
2256 | { | 2259 | { |
@@ -2264,10 +2267,10 @@ struct leaf *node; | |||
2264 | } | 2267 | } |
2265 | if (cnt == 1) | 2268 | if (cnt == 1) |
2266 | { | 2269 | { |
2267 | MakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst); | 2270 | MakeMove(player,&xnode,&tempb,&tempc,&tempsf,&tempst); |
2268 | if (SqAtakd(PieceList[opponent][0],computer)) | 2271 | if (SqAtakd(PieceList[player][0],opponent_player)) |
2269 | { | 2272 | { |
2270 | UnmakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst); | 2273 | UnmakeMove(player,&xnode,&tempb,&tempc,&tempsf,&tempst); |
2271 | /*ShowMessage("Illegal Move!!");*/ | 2274 | /*ShowMessage("Illegal Move!!");*/ |
2272 | return(false); | 2275 | return(false); |
2273 | } | 2276 | } |
@@ -2283,10 +2286,20 @@ struct leaf *node; | |||
2283 | GameList[GameCnt].nodes = 0; | 2286 | GameList[GameCnt].nodes = 0; |
2284 | ElapsedTime(1); | 2287 | ElapsedTime(1); |
2285 | GameList[GameCnt].time = (short)et; | 2288 | GameList[GameCnt].time = (short)et; |
2286 | TimeControl.clock[opponent] -= et; | 2289 | TimeControl.clock[player] -= et; |
2287 | --TimeControl.moves[opponent]; | 2290 | --TimeControl.moves[player]; |
2288 | *mv = (xnode.f << 8) + xnode.t; | 2291 | *mv = (xnode.f << 8) + xnode.t; |
2289 | algbr(xnode.f,xnode.t,false); | 2292 | algbr(xnode.f,xnode.t,false); |
2293 | |||
2294 | short index; | ||
2295 | for (index=0;index<5;index++){ | ||
2296 | move_buffer[index] = mvstr1[index]; | ||
2297 | } | ||
2298 | if (SqAtakd(PieceList[opponent_player][0],player)){ | ||
2299 | move_buffer[4] = '+'; | ||
2300 | move_buffer[5] = '\0'; | ||
2301 | } | ||
2302 | |||
2290 | return(true); | 2303 | return(true); |
2291 | } | 2304 | } |
2292 | } | 2305 | } |
diff --git a/apps/plugins/chessbox/gnuchess.h b/apps/plugins/chessbox/gnuchess.h index 5367bb3254..6a4a6bdd4e 100644 --- a/apps/plugins/chessbox/gnuchess.h +++ b/apps/plugins/chessbox/gnuchess.h | |||
@@ -49,7 +49,7 @@ extern struct plugin_api* rb; | |||
49 | /* ---- The beginning of a GNUChess v2 APIfication ---- */ | 49 | /* ---- The beginning of a GNUChess v2 APIfication ---- */ |
50 | void SetTimeControl(void); | 50 | void SetTimeControl(void); |
51 | void GNUChess_Initialize(void); | 51 | void GNUChess_Initialize(void); |
52 | int VerifyMove(char s[],short iop,unsigned short *mv); | 52 | int VerifyMove(short player, char s[],short iop,unsigned short *mv, char *move_buffer); |
53 | int SelectMove ( short side, short iop , void (*callback)(void), char *move_buffer ); | 53 | int SelectMove ( short side, short iop , void (*callback)(void), char *move_buffer ); |
54 | void InitializeStats ( void ); | 54 | void InitializeStats ( void ); |
55 | void ElapsedTime ( short iop ); | 55 | void ElapsedTime ( short iop ); |