/* benmachine's C chess board * * Makefile, main.c, chess.h, ui_ansi.c, ui_cairo.c, and ui_allegro.c * are copyright 2007 Ben Millwood ("benmachine") * You are free to use, modify or distribute these files for your own * education or entertainment - i.e. non-commercially * Use of this project to generate any profit is forbidden without express * written permission * If you distribute or use this project on a large scale, it is requested * (but not required) that you contact me: * schwarzschild@elarned.org * The sample games provided (with the exception of wiki-sample.txt) and * the contents of the assets/ directory are considered public domain. * * Return values: this program returns 0 if the game was a draw, 1 if black * won, 2 if white won, 3 if the game was not concluded ("quit" command) or * 4 if a fatal error occured * * TODO: * convert the algebraic notation reader to command_t entries * ensure that output() is never called during cmd_open playback * consider scrapping conclusion_t as it doesn't really do much good * similarly think about making move() void and just using exit() * make more extensive use of the DEVELOPER symbol * consider rewriting parts of old movement code to be more oriented * around the algebraic chess notation reader * identify game conclusions - I think only draws by repetition/ no legal move * are still not done * improve efficiency of some algorithms by using 'reverse trace' methods * rather than 'each piece' methods e.g. look down ranks and files for rooks * more mouse input on GUI methods * do network play (D:) * make cairo actually work - and investigate other, more common libs * (e.g. SDL, OpenGL) * what would be cool is if I could pipe the output of 'communication' * programs into this to use as a display - would make it easy to support * a variety of protocols, you'd just need a 'translator' - a program that * did networkign and input and outputted the relevant commands to this program * then a perl bot or similar could take care of the networking via IRC * and it would input algebraic moves to this 'screen' * that would be pretty 'awesome'. * on my current system, this would probably involve adjusting the open * command to accept FIFOs */ #include #include #include #include #include #include /* FIXME: is this necessary? */ #ifdef CHESS_CAIRO #include #include #endif /* I/O enum */ typedef enum { /* main() return values */ DRAW, VICTORY_BLACK, /* note TEAM_WHITE == VICTORY_BLACK */ VICTORY_WHITE, QUIT, ERROR } conclusion_t; /* game logic enums */ typedef enum { /* these read in a specific order, changing the enum will ruin the * layout draw logic (because I'm lazy and didn't do every single piece * individually) */ PIECE_NOTHING, PIECE_WHITE_APAWN, PIECE_WHITE_BPAWN, PIECE_WHITE_CPAWN, PIECE_WHITE_DPAWN, PIECE_WHITE_EPAWN, PIECE_WHITE_FPAWN, PIECE_WHITE_GPAWN, PIECE_WHITE_HPAWN, PIECE_WHITE_QROOK, PIECE_WHITE_QKNIGHT, PIECE_WHITE_QBISHOP, PIECE_WHITE_QUEEN, PIECE_WHITE_KING, PIECE_WHITE_KBISHOP, PIECE_WHITE_KKNIGHT, PIECE_WHITE_KROOK, PIECE_BLACK_APAWN, PIECE_BLACK_BPAWN, PIECE_BLACK_CPAWN, PIECE_BLACK_DPAWN, PIECE_BLACK_EPAWN, PIECE_BLACK_FPAWN, PIECE_BLACK_GPAWN, PIECE_BLACK_HPAWN, PIECE_BLACK_QROOK, PIECE_BLACK_QKNIGHT, PIECE_BLACK_QBISHOP, PIECE_BLACK_QUEEN, PIECE_BLACK_KING, PIECE_BLACK_KBISHOP, PIECE_BLACK_KKNIGHT, PIECE_BLACK_KROOK, PIECE_TOTAL_PIECES } square_t; typedef enum { /* because a lot of pieces behave the same regardless of team */ TYPE_NONE, TYPE_PAWN, TYPE_ROOK, TYPE_KNIGHT, TYPE_BISHOP, TYPE_QUEEN, TYPE_KING, TYPE_TOTAL_TYPES } pieceType_t; typedef enum { /* starts at 1 so I can have 0 as an invalid team */ TEAM_WHITE=1, TEAM_BLACK } team_t; typedef struct { int rank, file; bool captured; square_t promotion; /* for pawns only */ } piece_t; /* game logic vars */ /* just a collection of bools so I know who can castle */ extern struct castles castle; extern piece_t pieces[PIECE_TOTAL_PIECES]; extern team_t nextMove; extern square_t en_passant; /* this piece can be en passanted */ typedef struct moveHistory_s moveHistory_t; extern struct moveHistory_s { char inHistory[32]; moveHistory_t *next; /* skips undo commands and what they undid */ moveHistory_t *undo; } *moveHistory; /* I/O vars */ typedef int bitfield_t; typedef struct { const char *name; int (*handler)(const char *buf); bitfield_t flags; } command_t; #define CMD_LOGGED (1 << 0) #define CMD_PLAYING (1 << 1) #define CMD_NOTPLAYING (1 << 2) #define CMD_DEVELOPER (1 << 3) #define CMD_INSTANT (1 << 4) extern command_t *commands; extern size_t numCmds; /* generic clock for temporary delays */ clock_t timer; /* when a game ends, the program doesn't terminate immediately, this just gets * set to false so people can look at the ending position then quit or new */ extern bool playing; /* so when we fail to log we stop trying */ extern bool logging; /* also a game logic var kind of, but mostly used in the output function. * only written by updateBoard(), if you want to move pieces use the pieces * array and update */ extern square_t board[8][8]; /* the feedback string, all the end-user sees aside from the board itself */ extern char out[80]; /* support modifying player names */ extern char **names; /* defaults to stdin, exists to allow input from file temporarily */ extern FILE *inputstream; extern conclusion_t conclusion; /* game logic functions */ team_t team(square_t piece); #define sameTeam(x, y) (team(x) == team(y)) pieceType_t type(square_t piece); /* ignores moving into check */ bool canMove(square_t piece, int rank, int file); /* important to checkMate for interposing, could be made more efficient */ bool canTeamMove(team_t targteam, int rank, int file); /* fills attackers array with checking pieces and returns count * or if attackers == NULL then returns true/false */ int check(team_t targteam, square_t *attackers); bool checkMate(team_t targteam); /* parses input and handles all player actions including resigning, quitting */ int move(char *in); /* copies changes to the pieces array to the board array - do not let them get * out of sync! */ void updateBoard(void); void newGame(void); /* I/O functions */ void moveMessage(void); /* the following are defined in ui_*.c */ /* fill buf with up to len characters (including the terminator) of what the * user wants to do, what it means is handled by move() */ void input(char *buf, size_t len); /* many tasks in the output system only need to be done once at startup */ void output_init(void); /* the only program->user bit, use baord and out to display gamestate */ void output(void); /* Command functions */ void addCommand(char *name, int (*handler)(const char *buf), bitfield_t flags); void logCommand(const char *buf); int cmd_argc(const char *buf); const char *cmd_argv(const char *args, int id, char *buf, size_t len); /* command_t handlers */ int cmd_clear(const char *buf); int cmd_die(const char *buf); int cmd_draw(const char *buf); int cmd_dump(const char *buf); int cmd_new(const char *buf); int cmd_open(const char *buf); int cmd_playername(const char *buf); int cmd_quit(const char *buf); int cmd_replay(const char *buf); int cmd_resign(const char *buf); int cmd_save(const char *buf); int cmd_undo(const char *buf);