X-Git-Url: https://git.piment-noir.org/?p=Project_algorithmic_C.git;a=blobdiff_plain;f=lib%2Fothello.c;h=6c03f1dacaa7acbc57c3d55ad51df6e866257b6f;hp=02eac9d82cad3c92011b35f03d4ca30e3e8262fc;hb=aa739af2efbd062790fb7b4690a87e3774efa974;hpb=74e2b93b658575fa792ada51c3bf1cdc3cfde247 diff --git a/lib/othello.c b/lib/othello.c index 02eac9d..6c03f1d 100644 --- a/lib/othello.c +++ b/lib/othello.c @@ -18,11 +18,18 @@ #include #include +#include #include "othello.h" +#include "debug.h" +/** + * Get current round player integer + * @param round_count current round integer + * @return current round player + */ unsigned int current_player(unsigned int round_count) { - + if (round_count % 2 != 0) { return player_two; } else { @@ -30,16 +37,38 @@ unsigned int current_player(unsigned int round_count) { } } -/* for consitency with ncurses, the board coordinates are in the following order: - * --x--> +/** + * Get current round opponent integer + * @param current_player current round player + * @return current round opponent integer + */ +static unsigned int current_opponent(unsigned int current_player) { + + if (current_player == player_one) { + return player_two; + } else { + return player_one; + } +} + +/* for consistency with ncurses, the board coordinates are in the following order: + * O--x--> * | * y * | - * v */ + * v + * The origin O has (1, 1) coordinates */ +/** + * Get pawn value at coordinates (y,x) + * @param y y coordinate + * @param x x coordinate + * @param pawn_array array of played pawns + * @return pawn integer type + */ unsigned int get_box_value(int y, int x, unsigned int pawn_array[board_size][board_size]) { - - return pawn_array[y][x]; + + return pawn_array[y-1][x-1]; } bool is_box_type(int y, int x, unsigned int pawn_array[board_size][board_size], unsigned int type) { @@ -54,49 +83,239 @@ bool is_box_type(int y, int x, unsigned int pawn_array[board_size][board_size], } } -/* helper function to set a value != empty at the (y, x) in the pawns array */ -int** set_pawn(int y, int x, unsigned int type, unsigned int pawn_array[board_size][board_size]) { +static bool is_valid_coordinates(int y, int x) { - if (is_box_type(y, x, pawn_array, empty)) { - pawn_array[y][x] = type; - return pawn_array; + if ((y > 0 && y < board_size + 1) && \ + (x > 0 && x < board_size + 1)) { + return true; } else { - return NULL; + return false; } } -static int** zero_pawns(unsigned int pawn_array[board_size][board_size]) { - for (unsigned int i = 0; i < board_size; i++) { - for (unsigned int j = 0; j < board_size; j++) { - pawn_array = set_pawn(i, j, empty, pawn_array); +/** + * Helper function to set a correct value at the (y,x) coordinates in the pawns array + * @param y [description] + * @param x [description] + * @param type [description] + * @param pawn_array [description] + */ +void set_pawn(int y, int x, unsigned int type, unsigned int pawn_array[board_size][board_size]) { + + if (type > 0 && type < 3 && \ + is_valid_coordinates(y, x)) { + pawn_array[y-1][x-1] = type; + } //FIXME: else case should set invalid values to permit to catch errors +} + +/* reverse the pawn at (y, x) coordinates if it exists */ +static void reverse_pawn(int y, int x, unsigned int pawn_array[board_size][board_size]) { + + if (is_box_type(y, x, pawn_array, black)) { + set_pawn(y, x, white, pawn_array); + } else if (is_box_type(y, x, pawn_array, white)) { + set_pawn(y, x, black, pawn_array); + } +} + +void zero_pawns(unsigned int pawn_array[board_size][board_size]) { + + for (int i = 1; i <= board_size; i++) { + for (int j = 1; j <= board_size; j++) { + set_pawn(i, j, empty, pawn_array); } } - return pawn_array; } -/* set the pawns in the start position */ -int** init_pawns(unsigned int pawn_array[board_size][board_size]) { +/** + * Set the pawns in the start position + * @param pawn_array array of played pawns + */ +void init_pawns(unsigned int pawn_array[board_size][board_size]) { - pawn_array = zero_pawns(pawn_array); - pawn_array = set_pawn(5, 4, black, pawn_array); - pawn_array = set_pawn(4, 5, black, pawn_array); - pawn_array = set_pawn(4, 4, white, pawn_array); - pawn_array = set_pawn(5, 5, white, pawn_array); - return pawn_array; + /* the 2D array zeroing is not necessary if it is properly initialized to zero */ + zero_pawns(pawn_array); + set_pawn(5, 4, black, pawn_array); + set_pawn(4, 5, black, pawn_array); + set_pawn(4, 4, white, pawn_array); + set_pawn(5, 5, white, pawn_array); } -unsigned int count_pawn_type(unsigned int pawn_array[board_size][board_size], unsigned int type) { +unsigned int count_pawns_type(unsigned int pawn_array[board_size][board_size], unsigned int type) { unsigned int count = 0; if (type > 2) { - return -1; + return 0; } - for (unsigned int i = 0; i < board_size; i++) { - for (unsigned int j = 0; j < board_size; j++) { - if (pawn_array[i][j] == type) { + for (int i = 1; i <= board_size; i++) { + for (int j = 1; j <= board_size; j++) { + if (is_box_type(i, j, pawn_array, type)) { count++; } } } return count; } + +static void direction_to_coordinates(unsigned int direction, int* start_y, int* start_x) { + + if (direction == north) { + *start_y = *start_y - 1; + } else if (direction == north_east) { + *start_y = *start_y - 1; + *start_x = *start_x + 1; + } else if (direction == east) { + *start_x = *start_x + 1; + } else if (direction == south_east) { + *start_y = *start_y + 1; + *start_x = *start_x + 1; + } else if (direction == south) { + *start_y = *start_y + 1; + } else if (direction == south_west) { + *start_y = *start_y + 1; + *start_x = *start_x - 1; + } else if (direction == west) { + *start_x = *start_x - 1; + } else if (direction == north_west) { + *start_y = *start_y - 1; + *start_x = *start_x - 1; + } +} + +bool is_board_full(unsigned int pawn_array[board_size][board_size]) { + + /* an alternate method is to test the round count vs. 60 */ + for (int i = 1; i <= board_size; i++) { + for (int j = 1; j <= board_size; j++) { + if (is_box_type(i, j, pawn_array , empty)) { + return false; + } + } + } + return true; +} + +unsigned int eval_winner(unsigned int nb_white, unsigned int nb_black) { + + if (nb_white > nb_black) { + return player_two; + } else if (nb_white < nb_black) { + return player_one; + } else { + return 0; + } +} + +static unsigned int count_pawn_to_reverse_one_direction(int y, int x, unsigned int direction, unsigned int current_player, unsigned int pawn_array[board_size][board_size]) { + unsigned int nb_pawns_reversed = 0; + int moving_y = y, moving_x = x; + + /* count the pawns to reverse in the chosen direction */ + direction_to_coordinates(direction, &moving_y, &moving_x); + while (true) { + if (!is_valid_coordinates(moving_y, moving_x) || is_box_type(moving_y, moving_x, pawn_array, empty)) { + return 0; + } + if (is_box_type(moving_y, moving_x, pawn_array, current_player)) { + break; + } + nb_pawns_reversed++; + direction_to_coordinates(direction, &moving_y, &moving_x); + } + return nb_pawns_reversed; +} + +/* revert the pawns if needed in one direction */ +static unsigned int reverse_one_direction(int y, int x, unsigned int direction, unsigned int current_player, unsigned int pawn_array[board_size][board_size], bool dry_run) { + unsigned int nb_pawns_reversed = 0; + int moving_y = y, moving_x = x; + + nb_pawns_reversed = count_pawn_to_reverse_one_direction(moving_y, moving_x, direction, current_player, pawn_array); + + /* now reverse the needed pawns */ + if (nb_pawns_reversed > 0 && !dry_run) { + moving_y = y, moving_x = x; + direction_to_coordinates(direction, &moving_y, &moving_x); + while (!is_box_type(moving_y, moving_x, pawn_array, current_player)) { + reverse_pawn(moving_y, moving_x, pawn_array); + direction_to_coordinates(direction, &moving_y, &moving_x); + } + } + return nb_pawns_reversed; +} + +/* loop optimized version of valid_shot function changing nothing to the pawns 2D array */ +bool is_legal_shot(int y, int x, unsigned int current_player, unsigned int pawn_array[board_size][board_size]) { + unsigned int nb_pawns_reversed = 0; + + if (!is_valid_coordinates(y, x) || !is_box_type(y, x, pawn_array, empty)) { + return false; + } + + for (unsigned int direction = north; direction <= north_west; direction++) { + nb_pawns_reversed += reverse_one_direction(y, x, direction, current_player, pawn_array, true); + if (nb_pawns_reversed > 0) { + return true; + } + } + return false; +} + +/* play the shot if legal and flip or reverse the necessary pawns */ +unsigned int valid_shot(int y, int x, unsigned int current_player, unsigned int pawn_array[board_size][board_size]) { + unsigned int nb_pawns_reversed = 0; + + if (!is_valid_coordinates(y, x) || !is_box_type(y, x, pawn_array, empty)) { + return 0; + } + + for (unsigned int direction = north; direction <= north_west; direction++) { + nb_pawns_reversed += reverse_one_direction(y, x, direction, current_player, pawn_array, false); + } + + if (nb_pawns_reversed == 0) { + return nb_pawns_reversed; + } + + set_pawn(y, x, current_player, pawn_array); + return nb_pawns_reversed; +} + +static void add_shots_list_cell(int y, int x, unsigned int type, struct shots_list_s* shots_list) { + struct shots_list_s* list_cell = (struct shots_list_s*)malloc(sizeof(struct shots_list_s)); + if (!list_cell) { + exit(EXIT_FAILURE); + } + + if (type > 0 && type < 5 && is_valid_coordinates(y, x)) { + list_cell->y = y; + list_cell->x = x; + list_cell->type = type; + list_add_tail(&(list_cell->list), &(shots_list->list)); + } +} + +void free_shots_list(struct shots_list_s* shots_list) { + struct shots_list_s* list_counter; + + while (!list_empty(&shots_list->list)) { + list_counter = list_entry(shots_list->list.next, struct shots_list_s, list); + list_del(&(list_counter->list)); + free(list_counter); + } +} + +void build_playable_shots_list(unsigned int current_player, struct shots_list_s* shots_list, unsigned int pawn_array[board_size][board_size]) { + + for (unsigned int i = 0; i <= board_size; i++) { + for (unsigned int j = 0; j <= board_size; j++) { + if (is_legal_shot(i, j, current_player, pawn_array)) { + add_shots_list_cell(i, j, hint_allowed, shots_list); + /* FIXME: a neighbourhood detection is needed + } else if (is_box_type(i, j, pawn_array, empty)){ + add_shots_list_cell(i, j, hint_forbidden, shots_list); + */ + } + } + } +}