summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/plugins/chessbox/chessbox.c42
-rw-r--r--apps/plugins/chessbox/chessbox_pgn.c381
-rw-r--r--apps/plugins/chessbox/chessbox_pgn.h29
-rw-r--r--apps/plugins/chessbox/gnuchess.c37
-rw-r--r--apps/plugins/chessbox/gnuchess.h2
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 ---- */
953void cb_play_game(void) { 952void 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"
192int loghandler; 193int loghandler;
193 194
194struct plugin_api* rb; 195struct 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
524void 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
523char * get_game_text(int selected_item, void *data, char *buffer){ 698char * 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
716void 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 ---- */
542struct pgn_game_node* pgn_list_games(struct plugin_api* api,const char* filename){ 726struct 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
597struct pgn_game_node* pgn_show_game_list(struct plugin_api* api, struct pgn_game_node* first_game){ 784struct 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
641void pgn_parse_game(struct plugin_api* api, const char* filename, struct pgn_game_node* selected_game){ 829void 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
899struct 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
937void 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
971void 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
985void 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 */
57struct pgn_game_node* pgn_list_games(struct plugin_api* api, const char* filename); 59struct 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 */
62struct pgn_game_node* pgn_show_game_list(struct plugin_api* api, struct pgn_game_node* first_game); 65struct 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 */
67void pgn_parse_game(struct plugin_api* api, const char* filename, struct pgn_game_node* selected_game); 71void 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 */
77struct pgn_game_node* pgn_init_game(struct plugin_api* api);
78
79/* Add a new ply to the game structure based on the positions */
80void 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 */
85void 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 */
90void 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
2234int VerifyMove(char s[],short iop,unsigned short *mv) 2233int 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{
2242static short pnt,tempb,tempc,tempsf,tempst,cnt; 2244static short pnt,tempb,tempc,tempsf,tempst,cnt;
2243static struct leaf xnode; 2245static struct leaf xnode;
2244struct leaf *node; 2246struct leaf *node;
2247short 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 ---- */
50void SetTimeControl(void); 50void SetTimeControl(void);
51void GNUChess_Initialize(void); 51void GNUChess_Initialize(void);
52int VerifyMove(char s[],short iop,unsigned short *mv); 52int VerifyMove(short player, char s[],short iop,unsigned short *mv, char *move_buffer);
53int SelectMove ( short side, short iop , void (*callback)(void), char *move_buffer ); 53int SelectMove ( short side, short iop , void (*callback)(void), char *move_buffer );
54void InitializeStats ( void ); 54void InitializeStats ( void );
55void ElapsedTime ( short iop ); 55void ElapsedTime ( short iop );