/******************************************************************************/ /*** ***/ /*** Main program for chess playing robot. Software written by ***/ /*** ***/ /*** Arnoud Visser, arnoud@fwi.uva.nl ***/ /*** Joris van Dam, dam@fwi.uva.nl ***/ /*** ***/ /*** Software thorougly messed up by Matthijs Spaan ***/ /*** and some more by Olaf Booij ***/ /*** $Id: playchess.c,v 1.26 2008/06/13 11:34:05 obooij Exp $ ***/ /*** ***/ /******************************************************************************/ #include #include #include #include #include "interface.h" #include "chess.h" #include "arm.h" #include "path.h" #include "chesscmds.h" #define NO_WINDOW #define EXIT_FAILURE 1 static double boardX=-1, boardY=-1, boardTheta=-1; #ifdef ENDGAME static int useProlog=1; #else static int useProlog=0; #endif #ifdef ROOK static int doRookEndgame=1; #else static int doRookEndgame=0; #endif #ifdef QUEEN static int doQueenEndgame=1; #else static int doQueenEndgame=0; #endif #ifdef PAWN static int doPawnEndgame=1; #else static int doPawnEndgame=0; #endif #ifdef ROOKROOK static int doRookRookEndgame=1; #else static int doRookRookEndgame=0; #endif static int useStandardPP=1,useStandardIK=1; /* * Function specifications to keep scil happy */ static void joehoe (); static void mm_play (); static void mm_start_loop (); static void mm_piece_move (); static void mm_end (); static void setupBoard(void); static int read_java_board (chess_board_t *board, char *filename); static void write_java_board (chess_board_t* board, FILE* fid); static void joehoe () { chess_board_t board; if(!useStandardPP) printf("playchess : using STUDENT path planning module\n"); else printf("playchess : using STANDARD path planning module\n"); if(!useStandardIK) printf("playchess : using STUDENT inverse kinematics module\n"); else printf("playchess : using STANDARD inverse kinematics module\n"); if(!useProlog) printf("playchess : using STANDARD user input for white moves\n"); else printf("playchess : using STUDENT Prolog endgame solver for finding white moves\n"); if (read_java_board(&board, "board.gch") != EXIT_SUCCESS) { printf("playchess : No board.gch present at the moment.\n"); } else { printf("playchess : Present board setting (board.gch) is:\n"); write_java_board(&board, stdout); } } /* static void write_xyz_list (xyz_list) xyz_list_t xyz_list; { FILE* fid; xyz_list_t xyz; fid = fopen("positions.txt", "w"); if (fid == NULL){ fprintf(stderr, "Cannot open file positions.txt\n Exiting..."); exit(EXIT_FAILURE); } xyz = xyz_list; while(xyz != NULL){ fprintf(fid, "%f %f %f %f %f \n", xyz->x, xyz->y, xyz->z, xyz->theta, xyz->grip); xyz = xyz->next_data; } fclose(fid); } */ // write a gnuchessr to general file (could be stdout) static void write_java_board (chess_board_t* board, FILE* fid) { int row, column; // print the header // TODO, This now prints a phony header, this should contain more info. fprintf(fid,"Black computer White Human 1\n"); fprintf(fid,"Castled White false Black false\n"); fprintf(fid,"TimeControl 0 Operator Time 0\n"); fprintf(fid,"White Clock 0 Moves 0\n"); fprintf(fid,"Black Clock 0 Moves 0\n"); fprintf(fid,"\n"); for(row = 7; row >= 0; row--){ fprintf(fid, "%d ", row+1); for(column = 0; column < 8; column++){ if(board->field[row][column] == NULL){ fprintf(fid, "."); } else{ switch (board->field[row][column]->side){ case white_player: switch (board->field[row][column]->kind){ case pawn_piece: fprintf(fid, "p"); break; case rook_piece: fprintf(fid, "r"); break; case knight_piece: fprintf(fid, "n"); break; case bishop_piece: fprintf(fid, "b"); break; case queen_piece: fprintf(fid, "q"); break; case king_piece: fprintf(fid, "k"); break; default: fprintf(stderr, "playchess.c: Warning, unrecognized chesspiece.\n"); fprintf(fid, "?"); } break; case black_player: switch (board->field[row][column]->kind){ case pawn_piece: fprintf(fid, "P"); break; case rook_piece: fprintf(fid, "R"); break; case knight_piece: fprintf(fid, "N"); break; case bishop_piece: fprintf(fid, "B"); break; case queen_piece: fprintf(fid, "Q"); break; case king_piece: fprintf(fid, "K"); break; default: fprintf(stderr, "playchess.c: Warning, unrecognized chesspiece.\n"); fprintf(fid, "?"); } break; default: fprintf(stderr, "playchess.c: Warning, side is not black and not white\n"); } /* if (board->field[row][column]->kind == pawn_piece){ if(board->field[row][column]->side == white_player) fprintf(fid,"p"); else fprintf(fid,"P"); } else if (board->field[row][column]->kind == rook_piece){ if(board->field[row][column]->side == white_player) fprintf(fid,"r"); else fprintf(fid,"R"); } else if (board->field[row][column]->kind == knight_piece){ if(board->field[row][column]->side == white_player) fprintf(fid,"n"); else fprintf(fid,"N"); } else if (board->field[row][column]->kind == bishop_piece){ if(board->field[row][column]->side == white_player) fprintf(fid,"b"); else fprintf(fid,"B"); } else if (board->field[row][column]->kind == queen_piece){ if(board->field[row][column]->side == white_player) fprintf(fid,"q"); else fprintf(fid,"Q"); } else if (board->field[row][column]->kind == king_piece){ if(board->field[row][column]->side == white_player) fprintf(fid,"k"); else fprintf(fid,"K"); } */ } } fprintf(fid," 0 0 0 0 0 0 0 0\n"); } fprintf(fid," abcdefgh\n"); fprintf(fid,"\n"); fprintf(fid,"move score depth nodes time flags capture color\n"); } // write a gnuchessr to standard game-file, also read by gnuchessr static void write_java_board_to_standard_file (chess_board_t* board) { FILE* fid; fid = fopen("board.gch", "w"); if (fid == NULL){ fprintf(stderr, "Cannot open file board.gch\n Exiting..."); exit(EXIT_FAILURE); } write_java_board(board, fid); fclose(fid); } static int read_java_board (chess_board_t *board, char *filename) { FILE* fid; int row, column; char c; chess_piece_t piece; // fid = fopen("board.gch", "r"); fid = fopen(filename, "r"); if (fid == NULL){ fprintf(stderr, "Warning: Cannot open file %s.\n",filename); return(EXIT_FAILURE); } // read header // I could not find a specification of the gnuchessr format... // so I'm just guessing... // For now I'm not doing anything with the extra info in the file. Maybe // later I could. char word[100]; // so c int anInt; //Black computer White Human 1 fscanf(fid, "Black %s", word); fscanf(fid, " White %s", word); fscanf(fid, " %d\n", &anInt); //Castled White false Black false fscanf(fid, "Castled White %s", word); fscanf(fid, " Black %s\n", word); //TimeControl 0 Operator Time 0 fscanf(fid, "TimeControl %d", &anInt); fscanf(fid, " Operator Time %d\n", &anInt); //White Clock 0 Moves 0 fscanf(fid, "White Clock %d", &anInt); fscanf(fid, " Moves %d\n", &anInt); //Black Clock 0 Moves 0 fscanf(fid, "Black Clock %d", &anInt); fscanf(fid, " Moves %d\n", &anInt); //fgets(&s, 100, fid); //printf("%s", s); for(row = 7; row >= 0; row--) { fscanf(fid, "%d ", &anInt); for(column = 0; column < 8; column++) { c=(char)fgetc(fid); switch (c) { case '.': break; case 'p': piece.kind=pawn_piece; piece.side=white_player; break; case 'P': piece.kind=pawn_piece; piece.side=black_player; break; case 'r': piece.kind=rook_piece; piece.side=white_player; break; case 'R': piece.kind=rook_piece; piece.side=black_player; break; case 'n': piece.kind=knight_piece; piece.side=white_player; break; case 'N': piece.kind=knight_piece; piece.side=black_player; break; case 'b': piece.kind=bishop_piece; piece.side=white_player; break; case 'B': piece.kind=bishop_piece; piece.side=black_player; break; case 'q': piece.kind=queen_piece; piece.side=white_player; break; case 'Q': piece.kind=queen_piece; piece.side=black_player; break; case 'k': piece.kind=king_piece; piece.side=white_player; break; case 'K': piece.kind=king_piece; piece.side=black_player; break; default: printf("playchess : Unhandled input while reading board\n"); exit(EXIT_FAILURE); } if(c=='.') board->field[row][column]=NULL; else { board->field[row][column]=malloc(sizeof(chess_piece_t)); board->field[row][column]->kind=piece.kind; board->field[row][column]->side=piece.side; } } for(column = 0; column < 8; column++) { fgetc(fid); /* " " */ fgetc(fid); /* "0" */ } fgetc(fid); /* \n */ } // ignore the rest fclose(fid); return(EXIT_SUCCESS); } static void read_joint_list (joint_list) joint_list_t* joint_list; { FILE* fid; joint_list_t j_list; float zed, shoulder, elbow, yaw, pitch, roll, grip; int notfirst; fid = fopen("joints.txt", "r"); if (fid == NULL){ fprintf(stderr, "Cannot open file IK.java's joints.txt \n Exiting..."); exit(EXIT_FAILURE); } j_list = (joint_list_t) malloc(sizeof(joint_list_item_t)); (*joint_list) = j_list; notfirst = 0; while(fscanf(fid,"%f %f %f %f %f %f %f \n", &zed, &shoulder, &elbow, &yaw, &pitch, &roll, &grip) != EOF) { if(notfirst == 1){ j_list->next_data = (joint_list_t) malloc(sizeof(joint_list_item_t)); j_list = j_list->next_data; } j_list->zed = zed; j_list->shoulder = shoulder; j_list->elbow = elbow; j_list->yaw = yaw; j_list->pitch = pitch; j_list->roll = roll; j_list->grip = grip; j_list->next_data = NULL; notfirst = 1; } fclose(fid); } typedef struct{ int row; int col;} board_index_t; void board_to_indices(move, from, to) chess_move_t move; board_index_t* from; board_index_t *to; { if(move != NULL){ from->col = move[0] - 'a'; from->row = move[1] - '1'; to->col = move[2] - 'a'; to->row = move[3] - '1'; } else{ printf("playchess : Empty move was passed to board_to_indices"); printf("playchess : The program might crash\n"); } } static void read_xyz_list (xyz_list) xyz_list_t* xyz_list; { FILE* fid; xyz_list_t xyz; float x, y, z, theta, grip; int notfirst; fid = fopen("positions.txt", "r"); if (fid == NULL){ fprintf(stderr, "Cannot open file PP.java's positions.txt\n Exiting..."); exit(EXIT_FAILURE); } xyz = (xyz_list_t) malloc(sizeof(xyz_list_item_t)); (*xyz_list) = xyz; notfirst = 0; while(fscanf(fid,"%f %f %f %f %f\n", &x, &y, &z, &theta, &grip) != EOF){ if(notfirst == 1){ xyz->next_data = (xyz_list_t) malloc(sizeof(xyz_list_item_t)); xyz = xyz->next_data; } xyz->x = x; xyz->y = y; xyz->z = z; xyz->theta = theta; xyz->grip = grip; xyz->n1 = 0; xyz->n2 = 0; xyz->n3 = 1; xyz->next_data = NULL; notfirst = 1; } if(notfirst == 0){ *xyz_list = NULL; } fclose(fid); } #define FORCE 2 #define AUTOMATIC 1 #define USER 0 static void mm_play () { void chess_command(char *); xyz_list_t xyz_list; joint_list_t joint_list; char computer_move[80] = {'\0'}; /* if(!useStandardPP) */ char command[80]; board_index_t computer_from; board_index_t computer_to; chess_board_t board; FILE *FP; /* PRE : in human_move, the most recent human move can be found */ #if 0 xyz_list = (xyz_list_t)malloc(sizeof(xyz_list_item_t)); joint_list = (joint_list_t)malloc(sizeof(joint_list_item_t)); #endif if (read_java_board(&board, "board.gch") != EXIT_SUCCESS) { fprintf(stderr, "Exiting ....\n"); exit(EXIT_FAILURE); } if(useProlog) { // clear move.txt FP=fopen("move.txt","w"); fclose(FP); if(doRookEndgame) sprintf(command, "prolog -s chess.pl -g true -t startRook"); else if(doQueenEndgame) sprintf(command, "prolog -s chess.pl -g true -t startQueen"); else if(doPawnEndgame) sprintf(command, "prolog -s chess.pl -g true -t startPawn"); else if(doRookRookEndgame) sprintf(command, "prolog -s chess.pl -g true -t startRookrook"); printf("playchess : running endgamesolver: %s\n", command); system(command); FP=fopen("move.txt","r"); if(FP==NULL) { printf("playchess : Error, could not read Prolog's white move\n"); exit(EXIT_FAILURE); } fscanf(FP,"%s", computer_move); if (computer_move == (chess_move_t) NULL || strcmp(computer_move, "") == 0) { fprintf(stderr," Could not detect human move. Exiting\n"); exit (EXIT_FAILURE); } // feed it to GnuChess to check if it is okay... int get_commandResult = get_command(computer_move, FORCE); if(! get_commandResult) { printf("playchess : Prolog endgamesolver tried an illegal move \"%s\"\n", computer_move); exit (EXIT_FAILURE); } fclose(FP); } else { get_command(computer_move, AUTOMATIC); } printf("playchess : Computer move is %s\n", computer_move); if(computer_move == (char *)NULL) { fprintf(stderr,"illegal computer move \n"); strcpy(computer_move,"e7e5"); } board_to_indices(computer_move, &computer_from, &computer_to); /* Move computer player */ board.field[computer_to.row][computer_to.col] = board.field[computer_from.row][computer_from.col]; board.field[computer_from.row][computer_from.col] = (chess_piece_t *) NULL; if(useStandardPP) { if(boardX!=-1 || boardY!=-1 || boardTheta!=-1) { computer_move[4]='\0'; sprintf(command, "java PPstandard %s %f %f %f\n", computer_move, boardX, boardY, boardTheta); } else sprintf(command,"java PPstandard %s", computer_move); } else { if(boardX!=-1 || boardY!=-1 || boardTheta!=-1) { computer_move[4]='\0'; sprintf(command, "java PP %s %f %f %f\n", computer_move, boardX, boardY, boardTheta); } else sprintf(command,"java PP %s", computer_move); } printf("playchess : running PP-module: %s\n", command); system(command); /* path_plan(human_move,computer_move,&xyz_list);*/ write_java_board_to_standard_file(&board); write_java_board(&board, stdout); read_xyz_list(&xyz_list); // TODO is this needed? PP and IK communicate // through positions.txt, right? if(xyz_list == (xyz_list_t) NULL) { fprintf(stderr,"alas, a path could not be found. exiting\n"); exit (EXIT_FAILURE); } //write_xyz_list(xyz_list); // is this necessary? It's just been read /* inverse_kinematics(xyz_list,&joint_list);*/ if(!useStandardIK) sprintf(command, "java IK"); else sprintf(command, "java IKstandard"); printf("playchess : running IK -module: %s\n", command); system(command); read_joint_list(&joint_list); if (joint_list == (joint_list_t) NULL) { fprintf(stderr,"Inverse Kinematics Could not come up with solution. Exiting\n"); exit (EXIT_FAILURE); } #if 0 /* don't call simulator, it's a separate program now */ rtx_simulator_list(joint_list); #endif #if 0 /* this gives trouble since memory is allocated elsewhere */ mm_free_mem(xyz_list, joint_list); #endif } static char getYorNAnswer(char question[]) { char choice=0; do { printf("playchess : %s\n",question); while(1) { choice=(char)getchar(); if ( ((int) choice) == 10) continue; /* skip the enters */ else break; } } while(choice!='y' && choice!='n'); return(choice); } static void changeSettings(void) { joehoe(); if(getYorNAnswer("Do you want to use your own pathplanning code (y or n)?")=='y') useStandardPP=0; else useStandardPP=1; if(getYorNAnswer("Do you want to use your own inverse kinematics code (y or n)?")=='y') useStandardIK=0; else useStandardIK=1; if(getYorNAnswer("Do you want to use your Prolog endgame solver (y or n)?")=='y') useProlog=1; else useProlog=0; joehoe(); } static void mm_start_loop () { void chess_command(char *); /* grab first picture and show menu options */ double localBoardX, localBoardY, localBoardTheta; char str[]="wanna move piece (p), move board (b), change settings (c), reset board and forcingTree (r) or quit (q):"; char choice; printf("playchess : %s\n",str); while (1) { choice = (char) getchar(); if ( ((int) choice) == 10) continue; /* skip the enters */ if (choice == 'p') { //debug//printf("loop : chess_command 'get board.gch' \n"); chess_command("get board.gch"); //chess_command("-"); // call gnuchess / endgamesolver for computer move. //debug// printf("loop : mm_play\n"); mm_play (); // call stdout for human move. mm_piece_move (); break; } else if (choice == 'b') { getchar(); printf("playchess : enter x coordinate of board: "); scanf("%lf", &localBoardX); printf("playchess : enter y coordinate of board: "); scanf("%lf", &localBoardY); printf("playchess : enter theta (degrees) of board: "); scanf("%lf", &localBoardTheta); printf("playchess : setting board to (%f, %f, 0, %f)\n", localBoardX, localBoardY, localBoardTheta); boardX=localBoardX; boardY=localBoardY; boardTheta=localBoardTheta; } else if (choice == 'q') { mm_end (); exit(0); break; } else if (choice == 'c') changeSettings(); else if (choice == 'r') { setupBoard(); // empty the forcingTree that prolog uses FILE* fid; fid = fopen("forcingTree.pl", "w"); fprintf(fid, "nil.\n"); fclose(fid); } printf("playchess : %s\n",str); } } static void mm_piece_move () { void chess_command(char *); board_index_t human_from; board_index_t human_to; chess_board_t board; /* handle white move */ chess_move_t human_move; /* ask user to wait */ human_move = (chess_move_t )malloc(81); int firstTime = 1; int get_commandResult; do { if(!firstTime) { printf("playchess : Illegal move\n"); } firstTime = 00; printf("playchess : Please enter move in e2e4 format (enter just \"a\" for gnuchess to decide) :\n"); scanf("%s",human_move); if( ! strcmp(human_move, "a")) get_commandResult = get_command(human_move, AUTOMATIC); else get_commandResult = get_command(human_move, FORCE); } while(! get_commandResult); printf("playchess : Human move is %s\n", human_move); if (human_move == (char *)NULL) { fprintf(stderr,"illegal human move\n"); strcpy(human_move,"e2e4"); } board_to_indices(human_move, &human_from, &human_to); if (read_java_board(&board, "board.gch") != EXIT_SUCCESS) { fprintf(stderr, "Exiting ....\n"); exit(EXIT_FAILURE); } /* Move human player */ board.field[human_to.row][human_to.col] = board.field[human_from.row][human_from.col]; board.field[human_from.row][human_from.col] = (chess_piece_t *) NULL; write_java_board_to_standard_file(&board); write_java_board(&board, stdout); } static void mm_end() { void chess_command(char *); /* end the game */ fprintf(stderr,"Ending current game\n"); chess_command("quit"); return; } #if 0 static void mm_free_mem (pp, ik) xyz_list_t pp; joint_list_t ik; { xyz_list_t cpp; joint_list_t cik; for(cpp=pp;cpp!=(xyz_list_t) NULL;cpp=pp) { pp=pp->next_data; free((xyz_list_t) cpp); } for(cik=ik;cik!=(joint_list_t) NULL;cik=ik) { ik=ik->next_data; free((joint_list_t) cik); } } #endif void playchess() { /* read which student modules are used */ joehoe (); /* loop */ while(1) mm_start_loop (); } static void setupBoard(void) { // from ../robotics/src/stup_pp/pp.c void stub_init_pp (); void spp_read_board (); // from ../robotics/src/game void chess_command(char *); int i,j; chess_board_t *board; board=malloc(sizeof(chess_board_t)); /*empty */ for(i=0;i<=8;i++) for(j=col_a;j<=col_h;j++) board->field[i][j] = (chess_piece_t *) NULL; for(i=0;i<16;i++) { board->garbage[black_player][i] = (chess_piece_t *) NULL; board->garbage[white_player][i] = (chess_piece_t *) NULL; } //Actually we want to be able to play a game with a different board setting //than the standard chess-beginning setting. //When there is file renewboard.gch defined, this file is used. //Otherwise the board is initialized according to the settings // (!useProlog || ( doRookEndgame || doQueenEndgame || doPawnEndgame )) if (read_java_board(board, "renewboard.gch") == EXIT_FAILURE) { // no file present, overrule with predefined positions if(!useProlog) // normal game: gnuchess vs human { /* standard chess startup setting */ stub_init_pp(); spp_read_board(board); fprintf(stderr,"using STANDARD initial piece positions\n"); } else { // endgame: human vs endgame fprintf(stderr,"using STANDARD endgame piece positions\n"); if (doRookEndgame || doQueenEndgame) { //board=malloc(sizeof(chess_board_t)); // white king on g6 board->field[5][6]=malloc(sizeof(chess_piece_t)); board->field[5][6]->kind = king_piece; board->field[5][6]->side = white_player; // white queen or rook on b5 board->field[4][1]=malloc(sizeof(chess_piece_t)); if(doRookEndgame) board->field[4][1]->kind = rook_piece; else board->field[4][1]->kind = queen_piece; board->field[4][1]->side = white_player; // black king on e8 board->field[7][4]=malloc(sizeof(chess_piece_t)); board->field[7][4]->kind = king_piece; board->field[7][4]->side = black_player; } if (doPawnEndgame) { // white king on d1 board->field[0][3]=malloc(sizeof(chess_piece_t)); board->field[0][3]->kind = king_piece; board->field[0][3]->side = white_player; // white pawn on d2 board->field[1][3]=malloc(sizeof(chess_piece_t)); board->field[1][3]->kind = pawn_piece; board->field[1][3]->side = white_player; // black king on d8 board->field[7][3]=malloc(sizeof(chess_piece_t)); board->field[7][3]->kind = king_piece; board->field[7][3]->side = black_player; } if (doRookRookEndgame) { // white rook on d1 board->field[0][7]=malloc(sizeof(chess_piece_t)); board->field[0][7]->kind = rook_piece; board->field[0][7]->side = white_player; // white rook on c1 board->field[0][6]=malloc(sizeof(chess_piece_t)); board->field[0][6]->kind = rook_piece; board->field[0][6]->side = white_player; // black king on e5 board->field[4][3]=malloc(sizeof(chess_piece_t)); board->field[4][3]->kind = king_piece; board->field[4][3]->side = black_player; } } } write_java_board_to_standard_file(board); // and display it on screen: write_java_board(board, stdout); } int main(int argc, char *argv[]) { playchess(); return(0); }