Next will be the AI and the play again feature.
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
+exo?
*.static
*.dynamic
# for cygwin
To use it:
$ cp -a exo_skel TP_#/exo? (where # and ? are digits)
$ cd TP_#/exo? && cp exo_skel.c exo?.c
- Edit the Makefile to change the TARGET variable to the
+ Edit the Makefile to change the BINARY_NAME variable to the
exercice name desired
/* FIXME: ensure we manipulate real array */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
-#endif /* MACROS_H */
+#endif /* MACROS_H */
LDLIBS := $(filter-out -ltinfo,$(LDLIBS))
BINARY_SUFFIX := .exe
DLIB_SUFFIX := .dll
+# do not archive external libraries
CYGWIN_LDLIBS_NOARCHIVE := $(LDLIBS)
CYGWIN_LIBLDFLAGS := -Wl,--out-implib=$(LIBRARY_PATH)/$(DLIB_PREFIX)$(LIBRARY_NAME)$(DLIB_SUFFIX).a \
-Wl,--export-all-symbols \
Tic-tac-toe
-----------
-Touches correspondantes au case de la grille:
+Touches correspondantes aux cases de la grille:
a|z|e
-+-+-
#include "coordinates.h"
+#include <ncurses.h>
+
void init_coordinates(coordinates_t* coordinates_array) {
+
for (unsigned i = 0; i < MAX_COORDINATES; i++) {
coordinates_array[i] = set_coordinates(0, 0, 0);
}
return new_coordinates;
}
+/* FIXME: Does it worth doing a coordinates_t get_coordinates(int y, int x, unsigned type); helper function? */
+/* Or a int get_coordinates_x(int y, int x, unsigned type); helper function? */
+
/* the function do a lot of sanity checks before adding new board elements,
* hence the loop. moving the checks in the main loop is also possible */
unsigned add_coordinates(coordinates_t new_coordinates, coordinates_t* coordinates_array, unsigned round) {
+
/* valid coordinates are in the [1-3] range */
if (new_coordinates.y < 1 || new_coordinates.y > 3 || new_coordinates.x < 1 || new_coordinates.x > 3) {
return 3; /* error value for invalid coordinates */
- } else if (round == MAX_COORDINATES + 1) {
+ } else if (round == MAX_COORDINATES) {
+ /* round is off-by-one */
+ coordinates_array[MAX_COORDINATES - 1] = new_coordinates;
return 1; /* error value for full array */
}
-
for (unsigned i = 0; i < MAX_COORDINATES; i++) {
/* check if already entered */
if (new_coordinates.y == (coordinates_array + i)->y && new_coordinates.x == (coordinates_array + i)->x) {
return 4; /* error value for unknown error case - should never happen - */
}
-bool chk_win_conditions(coordinates_t* coordinates_array) {
- for (unsigned i = 0; i < MAX_COORDINATES; i++) {
+static bool chk_line(coordinates_t* coordinates_array, int line_number, unsigned round) {
+ unsigned nb_o_align = 0;
+ unsigned nb_x_align = 0;
+
+ for (unsigned i = 0; i < round; i++) {
+ /* check if they are all the same */
+ if ((coordinates_array + i)->y == line_number && (coordinates_array + i)->type == 0) {
+ nb_o_align++;
+ }
+ if ((coordinates_array + i)->y == line_number && (coordinates_array + i)->type == 1) {
+ nb_x_align++;
+ }
+ }
+ if (nb_o_align == 3 || nb_x_align == 3) {
+ return true;
+ }
+ return false;
+}
+
+static bool chk_column(coordinates_t* coordinates_array, int column_number, unsigned round) {
+ unsigned nb_o_align = 0;
+ unsigned nb_x_align = 0;
+ for (unsigned i = 0; i < round; i++) {
+ /* check if they are all the same */
+ if ((coordinates_array + i)->x == column_number && (coordinates_array + i)->type == 0) {
+ nb_o_align++;
+ }
+ if ((coordinates_array + i)->x == column_number && (coordinates_array + i)->type == 1) {
+ nb_x_align++;
+ }
+ }
+ /* one column must be full of the same type */
+ if (nb_o_align == 3 || nb_x_align == 3) {
+ return true;
+ }
+ return false;
+}
+
+static bool chk_diagonals(coordinates_t* coordinates_array, unsigned round) {
+ unsigned nb_o_diag_one = 0, nb_o_diag_two = 0;
+ unsigned nb_x_diag_one = 0, nb_x_diag_two = 0;
+
+ for (unsigned i = 0; i < round; i++) {
+ /* dumb count of each elements type in the two diagonals */
+ for (int y_x_diag = 1; y_x_diag < 4; y_x_diag++) {
+ if ((coordinates_array + i)->y == y_x_diag && (coordinates_array + i)->x == y_x_diag && (coordinates_array + i)->type == 0) {
+ nb_o_diag_one++;
+ }
+ if ((coordinates_array + i)->y == y_x_diag && (coordinates_array + i)->x == (4 - y_x_diag) && (coordinates_array + i)->type == 0) {
+ nb_o_diag_two++;
+ }
+ if ((coordinates_array + i)->y == y_x_diag && (coordinates_array + i)->x == y_x_diag && (coordinates_array + i)->type == 1) {
+ nb_x_diag_one++;
+ }
+ if ((coordinates_array + i)->y == y_x_diag && (coordinates_array + i)->x == (4 - y_x_diag) && (coordinates_array + i)->type == 1) {
+ nb_x_diag_two++;
+ }
+ }
+ if (nb_o_diag_one == 3 || nb_o_diag_two == 3 || nb_x_diag_one == 3 || nb_x_diag_two == 3) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool chk_win_conditions(coordinates_t* coordinates_array, unsigned round) {
+
+ /* winning conditions begin at round = 4 */
+ if (round > 3) {
+ if (chk_diagonals(coordinates_array, round)) {
+ return true;
+ }
+ for (unsigned i = 1; i < 4; i++) {
+ if (chk_line(coordinates_array, i, round) || \
+ chk_column(coordinates_array, i, round)) {
+ return true;
+ }
+ }
}
return false;
}
void init_coordinates(coordinates_t* coordinates_array);
coordinates_t set_coordinates(int y, int x, unsigned type);
unsigned add_coordinates(coordinates_t new_coordinates, coordinates_t* coordinates_array, unsigned round);
-bool chk_win_conditions(coordinates_t* coordinates_array);
+bool chk_win_conditions(coordinates_t* coordinates_array, unsigned round);
#endif /* COORDINATES_H */
* which can be a space ' ' */
void print_board(int y, int x) {
+
mvprintw(y, x, " | |");
mvprintw(y+1, x, " | |");
mvprintw(y+2, x, "----+----+----");
* The added (y, x) couple values can be {0, 3, 6}x{1, 6, 11}
*/
-void print_x(int y, int x) {
+static void print_x(int y, int x) {
+
mvprintw(y, x, "\\/");
mvprintw(y+1, x,"/\\");
}
-void print_o(int y, int x) {
+static void print_o(int y, int x) {
+
mvprintw(y, x, "/\\");
mvprintw(y+1, x, "\\/");
}
* 2 -> +3 2 -> +6
* 3 -> +6 3 -> +11 */
static int remap_y(int y) {
+
if (y == 1) {
return 0;
} else if (y == 2) {
}
static int remap_x(int x) {
+
if (x == 1) {
return 1;
} else if (x == 2) {
void print_coordinates(coordinates_t coordinates_array[], int base_y, int base_x) {
unsigned i = 0;
+
while ((coordinates_array + i)->y != 0 && (coordinates_array + i)->x != 0) {
if ((coordinates_array + i)->type == 0) {
print_o(base_y + remap_y((coordinates_array + i)->y), base_x + remap_x((coordinates_array + i)->x));
i++;
}
}
+
+/* void printf_result(unsigned player, unsigned round) {
+ char* result_msg = "";
+
+ if (round < MAX_COORDINATES + 1) {
+ if (player == 0) {
+ result_msg = "Joueur 1";
+ } else {
+ result_msg = "Joueur 2";
+ }
+ printf("%s gagne !\n", result_msg);
+ } else {
+ printf("Egalite !\n");
+ }
+} */
+
#include "coordinates.h"
+/* ncurses printing */
void print_board(int y, int x);
-void print_x(int y, int x);
-void print_o(int y, int x);
void print_coordinates(coordinates_t coordinates_array[], int base_y, int base_x);
+/* non ncurses printing */
+/* void printf_result(unsigned player, unsigned round); */
+
#endif /* DISPLAY_H */
/* FIXME: ensure we manipulate real array */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
-#endif /* MACROS_H */
+#endif /* MACROS_H */
int main() {
int row, col, errno = 0, round = 0, player = 0, key_pressed;
+ bool winning_condition = false;
+ bool loop_exit_condition = false;
const int str_max_length = 255;
+ /* FIXME: make a strings handling library */
char* top_msg = malloc(str_max_length * sizeof(char));
char* back_msg = malloc(str_max_length * sizeof(char));
+ char* exit_msg = malloc(str_max_length * sizeof(char));
initscr();
getmaxyx(stdscr, row, col);
print_coordinates(coordinates_array, base_y, base_x);
- /* getch() is blocking */
- key_pressed = getch();
- switch (key_pressed) {
- case 'a':
- new_coordinates = set_coordinates(1, 1, player);
- break;
- case 'z':
- new_coordinates = set_coordinates(1, 2, player);
- break;
- case 'e':
- new_coordinates = set_coordinates(1, 3, player);
- break;
- case 'q':
- new_coordinates = set_coordinates(2, 1, player);
- break;
- case 's':
- new_coordinates = set_coordinates(2, 2, player);
- break;
- case 'd':
- new_coordinates = set_coordinates(2, 3, player);
- break;
- case 'w':
- new_coordinates = set_coordinates(3, 1, player);
- break;
- case 'x':
- new_coordinates = set_coordinates(3, 2, player);
- break;
- case 'c':
- new_coordinates = set_coordinates(3, 3, player);
- break;
- default:
- /* set invalid coordinates */
- new_coordinates = set_coordinates(0, 0, player);
- break;
+ /* FIXME: group the winning case code blocks */
+ if (!winning_condition) {
+ /* getch() is blocking */
+ key_pressed = getch();
+ switch (key_pressed) {
+ case 'a':
+ new_coordinates = set_coordinates(1, 1, player);
+ break;
+ case 'z':
+ new_coordinates = set_coordinates(1, 2, player);
+ break;
+ case 'e':
+ new_coordinates = set_coordinates(1, 3, player);
+ break;
+ case 'q':
+ new_coordinates = set_coordinates(2, 1, player);
+ break;
+ case 's':
+ new_coordinates = set_coordinates(2, 2, player);
+ break;
+ case 'd':
+ new_coordinates = set_coordinates(2, 3, player);
+ break;
+ case 'w':
+ new_coordinates = set_coordinates(3, 1, player);
+ break;
+ case 'x':
+ new_coordinates = set_coordinates(3, 2, player);
+ break;
+ case 'c':
+ new_coordinates = set_coordinates(3, 3, player);
+ break;
+ default:
+ /* set invalid coordinates */
+ new_coordinates = set_coordinates(0, 0, player);
+ break;
+ }
+ errno = add_coordinates(new_coordinates, coordinates_array, round);
+ winning_condition = chk_win_conditions(coordinates_array, round);
}
- errno = add_coordinates(new_coordinates, coordinates_array, round);
-
- if (errno == 2) {
- back_msg = "Choisir une case vide";
- } else if (errno == 3) {
- back_msg = "Coordonnees invalides";
- } else if (errno == 1) {
- back_msg = "Tableau rempli sans gagnant: egalite";
- } else if (errno == 4) {
- back_msg = "Erreur inconnue";
- } else if (errno == 0) {
- /* FIXME: properly zero the string */
- back_msg = "";
+ if (winning_condition) {
+ if (player == 0) {
+ back_msg = "Joureur 1 gagne !";
+ } else {
+ back_msg = "Joureur 2 gagne !";
+ }
+ }
+
+ if (!winning_condition) {
+ if (errno == 2) {
+ back_msg = "Choisir une case vide";
+ } else if (errno == 3) {
+ back_msg = "Coordonnees invalides";
+ } else if (errno == 1) {
+ back_msg = "Tableau rempli sans gagnant: egalite";
+ } else if (errno == 4) {
+ back_msg = "Erreur inconnue";
+ } else if (errno == 0) {
+ /* FIXME: properly zero the string */
+ back_msg = "";
+ }
}
mvprintw(base_y + 10, (base_x + 7 - strlen(back_msg)/2), back_msg);
+ if (winning_condition || errno == 1) {
+ /* print the updated coordinates before exiting */
+ print_coordinates(coordinates_array, base_y, base_x);
+ exit_msg = "Pressez une touche pour sortir";
+ mvprintw(base_y + 12, (base_x + 7 - strlen(exit_msg)/2), exit_msg);
+ loop_exit_condition = true;
+ }
+
refresh();
- } while (errno != 1);
+ } while (!loop_exit_condition);
+
+ /* getch() is blocking */
+ getch();
+
+ endwin();
if (!top_msg)
free(top_msg);
if (!back_msg)
free(back_msg);
-
- endwin();
+ if (!exit_msg)
+ free(exit_msg);
exit(EXIT_SUCCESS);
}