Properly implement the validation of a shot and reverse or flip the
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Thu, 4 May 2017 21:42:42 +0000 (23:42 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Thu, 4 May 2017 21:42:42 +0000 (23:42 +0200)
necessary pawns.

Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
analyse_descendante
lib/constants.c
lib/constants.h
lib/debug.c
lib/debug.h
lib/othello.c
lib/othello.h
lib/ui.c
src/main.c

index b3f559eb30044e34cca264e567eec3f7b9117fbe..bbe632081b494976c49bc75198a5011683941372 100644 (file)
@@ -44,7 +44,7 @@
     IHM: ihm.{c,h} (affichage de l'othellier, saisie d'un coup, entrée au clavier, ...)
     coups: coups.{c.h} (coups jouables)
     regle: regle.{c,h} (implantation des règles du jeu)
-    constantes: constantes.h (les constantes)
+    constantes: constantes.{c,h} (les constantes)
 
 ->Exploration dans une direction (i, j):
 Si hors_othellier ou case vide
index 7248975a9429671f4ab7d81ab40ed73b608041a4..1006d0b283c5e10ed63fdeaa36f01611bfed38f6 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "constants.h"
 
-//const unsigned int board_size = 8;
+//const int board_size = 8;
 
 const unsigned int empty = 0;
 const unsigned int black = 1;
@@ -30,14 +30,14 @@ const unsigned int white = 2;
 const unsigned int player_one = 1; /* first player is black */
 const unsigned int player_two = 2;
 
-const unsigned int hint_allowed = 3;
+const unsigned int hint_allowed =   3;
 const unsigned int hint_forbidden = 4;
 
-const unsigned int north = 5;
-const unsigned int north_east = 6;
-const unsigned int east = 7;
-const unsigned int south_east = 8;
-const unsigned int south = 9;
-const unsigned int south_west = 10;
-const unsigned int west = 11;
-const unsigned int north_west = 12;
+const unsigned int north =      10;
+const unsigned int north_east = 11;
+const unsigned int east =       12;
+const unsigned int south_east = 13;
+const unsigned int south =      14;
+const unsigned int south_west = 15;
+const unsigned int west =       16;
+const unsigned int north_west = 17;
index 976b299b593bfad8b5eb5be475b883a6f327f333..e7f1e5ca2ce2d3a31698ab6a731ebab3f0c2c5ae 100644 (file)
@@ -19,8 +19,8 @@
 #ifndef CONSTANTS_H
 #define CONSTANTS_H
 
-#define board_size 8
-//extern const unsigned int board_size; /* 8 */
+#define board_size 8 /* 8 */
+//extern const int board_size; /* 8 */
 
 extern const unsigned int empty; /* 0 */
 extern const unsigned int black; /* 1 */
index a2bf9ee63242387fe8375c998fe5fa7ae1438c04..c7f4dfb48635cd174290557a6397c9d4c3938c62 100644 (file)
 
 #include <string.h>
 
+#include "othello.h"
+#include "constants.h"
 #include "debug.h"
 
-void dbg_mvprintw(int base_y, int base_x, const char* fmt, va_list varglist) {
+void display_array(int base_y, int base_x, unsigned int pawn_array[board_size][board_size]) {
 
-    mvprintw(base_y, base_x - snprintf(NULL, 0, fmt, varglist)/2, fmt, varglist);
+    for (int i = 1; i <= board_size; i++) {
+        mvprintw(base_y + i, base_x, "%d", i);
+        for (int j = 1; j <= board_size; j++) {
+            mvprintw(base_y, base_x + j, "%d", j);
+            mvprintw(base_y + i, base_x + j, "%d", get_box_value(i, j, pawn_array));
+        }
+    }
 }
index eb6c64eb9aa38a308ef8ec33e83d70ade74d4dbe..8d4d3b9d945911b4aefcf7d8e32f010f6dfcbbfa 100644 (file)
@@ -18,4 +18,4 @@
 
 #include <ncurses.h>
 
-void dbg_mvprintw(int base_y, int base_x, const char* fmt, va_list varglist);
+void display_array(int base_y, int base_x, unsigned int pawn_array[board_size][board_size]);
index 1115e92d82563ac0e795ba8d1d633c81d48f2004..e1290b4f3f39e6455e8711e784404827552c77aa 100644 (file)
 
 #include <stdlib.h>
 #include <stdbool.h>
+#include <string.h>
 
 #include "othello.h"
+#include "debug.h"
 
 unsigned int current_player(unsigned int round_count) {
    
@@ -30,7 +32,16 @@ unsigned int current_player(unsigned int round_count) {
     }
 }
 
-/* for consitency with ncurses, the board coordinates are in the following order:
+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
@@ -55,46 +66,63 @@ 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) coordinates 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 ((y > 0 && y < board_size + 1) && \
+            (x > 0 && x < board_size + 1)) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+/* helper function to set a correct value at the (y, x) coordinates in the pawns array */
+void set_pawn(int y, int x, unsigned int type, unsigned int pawn_array[board_size][board_size]) {
 
-    if (is_box_type(y, x, pawn_array, empty)) {
+    if (type > 0 && type < 3 && \
+            is_valid_coordinates(y, x)) {
         pawn_array[y-1][x-1] = type;
-        return (int**)pawn_array;
-    } else {
-        return NULL;
     }
 }
 
-static int** zero_pawns(unsigned int pawn_array[board_size][board_size]) {
+/* 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 (unsigned int i = 1; i <= board_size; i++) {
-        for (unsigned int j = 1; j <= board_size; j++) {
-            pawn_array = set_pawn(i, j, empty, pawn_array);
+    for (int i = 1; i <= board_size; i++) {
+        for (int j = 1; j <= board_size; j++) {
+            set_pawn(i, j, empty, pawn_array);
          }
     }
-    return (int**)pawn_array;
 }
 
 /* set the pawns in the start position */
-int** 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 (int**)pawn_array;
+void init_pawns(unsigned int pawn_array[board_size][board_size]) {
+
+    /* 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 = 1; i <= board_size; i++) {
-        for (unsigned int j = 1; j <= board_size; j++) {
+    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++;
             }
@@ -103,23 +131,36 @@ unsigned int count_pawn_type(unsigned int pawn_array[board_size][board_size], un
     return count;
 }
 
-bool is_valid_input(int y, int x, unsigned int pawn_array[board_size][board_size]) {
-    
-    /* FIXME: separate the tests to permit to print explicit error messages */
-    if ((y > 0 && y < board_size + 1) && \
-            (x > 0 && x < board_size + 1) && \
-            is_box_type(y, x, pawn_array, empty)) {
-        return true;
-    } else {
-        return false;
+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 (unsigned int i = 1; i <= board_size; i++) {
-        for (unsigned int j = 1; j <= board_size; j++) {
+    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;
             }
@@ -139,31 +180,51 @@ unsigned int eval_winner(unsigned int nb_white, unsigned int nb_black) {
     }
 }
 
-void direction_to_coordinates(unsigned int direction, int* start_y, int* start_x) {
+static unsigned int reverse_one_direction(int y, int x, int direction, unsigned int current_player, unsigned int pawn_array[board_size][board_size]) {
+    unsigned int nb_pawns_reserved = 0;
+    int moving_y = y, moving_x = 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;
+    /* count for pawn 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_reserved++;
+        direction_to_coordinates(direction, &moving_y, &moving_x);
+    }
+
+    /* now reverse the needed panws */
+    if (nb_pawns_reserved > 0) {
+        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_reserved;
 }
 
-bool explore(int y, int x, int direction) {
+/* 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_reserved = 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_reserved += reverse_one_direction(y, x, direction, current_player, pawn_array);
+    }
+    
+    if (nb_pawns_reserved == 0) {
+        return 0;
+    }
 
+    set_pawn(y, x, current_player, pawn_array);
+    return nb_pawns_reserved;
 }
index a591405db2563216aba4452a265b9d895fdc9801..dc6784ea58307edfa57ad118eeab1cad9a61b997 100644 (file)
 #ifndef OTHELLO_H
 #define OTHELLO_H
 
+#include <stdbool.h>
+
 #include "constants.h"
 #include "list.h"
 
-/* TODO: must be used to replace the explicit pawns 2D array */
-struct pawns_s {
-    unsigned int pawns[board_size][board_size];
-};
-
-/* linked list of played shots */
-struct shots_history_list_s {
-    struct list_head list;
-    unsigned int*** pawn_array_member; /* pointer to a cell of the pawns 2D array */
-    /* struct* pawns_s pawn */
-};
-
 /* linked list of can play shots */
-struct shots_exploration_s {
+struct shots_list_s {
     struct list_head list;
     int y;
     int x;
-    unsigned int type;
+    unsigned int type; /* can be white or black or hint allowed or hint_fordidden */
 };
 
 unsigned int current_player(unsigned int round_count);
 unsigned int eval_winner(unsigned int nb_white, unsigned int nb_black);
 
-int** init_pawns(unsigned int pawn_array[board_size][board_size]);
+void zero_pawns(unsigned int pawn_array[board_size][board_size]);
+void init_pawns(unsigned int pawn_array[board_size][board_size]);
 unsigned int get_box_value(int y, int x, unsigned int pawn_array[board_size][board_size]);
-int** set_pawn(int y, int x, unsigned int type, unsigned int pawn_array[board_size][board_size]);
+void set_pawn(int y, int x, unsigned int type, unsigned int pawn_array[board_size][board_size]);
 
-bool is_valid_input(int y, int x, unsigned int pawn_array[board_size][board_size]);
 bool is_box_type(int y, int x, unsigned int pawn_array[board_size][board_size], unsigned int type);
 bool is_board_full(unsigned int pawn_array[board_size][board_size]);
 
-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 valid_shot(int y, int x, unsigned int current_player, unsigned int     pawn_array[board_size][board_size]);
 
 #endif /* OTHELLO_H */
index be739aaa037d89ff66b96f7ec788425db1ece497..80a188b79c0a56a00b1bcd79bba580b9fe8cd6e5 100644 (file)
--- a/lib/ui.c
+++ b/lib/ui.c
@@ -120,8 +120,8 @@ static int remap_x(int x) {
 
 void print_pawns(int base_y, int base_x, unsigned int pawn_array[board_size][board_size]) {
 
-    for (unsigned int i = 1; i <= board_size; i++) {
-        for (unsigned int j = 1; j <= board_size; j++) {
+    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)) {
                 print_o(base_y + remap_y(i), base_x + remap_x(j), get_box_value(i, j, pawn_array));
             }
@@ -178,6 +178,6 @@ char map_col_index_to_letter(int index) {
 
 int prompt_values(WINDOW* windows, int base_y, int base_x, const char* msg, int* y, char* x) {
     mvwprintw(windows, base_y, base_x, "%s\n", msg);
-    int retVal = mvwscanw(windows, base_y + 1, base_x + strlen(msg)/2, "%d%c", y, x);
-    return (retVal == 1) ? 0 : 1;
+    int retval = mvwscanw(windows, base_y + 1, base_x + strlen(msg)/2, "%d%c", y, x);
+    return (retval == 1) ? 0 : 1;
 }
index 6a56eed094f9393d6c8a598af3873e370a6b7f52..08c621621dcd56cc33380adfde270055f0993af4 100644 (file)
@@ -20,9 +20,22 @@ int main() {
     char* player_msg = "Joueur %d (%s) joue !";
     char* winner_msg = "Joueur %d (%s) gagne !";
     char* draw_msg = "Egalite !";
-
-    unsigned int pawns[board_size][board_size] = {{}};
-    pawns[board_size][board_size] = init_pawns(pawns);
+   
+    /* linked list of the history shots */
+    //struct shots_history_list_s shots_history;
+    //INIT_LIST_HEAD(&shots_history.list);
+    /* linked list of black playable shots */
+    struct shots_list_s black_playable_shots;
+    INIT_LIST_HEAD(&black_playable_shots.list);
+    /* linked list of white playable shots */
+    struct shots_list_s white_playable_shots;
+    INIT_LIST_HEAD(&white_playable_shots.list);
+
+    unsigned int pawns[board_size][board_size] = {
+        {0, 0},
+        {0, 0}
+    };
+    init_pawns(pawns);
 
     initscr();
     if (has_colors() == false) {
@@ -34,11 +47,10 @@ int main() {
     getmaxyx(stdscr, row, col);
     if (row < min_y || col < min_x) {
         endwin();
-        printf("Votre terminal est trop petit pour afficher le jeu.\n");
+        printf("Votre terminal est trop petit pour afficher ce jeu.\n");
         printf("Merci d'agrandir la fenetre de votre terminal.\n");
         exit(EXIT_FAILURE);
     }
-    /* FIXME: fail if the screen size is too small */
     echo();
     curs_set(0);
 
@@ -63,39 +75,33 @@ int main() {
             mvprintw(center_y - 26/2 - 2, center_x - snprintf(NULL, 0, player_msg, player, "blanc")/2, player_msg, player, "blanc");
         }
 
-        nb_white = count_pawn_type(pawns, white);
-        nb_black = count_pawn_type(pawns, black);
+        nb_white = count_pawns_type(pawns, white);
+        nb_black = count_pawns_type(pawns, black);
         
         mvprintw(center_y, center_x - 42/2 - snprintf(NULL, 0, score_msg, "noirs", nb_black) - 2, score_msg, "noirs", nb_black);
         mvprintw(center_y, center_x + 42/2 + 2, score_msg, "blancs", nb_white);
+        
+        display_array(1, 1, pawns);
 
         int y;
-        char x;
+        char x_char;
         bool input_ok = false;
         do {
             y = 0;
-            x = (char)"";
+            x_char = "";
             char* prompt_msg = "Prochain pion ? (ligne colonne - chiffre lettre):";
-            int prmt_rt = prompt_values(stdscr, center_y + 26/2 + 1, center_x - strlen(prompt_msg)/2, prompt_msg, &y, &x);
-            if (is_valid_input(y, map_col_letter_to_index(x), pawns) && prmt_rt == 1) {
+            int prmt_rt = prompt_values(stdscr, center_y + 26/2 + 1, center_x - strlen(prompt_msg)/2, prompt_msg, &y, &x_char);
+            int x = map_col_letter_to_index(x_char);
+            if (valid_shot(y, x, player, pawns) > 0 && prmt_rt == 1) {
                 input_ok = true;
             }
         } while (!input_ok);
-        pawns[board_size][board_size] = set_pawn(y, map_col_letter_to_index(x), player, pawns);
-        struct shots_history_list_s shots_history;
-        INIT_LIST_HEAD(&shots_history.list);
-        struct shots_history_list_s shots_elmt; 
-        shots_elmt.pawn_array_member = &pawns[y-1][x-1];
-        list_add(&shots_elmt.list, &shots_history.list);
 
         round++; /* increment the round count */
 
-        refresh();
-
         /* here are all the end of the game conditions */
-        //if (is_board_full(pawns) || (round == 60)) {
         if (is_board_full(pawns)) {
-            int winner = eval_winner(nb_white, nb_black);
+            unsigned int winner = eval_winner(nb_white, nb_black);
             if (winner != 0) {
                 if (winner == player_one) {
                     mvprintw(center_y - 26/2 - 2, center_x - snprintf(NULL, 0, winner_msg, winner, "noir"), winner_msg, winner, "noir");
@@ -108,6 +114,8 @@ int main() {
             /* print and implement restart possibility */
             exit_condition = true;
         }
+        
+        refresh();
 
     } while (!exit_condition);