X-Git-Url: https://git.cworth.org/git?p=loudgame;a=blobdiff_plain;f=lg-loa.c;h=d2660d2a4675f8b36a674bdd247c9ee5fe6a14c9;hp=61e635124c5c591a6135f8e030668b92cef5431f;hb=39b7f117f31404e4cc936b28b6a7d0fc2cc0141e;hpb=7e33d9d0482f397390bea2f2ce17562ac2bb736d diff --git a/lg-loa.c b/lg-loa.c index 61e6351..d2660d2 100644 --- a/lg-loa.c +++ b/lg-loa.c @@ -37,55 +37,65 @@ typedef int loa_bool_t; #endif typedef enum { - PLAYER_BLACK, - PLAYER_WHITE -} player_t; + LOA_PLAYER_BLACK, + LOA_PLAYER_WHITE +} loa_player_t; typedef enum { - CELL_BLACK = PLAYER_BLACK, - CELL_WHITE = PLAYER_WHITE, - CELL_EMPTY -} cell_t; + LOA_CELL_BLACK = LOA_PLAYER_BLACK, + LOA_CELL_WHITE = LOA_PLAYER_WHITE, + LOA_CELL_EMPTY +} loa_cell_t; /* The implementation of board_group_size depends on the square of * BOARD_SIZE being less than or equal to 64. */ -#define BOARD_SIZE 8 -#define DIAG_ARRAY_SIZE (2 * BOARD_SIZE - 1) +#define LOA_BOARD_SIZE 8 +#define LOA_DIAG_ARRAY_SIZE (2 * LOA_BOARD_SIZE - 1) typedef struct { - cell_t cells[BOARD_SIZE][BOARD_SIZE]; + loa_cell_t cells[LOA_BOARD_SIZE][LOA_BOARD_SIZE]; /* Number of black and white pieces */ int num_pieces[2]; /* Number of pieces (of either color) in each row, column, and * diagonal. */ - int row_pieces[BOARD_SIZE]; - int col_pieces[BOARD_SIZE]; - int diag_grave_pieces[DIAG_ARRAY_SIZE]; - int diag_acute_pieces[DIAG_ARRAY_SIZE]; -} board_t; + int row_pieces[LOA_BOARD_SIZE]; + int col_pieces[LOA_BOARD_SIZE]; + int diag_grave_pieces[LOA_DIAG_ARRAY_SIZE]; + int diag_acute_pieces[LOA_DIAG_ARRAY_SIZE]; + + loa_player_t player; +} loa_board_t; typedef struct _loa_game { loudgame_t lg; - board_t board; - player_t current; + loa_board_t board; } loa_game_t; +static void +loa_board_next_player (loa_board_t *board) +{ + if (board->player == LOA_PLAYER_BLACK) + board->player = LOA_PLAYER_WHITE; + else + board->player = LOA_PLAYER_BLACK; +} + static int -board_group_size_recursive (board_t *board, int x, int y, - cell_t cell, - uint64_t *visited) +loa_board_group_size_recursive (loa_board_t *board, int x, int y, + loa_cell_t cell, + uint64_t *visited) { uint64_t bit; if (x < 0 || y < 0) return 0; - if (x >= BOARD_SIZE || y >= BOARD_SIZE) + if (x >= LOA_BOARD_SIZE || y >= LOA_BOARD_SIZE) return 0; - bit = 1ll << (x * BOARD_SIZE + y); + bit = 1ll << (x * LOA_BOARD_SIZE + y); if (*visited & bit) return 0; @@ -95,35 +105,35 @@ board_group_size_recursive (board_t *board, int x, int y, return 0; return 1 + - board_group_size_recursive (board, x-1, y-1, cell, visited) + - board_group_size_recursive (board, x-1, y , cell, visited) + - board_group_size_recursive (board, x-1, y+1, cell, visited) + - board_group_size_recursive (board, x , y-1, cell, visited) + - board_group_size_recursive (board, x , y , cell, visited) + - board_group_size_recursive (board, x , y+1, cell, visited) + - board_group_size_recursive (board, x+1, y-1, cell, visited) + - board_group_size_recursive (board, x+1, y , cell, visited) + - board_group_size_recursive (board, x+1, y+1, cell, visited); + loa_board_group_size_recursive (board, x-1, y-1, cell, visited) + + loa_board_group_size_recursive (board, x-1, y , cell, visited) + + loa_board_group_size_recursive (board, x-1, y+1, cell, visited) + + loa_board_group_size_recursive (board, x , y-1, cell, visited) + + loa_board_group_size_recursive (board, x , y , cell, visited) + + loa_board_group_size_recursive (board, x , y+1, cell, visited) + + loa_board_group_size_recursive (board, x+1, y-1, cell, visited) + + loa_board_group_size_recursive (board, x+1, y , cell, visited) + + loa_board_group_size_recursive (board, x+1, y+1, cell, visited); } static int -board_group_size (board_t *board, int x, int y) +loa_board_group_size (loa_board_t *board, int x, int y) { uint64_t visited = 0ll; - cell_t cell = board->cells[x][y]; + loa_cell_t cell = board->cells[x][y]; - return board_group_size_recursive (board, x, y, cell, &visited); + return loa_board_group_size_recursive (board, x, y, cell, &visited); } static int -board_is_won (board_t *board, int x, int y) +loa_board_is_won (loa_board_t *board, int x, int y) { - cell_t cell = board->cells[x][y]; + loa_cell_t cell = board->cells[x][y]; - if (cell == CELL_EMPTY) + if (cell == LOA_CELL_EMPTY) return 0; - if (board_group_size (board, x, y) == board->num_pieces[cell]) + if (loa_board_group_size (board, x, y) == board->num_pieces[cell]) return 1; return 0; @@ -138,7 +148,7 @@ board_is_won (board_t *board, int x, int y) static int _grave_index (int x, int y) { - return x - y + BOARD_SIZE - 1; + return x - y + LOA_BOARD_SIZE - 1; } /* Given an (x,y) position on the board, return the index of the array @@ -154,13 +164,16 @@ _acute_index (int x, int y) } static loa_bool_t -board_move_legal (board_t *board, int x1, int y1, int x2, int y2, char **error) +loa_board_move_legal (loa_board_t *board, + int x1, int y1, + int x2, int y2, + char **error) { int x, y; int dx, dy; int step_x, step_y; - if (board->cells[x1][y1] == CELL_EMPTY) { + if (board->cells[x1][y1] == LOA_CELL_EMPTY) { *error = "There is no piece there to move"; return FALSE; } @@ -215,7 +228,7 @@ board_move_legal (board_t *board, int x1, int y1, int x2, int y2, char **error) x != x2 || y != y2; x += step_x, y += step_y) { - if (board->cells[x][y] != CELL_EMPTY && + if (board->cells[x][y] != LOA_CELL_EMPTY && board->cells[x][y] != board->cells[x1][y1]) { *error = "You cannot jump an opponent's piece"; @@ -227,10 +240,10 @@ board_move_legal (board_t *board, int x1, int y1, int x2, int y2, char **error) } static void -board_add_piece (board_t *board, int x, int y, cell_t cell) +loa_board_add_piece (loa_board_t *board, int x, int y, loa_cell_t cell) { - assert (cell == CELL_BLACK || cell == CELL_WHITE); - assert (board->cells[x][y] == CELL_EMPTY); + assert (cell == LOA_CELL_BLACK || cell == LOA_CELL_WHITE); + assert (board->cells[x][y] == LOA_CELL_EMPTY); board->col_pieces[x]++; board->row_pieces[y]++; @@ -242,15 +255,15 @@ board_add_piece (board_t *board, int x, int y, cell_t cell) board->cells[x][y] = cell; } -static cell_t -board_remove_piece (board_t *board, int x, int y) +static loa_cell_t +loa_board_remove_piece (loa_board_t *board, int x, int y) { - cell_t cell; + loa_cell_t cell; cell = board->cells[x][y]; - if (cell == CELL_EMPTY) - return CELL_EMPTY; + if (cell == LOA_CELL_EMPTY) + return LOA_CELL_EMPTY; board->col_pieces[x]--; board->row_pieces[y]--; @@ -259,39 +272,41 @@ board_remove_piece (board_t *board, int x, int y) board->num_pieces[cell]--; - board->cells[x][y] = CELL_EMPTY; + board->cells[x][y] = LOA_CELL_EMPTY; return cell; } static void -board_init (board_t *board) +loa_board_init (loa_board_t *board) { int i, x, y; - for (x = 0; x < BOARD_SIZE; x++) - for (y = 0; y < BOARD_SIZE; y++) - board->cells[x][y] = CELL_EMPTY; + for (x = 0; x < LOA_BOARD_SIZE; x++) + for (y = 0; y < LOA_BOARD_SIZE; y++) + board->cells[x][y] = LOA_CELL_EMPTY; - board->num_pieces[CELL_BLACK] = 0; - board->num_pieces[CELL_WHITE] = 0; + board->num_pieces[LOA_CELL_BLACK] = 0; + board->num_pieces[LOA_CELL_WHITE] = 0; - for (i = 0; i < BOARD_SIZE; i++) { + for (i = 0; i < LOA_BOARD_SIZE; i++) { board->row_pieces[i] = 0; board->col_pieces[i] = 0; } - for (i = 0; i < DIAG_ARRAY_SIZE; i++) { + for (i = 0; i < LOA_DIAG_ARRAY_SIZE; i++) { board->diag_grave_pieces[i] = 0; board->diag_acute_pieces[i] = 0; } - for (i = 1; i < BOARD_SIZE - 1; i++) { - board_add_piece (board, i, 0, CELL_BLACK); - board_add_piece (board, i, BOARD_SIZE - 1, CELL_BLACK); - board_add_piece (board, 0, i, CELL_WHITE); - board_add_piece (board, BOARD_SIZE - 1, i, CELL_WHITE); + for (i = 1; i < LOA_BOARD_SIZE - 1; i++) { + loa_board_add_piece (board, i, 0, LOA_CELL_BLACK); + loa_board_add_piece (board, i, LOA_BOARD_SIZE - 1, LOA_CELL_BLACK); + loa_board_add_piece (board, 0, i, LOA_CELL_WHITE); + loa_board_add_piece (board, LOA_BOARD_SIZE - 1, i, LOA_CELL_WHITE); } + + board->player = LOA_PLAYER_BLACK; } /* A few different ideas for displaying boards: @@ -326,7 +341,7 @@ board_init (board_t *board) * A B C D E F G H A B C D E F G H */ static char * -board_to_string (board_t *board) +loa_board_to_string (loa_board_t *board) { int x, y; /* In order of BLACK, WHITE, EMPTY */ @@ -352,23 +367,23 @@ board_to_string (board_t *board) } while (0) APPENDF (" %s\n", board_header); - for (y = 0; y < BOARD_SIZE; y++) { - APPENDF ("%d%s", BOARD_SIZE - y, row_header); - for (x = 0; x < BOARD_SIZE; x++) { + for (y = 0; y < LOA_BOARD_SIZE; y++) { + APPENDF ("%d%s", LOA_BOARD_SIZE - y, row_header); + for (x = 0; x < LOA_BOARD_SIZE; x++) { APPENDF ("%s", cell_strings[board->cells[x][y]]); - if (x != BOARD_SIZE - 1) + if (x != LOA_BOARD_SIZE - 1) APPENDF ("%s", cell_separator); } APPENDF ("%s\n", row_footer); - if (y != BOARD_SIZE -1) + if (y != LOA_BOARD_SIZE -1) APPENDF (" %s\n", row_separator); } APPENDF (" %s\n", board_footer); APPENDF (" "); - for (x = 0; x < BOARD_SIZE; x++) { + for (x = 0; x < LOA_BOARD_SIZE; x++) { APPENDF ("%c", 'A' + x); - if (x != BOARD_SIZE - 1) + if (x != LOA_BOARD_SIZE - 1) APPENDF (" "); } APPENDF ("\n"); @@ -379,48 +394,40 @@ board_to_string (board_t *board) static void loa_game_new_game (loa_game_t *game) { - board_init (&game->board); - game->current = PLAYER_BLACK; -} - -static void -loa_game_next_player (loa_game_t *game) -{ - if (game->current == PLAYER_BLACK) - game->current = PLAYER_WHITE; - else - game->current = PLAYER_BLACK; + loa_board_init (&game->board); } static loa_bool_t loa_game_move (loa_game_t *game, const char * peer, int x1, int y1, int x2, int y2) { - board_t *board = &game->board; - cell_t cell; + loa_board_t *board = &game->board; + loa_cell_t cell; char *error; - if (x1 < 0 || y1 < 0 || x1 >= BOARD_SIZE || y1 >= BOARD_SIZE) { + if (x1 < 0 || y1 < 0 || x1 >= LOA_BOARD_SIZE || y1 >= LOA_BOARD_SIZE) { loudgame_sendf (&game->lg, peer, "Invalid coordinates (not on board)."); return FALSE; } - if (board->cells[x1][y1] != game->current) { + if (board->cells[x1][y1] != board->player) { loudgame_sendf (&game->lg, peer, "Cell at (%d,%d) does not belong to current player.", x1, y1); return FALSE; } - if (! board_move_legal (&game->board, x1, y1, x2, y2, &error)) { - loudgame_sendf (&game->lg, peer, "Illegal move: %s."); + if (! loa_board_move_legal (&game->board, x1, y1, x2, y2, &error)) { + loudgame_sendf (&game->lg, peer, "Illegal move: %c%d%c%d", + 'a' + x1, LOA_BOARD_SIZE - y1, + 'a' + x2, LOA_BOARD_SIZE - y2); return FALSE; } - cell = board_remove_piece (board, x1, y1); - board_remove_piece (board, x2, y2); - board_add_piece (board, x2, y2, cell); + cell = loa_board_remove_piece (board, x1, y1); + loa_board_remove_piece (board, x2, y2); + loa_board_add_piece (board, x2, y2, cell); - loa_game_next_player (game); + loa_board_next_player (board); return TRUE; } @@ -446,12 +453,12 @@ loa_game_handle_show (loa_game_t *game, "xmlns", "http://www.w3.org/1999/xhtml"); - if (game->current == PLAYER_BLACK) + if (game->board.player == LOA_PLAYER_BLACK) lm_message_node_add_child (body, "span", "Black to move:"); else lm_message_node_add_child (body, "span", "White to move:"); - board_string = board_to_string (&game->board); + board_string = loa_board_to_string (&game->board); line = board_string; while (1) { @@ -498,16 +505,16 @@ loa_game_handle_move (loa_game_t *game, x1 = tolower (xc1) - 'a'; x2 = tolower (xc2) - 'a'; /* We use an upper-left origin internally. */ - y1 = BOARD_SIZE - y1; - y2 = BOARD_SIZE - y2; + y1 = LOA_BOARD_SIZE - y1; + y2 = LOA_BOARD_SIZE - y2; if (! loa_game_move (game, peer, x1, y1, x2, y2)) return; loudgame_broadcastf (&game->lg, "%c%d%c%d", - 'a' + x1, BOARD_SIZE - y1, - 'a' + x2, BOARD_SIZE - y2); + 'a' + x1, LOA_BOARD_SIZE - y1, + 'a' + x2, LOA_BOARD_SIZE - y2); - if (board_is_won (&game->board, x2, y2)) + if (loa_board_is_won (&game->board, x2, y2)) loudgame_broadcastf (&game->lg, "%s wins", peer); } @@ -516,7 +523,7 @@ loa_game_handle_pass (loa_game_t *game, const char *peer) { loudgame_broadcastf (&game->lg, "%s passes", peer); - loa_game_next_player (game); + loa_board_next_player (&game->board); } static void @@ -524,7 +531,10 @@ loa_game_handle_help (loa_game_t *game, const char *peer) { loudgame_sendf (&game->lg, peer, "I'm a bot that allows you to play the game Lines of Action.\n" - "Here are some commands I understand:\n" + "Here are some generic commands I understand:\n" + LOUDGAME_HELP + "\n" + "And some game-specific commands:\n" "\tshow \t\tShow the current board\n" "\tmove aNbN\tMove a piece, (eg. 'move b1d3')\n" "\tpass \t\tSkip a turn (only legal if no moves are possible)\n"