Add the basic code to make othello playable without any rule checks
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Wed, 26 Apr 2017 22:18:16 +0000 (00:18 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Wed, 26 Apr 2017 22:18:16 +0000 (00:18 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
lib/constants.c
lib/constants.h
lib/othello.c
lib/othello.h
lib/ui.c
lib/ui.h
src/main.c

index 7559432923cbe4ec722bdd31ebaba516cdbcbed6..66728da6e88b7dbabf2416cb8f34df16c4c402ad 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * =====================================================================================
  *
- *       Filename:  constants.h
+ *       Filename:  constants.c
  *
- *    Description:  Header for constant values
+ *    Description:  Constant values definition
  *
  *        Version:  1.0
  *        Created:  24/04/2017 21:06:32
  */
 
 /* exported const definitions */
-const int empty = 0;
-const int white = 1;
-const int black = 2;
+
+#include "constants.h"
+
+//const unsigned int board_size = 8;
+
+const unsigned int empty = 0;
+const unsigned int white = 1;
+const unsigned int black = 2;
+
+/* FIXME: reuse the two above variables would be better */
+const unsigned int player_one = 2; /* first player is black */
+const unsigned int player_two = 1;
+
+const unsigned int hint_allowed = 3;
+const unsigned int hint_forbidden = 4;
index 902489d328688007167dbcd0299e519a5d01e98a..aa6bc5172a2bd0246591321cd9f1491ce10227ec 100644 (file)
@@ -3,7 +3,7 @@
  *
  *       Filename:  constants.h
  *
- *    Description:  Header for constant values
+ *    Description:  Header for constant values export
  *
  *        Version:  1.0
  *        Created:  24/04/2017 21:06:32
 #define CONSTANTS_H
 
 #define board_size 8
+//extern const unsigned int board_size; /* 8 */
 
-extern const int empty;
-extern const int white;
-extern const int black;
+extern const unsigned int empty; /* 0 */
+extern const unsigned int white; /* 1 */
+extern const unsigned int black; /* 2 */
+
+extern const unsigned int player_one; /* black */
+extern const unsigned int player_two; /* white */
+
+
+extern const unsigned int hint_allowed; /* legal place for a pawn */
+extern const unsigned int hint_forbidden; /* illegal place for a pawn */
 
 #endif /* CONSTANTS_H */
 
index 0cd65a4d0a266e57c6cda3e87bd263877d629ff7..02eac9d82cad3c92011b35f03d4ca30e3e8262fc 100644 (file)
  * =====================================================================================
  */
 
+#include <stdlib.h>
+#include <stdbool.h>
 
+#include "othello.h"
+
+unsigned int current_player(unsigned int round_count) {
+   
+    if (round_count % 2 != 0) {
+        return player_two;
+    } else {
+        return player_one;
+    }
+}
+
+/* for consitency with ncurses, the board coordinates are in the following order:
+ * --x-->
+ * |
+ * y
+ * |
+ * v */
+
+unsigned int get_box_value(int y, int x, unsigned int pawn_array[board_size][board_size]) {
+   
+    return pawn_array[y][x];
+}
+
+bool is_box_type(int y, int x, unsigned int pawn_array[board_size][board_size], unsigned int type) {
+
+    if (type > 2) {
+        return NULL;
+    }
+    if (get_box_value(y, x, pawn_array) == type) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+/* 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]) {
+
+    if (is_box_type(y, x, pawn_array, empty)) {
+        pawn_array[y][x] = type;
+        return pawn_array;
+    } else {
+        return NULL;
+    }
+}
+
+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);
+         }
+    }
+    return 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 pawn_array;
+}
+
+unsigned int count_pawn_type(unsigned int pawn_array[board_size][board_size], unsigned int type) {
+    unsigned int count = 0;
+
+    if (type > 2) {
+        return -1;
+    }
+    for (unsigned int i = 0; i < board_size; i++) {
+        for (unsigned int j = 0; j < board_size; j++) {
+            if (pawn_array[i][j] == type) {
+                count++;
+            }
+        }
+    }
+    return count;
+}
index 7123697e655f5a41c1e30666afd39fefab951ddc..628f8e1c1a3a706c62d48b65777e0aefb332a5cb 100644 (file)
 
 #include "constants.h"
 
-int pawn[board_size][board_size] = {
-    {0, 0}
-};
+/* FIXME: declare and initialize the array here */
+//unsigned int pawns[board_size][board_size];
+
+unsigned int current_player(unsigned int round_count);
+
+int** init_pawns(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);
+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]);
+
+unsigned int count_pawn_type(unsigned int pawn_array[board_size][board_size], unsigned int type);
 
 #endif /* OTHELLO_H */
index c786772620be4e78df055a277c8f5507e78f989f..2673dc96348204ad9931d8f8efac8f9e5750333e 100644 (file)
--- a/lib/ui.c
+++ b/lib/ui.c
@@ -16,7 +16,7 @@
  * =====================================================================================
  */
 
-#include <ncurses.h>
+#include <string.h>
 
 #include "ui.h"
 
@@ -43,51 +43,107 @@ void print_board(int y, int x) {
     mvprintw(y+14, x, "5|    |    |    |    |    |    |    |    |");
     mvprintw(y+15, x, " |    |    |    |    |    |    |    |    |");
     mvprintw(y+16, x, " +----+----+----+----+----+----+----+----+");
-    mvprintw(y+17, x, "7|    |    |    |    |    |    |    |    |");
+    mvprintw(y+17, x, "6|    |    |    |    |    |    |    |    |");
     mvprintw(y+18, x, " |    |    |    |    |    |    |    |    |");
     mvprintw(y+19, x, " +----+----+----+----+----+----+----+----+");
-    mvprintw(y+20, x, "8|    |    |    |    |    |    |    |    |");
+    mvprintw(y+20, x, "7|    |    |    |    |    |    |    |    |");
     mvprintw(y+21, x, " |    |    |    |    |    |    |    |    |");
-    mvprintw(y+22, x, " -----+----+----+----+----+----+----+-----");
+    mvprintw(y+22, x, " +----+----+----+----+----+----+----+----+");
+    mvprintw(y+23, x, "8|    |    |    |    |    |    |    |    |");
+    mvprintw(y+24, x, " |    |    |    |    |    |    |    |    |");
+    mvprintw(y+25, x, " -----+----+----+----+----+----+----+-----");
 }
 
-static void print_o(int y, int x, int type) {
+static void print_o(int y, int x, unsigned int type) {
 
+    if (type == black) {
+        init_color(COLOR_CYAN, 0, 0, 0); /* redefine to a dark black color */
+        init_pair(2, COLOR_WHITE, COLOR_CYAN);
+        attron(COLOR_PAIR(2));
+    } else {
+        init_pair(3, COLOR_BLACK, COLOR_WHITE);
+        attron(COLOR_PAIR(3));
+    }
     mvprintw(y, x, "/\\");
     mvprintw(y+1, x, "\\/");
+    /* reset to default */
+    init_pair(1, COLOR_WHITE, COLOR_BLACK);
+    attron(COLOR_PAIR(1));
 }
 
 /* will be used for pawn placement hints */
-static void print_x(int y, int x, int type) {
+static void print_x(int y, int x, unsigned int type) {
 
+    if (type == hint_allowed) {
+        init_pair(4, COLOR_GREEN, COLOR_BLACK);
+        attron(COLOR_PAIR(4));
+    } else {
+        init_pair(5, COLOR_RED, COLOR_BLACK);
+        attron(COLOR_PAIR(5));
+    }
     mvprintw(y, x, "\\/");
     mvprintw(y+1, x,"/\\");
+    /* reset to default */
+    init_pair(1, COLOR_WHITE, COLOR_BLACK);
+    attron(COLOR_PAIR(1));
 }
 
 /* y = 1: y -> 0      x = 1: 1 -> 1
  * y > 1: y -> y + 3  x > 1: x -> x + 5 */
 static int remap_y(int y) {
-
+   
     if (y == 1) {
-        return 0;
-    } else if (y > 1) {
-        return (remap_y(y -1) + 3);
+        return 2;
+    } else if (y > 1 && y < board_size + 1) {
+        return (remap_y(y - 1) + 3);
     }
+    return -1;
 }
 
 static int remap_x(int x) {
 
     if (x == 1) {
-        return x;
-    } else if (x > 1) {
+        return 3;
+    } else if (x > 1 && x < board_size + 1) {
         return (remap_x(x - 1) + 5);
     }
+    return -1;
 }
 
-void print_pawns(int pawn_array[board_size][board_size]) {
-    for (int i = 0; i < board_size; i++) {
-        for (int j = 0; j < board_size; j++) {
-            //mvprintw(i,  j, "pawn[%d][%d] = %d\n", i, j, pawn_array[i][j]);
+void print_pawns(int base_y, int base_x, 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 (pawn_array[i][j] != empty) {
+                print_o(base_y + remap_y(i), base_x + remap_x(j), pawn_array[i][j]);
+            }
         }
     }
 }
+
+int map_col_letter_to_int(char c) {
+    
+    if (c == 'a' || c == 'A') {
+        return 1;
+    } else if (c == 'b' || c == 'B') {
+        return 2;
+    } else if (c == 'c' || c == 'C') {
+        return 3;
+    } else if (c == 'd' || c == 'D') {
+        return 4;
+    } else if (c == 'e' || c == 'E') {
+        return 5;
+    } else if (c == 'f' || c == 'F') {
+        return 6;
+    } else if (c == 'g' || c == 'G') {
+        return 7;
+    } else if (c == 'h' || c == 'H') {
+        return 8;
+    }
+    return -1;
+}
+
+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, "%d%c", y, x);
+    return (retVal == 1) ? 0 : 1;
+}
index ad32628042a00fc7f21ec044163fdbdd1359dc66..b24b6740ef63e3320b85364365fecabdb9bf58aa 100644 (file)
--- a/lib/ui.h
+++ b/lib/ui.h
 #ifndef UI_H
 #define UI_H
 
+#include <ncurses.h>
+
 #include "constants.h"
 
+int prompt_values(WINDOW* windows, int base_y, int base_x, const char* msg, int* y, char* x);
+
+int map_col_letter_to_int(char c);
+
 /* ncurses printing */
 void print_board(int y, int x);
-void print_pawns(int pawn_array[board_size][board_size]);
+void print_pawns(int base_y, int base_x, unsigned int pawn_array[board_size][board_size]);
 
 /* non ncurses printing */
 
index 7a327bed08e9bb79e74ecfbb03cd3f9815d08667..195bdbe1ef51644bf83d737bb6d42c148cadcfa3 100644 (file)
@@ -8,8 +8,15 @@
 
 int main() {
     int row = 0, col = 0;
-    int key_pressed = 0;
+    unsigned int round = 0;
+    unsigned int player = player_one; /* first player is black */
     bool exit_condition = false;
+    unsigned int nb_white = 0, nb_black = 0;
+
+    char* player_msg;
+
+    unsigned int pawns[board_size][board_size] = {{}};
+    pawns[board_size][board_size] = init_pawns(pawns);
 
     initscr();
     if (has_colors() == false) {
@@ -19,22 +26,64 @@ int main() {
     }
     start_color();
     getmaxyx(stdscr, row, col);
-    noecho();
+    //noecho();
+    echo();
     curs_set(0);
 
-    /* center the board */
-    int center_board_y = row/2 - 23/2;
-    int center_board_x = col/2 - 41/2;
+    /* center */
+    int center_y = row/2;
+    int center_x = col/2;
+    /* base coordinates to center the board */
+    int board_center_y = center_y - 26/2;
+    int board_center_x = center_x - 42/2;
 
     do {
-        print_board(center_board_y, center_board_x);
+        print_board(board_center_y, board_center_x);
+        print_pawns(board_center_y, board_center_x, pawns);
+
+        char* title_msg = "Jeu othello";
+        mvprintw(center_y - 26/2 - 4, (center_x - strlen(title_msg)/2), title_msg);
 
-        key_pressed = getch();
-        if (key_pressed == 'q') {
-            exit_condition = true;
+        nb_white = count_pawn_type(pawns, white);
+        nb_black = count_pawn_type(pawns, black);
+        
+        char* score_white_msg = "Pions blancs: %d";
+        mvprintw(center_y, center_x - 42/2 - strlen(score_white_msg) - 2, score_white_msg, nb_white);
+        char* score_black_msg = "Pions noirs: %d";
+        mvprintw(center_y, center_x + 42/2 + 2, score_black_msg, nb_black);
+
+        player = current_player(round);
+        
+        if (player == player_one) {
+            player_msg = "Joueur un (noir) joue !";
+        } else {
+            player_msg = "Joueur deux (blanc) joue !";
         }
-    } while (!exit_condition);
+        mvprintw(center_y - 26/2 - 2, (center_x - strlen(player_msg)/2), player_msg);
 
+        int y;
+        char x;
+        bool input_ok = false;
+        do {
+            y = 0;
+            x = "";
+            char* prompt_msg = "Prochain pion ? - ligne colonne (chiffre lettre):";
+            prompt_values(stdscr, center_y + 26/2 + 1, center_x - strlen(prompt_msg)/2, prompt_msg, &y, &x);
+            /* FIXME: separate the tests to permit to print explicit error messages */
+            if (((y > 0 && y < board_size + 1) || \
+                    (map_col_letter_to_int(x) > 0 && map_col_letter_to_int(x) < board_size + 1)) \
+                    && is_box_type(y, x, pawns, empty)) {
+                input_ok = true;
+            }
+        } while (!input_ok);
+        pawns[board_size][board_size] = set_pawn(y, map_col_letter_to_int(x), player, pawns);
+
+        round++; /* increment the round count */
+
+        refresh();
+
+    } while (!exit_condition);
+    
     endwin();
 
     exit(EXIT_SUCCESS);