diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..371b0f6 --- /dev/null +++ b/include/common.h @@ -0,0 +1,27 @@ +#ifndef COMMON_H +#define COMMON_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned int uint; + +/*Status code to represent respectively, +a negative answer, +a positive answer, +an almost positive answer +*/ +typedef enum { + NO, + YES, + ALMOST, +} e_status; + +#endif /*COMMON*/ diff --git a/include/model.h b/include/model.h new file mode 100644 index 0000000..21be7e1 --- /dev/null +++ b/include/model.h @@ -0,0 +1,195 @@ +#ifndef MODEL_H +#define MODEL_H +#include "common.h" + +#define MIN_BOARD_LEVEL 1 +#define MAX_BOARD_LEVEL 2 + +// Constant character to represent the cross player, the round, none or both of +// them (this last one is usefull for tie game) +typedef enum { + PLAYER_O = 'O', + PLAYER_X = 'X', + NOBODY = ' ', + BOTH = '#' +} e_player; + +// Constant defining the 9 possible positions in a tic tac toe, any of this +// position and none of this position +typedef enum { + TOPLEFT, + TOPCENTER, + TOPRIGHT, + MIDLEFT, + MIDCENTER, + MIDRIGHT, + BOTTOMLEFT, + BOTTOMCENTER, + BOTTOMRIGHT, + FREE, + NONE +} e_location; + +#define TICTACTOE_SIZE 9 +#define TICTACTOE_WIDTH 3 + +// The tic tac toe structure +typedef struct { + e_player *content; // array of TICTACTOE_SIZE e_player defining content of + // each the TICTACTOE_SIZE cells of a tic tac toe defined + // from top left to bottom right + e_player winner; // player who have won the tic tac toe game; BOTH in case of + // a tie game +} s_tictactoe; + +// A move structure +typedef struct { + e_location inner_position; // The position in the inner tic tac toe + e_location outer_position; // The position in the outer tic tact toe + e_player player; // The player who achieve the move +} s_move; + +// A simple linked list of s_move +typedef struct list { + s_move *last_move; + struct list *next; +} list_element_s_move; + +// The ultimate tic tac toe structure +typedef struct { + uint inception_level; // inception level of the ultimate tictactoe + s_tictactoe * + *inner_tictactoes; // array of the TICTACTOE_SIZE inner tic tac + // toes defining content of each the + // TICTACTOE_SIZE cells of an ultimate tic tac + // toe defined from top left to bottom right + s_tictactoe * + outer_tictactoe; // a tic tac toe representing the outer game which + // allows to store the winners of each inner tic tac toe + list_element_s_move *history; // full history of the played moves as a stack + // of s_moves - LIFO ended by a NULL pointer. +} s_utictactoe; +/* + * A uttt of inception-level 1 just correspond to the outer_tictactoe while + * inner_tictactoes is NULL + * + * A uttt of inception-level 2 is an array of TICTACTOE_SIZE tictactoes from + * TOP_LEFT to BOTTOM_RIGHT and outer_ticatactoe represent the overall game + * Example of indices for a uttt of inception-level 1 + * 0|1|2 + * ----- + * 3|4|5 + * ----- + * 6|7|8 + */ + +/*! + * This function allocates an s_move structure corresponding to an empty move + * (free positions and nobody as player). + * + * \return a reference to the s_move memory space allocated, NULL in case of + * allocation problem. + */ +s_move *create_empty_move(); + +/*! + * This function allocates an s_tictactoe structure corresponding to an empty + * tictactoe ready to be played. + * + * \return a reference to the s_tictactoe memory space allocated, NULL in case + * of allocation problem. + */ +s_tictactoe *create_empty_tictactoe(); + +/*! + * This function allocates an s_utictactoe structure corresponding to an empty + * utictactoe of the corresponding inception_level and ready to be played + * starting by PLAYER_X player. + * + * \return a reference to the s_utictactoe memory space allocated, NULL in case + * of allocation problem. + */ +s_utictactoe *create_empty_utictactoe(uint inception_level); + +/*! + * This function free all the memory used by a given s_move which reference is + * given. + * + * \param p_move a pointer on a s_move to be freed. + */ +void free_move(s_move *p_move); + +/*! + * This function free all the memory used by a given tictactoe structure which + * reference is given. + * + * \param p_ttt a pointer on a s_tictactoe to be freed. + */ +void free_tictactoe(s_tictactoe *p_ttt); + +/*! + * This function free all the memory used by a given ultimate tictactoe + * structure which reference is given. + * + * \param p_uttt a pointer on a s_utictactoe to be freed. + */ +void free_utictactoe(s_utictactoe *p_uttt); + +/*! + * This function determines the e_player which should be the next player to play + * in the corresponding p_uttt. + * + * \param p_uttt a pointer on a s_utictactoe. + * \return a e_player (PLAYER_X - if last player who played was PLAYER_O or its + * the first move, PLAYER_O - if last player who played was PLAYER_X, or NOBODY + * if no move can be done anymore or if there is a winner). + */ +e_player get_next_player_to_play(s_utictactoe *p_uttt); + +/*! + * This function determines the next outer position where the current player + * should play its next move in the corresponding p_uttt. + * + * \param p_uttt a pointer on a s_utictactoe. + * \return a e_location corresponding to the next outer position induced by the + * last move + * - set to FREE if the next move is free of constraints + */ +e_location get_next_outer_position(s_utictactoe *p_uttt); + +/*! + * This function evaluate if a move is valid in the corresponding p_uttt. + * A move is valid if its player and the inner and outer positions are + * consistent with the current s_utictactoe: correct unused position, not a + * tictactoe with already a winner and the correct player. It returns a boolean + * corresponding to the success of the move. + * + * \param p_uttt a pointer on a s_utictactoe. + * \param a_move an s_move to be played. + * \return YES if playing a_move was possible - NO if impossible. + */ +e_status is_move_valid(s_utictactoe *p_uttt, s_move *p_move); + +/*! + * This function set the winner of the corresponding p_ttt. + * + * \param p_ttt a pointer on a s_tictactoe whose winner field will be updated. + */ +void set_tictactoe_winner(s_tictactoe *p_ttt); + +/*! + * This function tries to play a given move in the corresponding p_uttt. + * It plays the corresponding move if possible and returns a boolean + * corresponding to the success of the move. The function should set the + * possible winner. + * + * \param p_uttt a pointer on a s_utictactoe. + * \param p_move an s_move to be played. + * \return YES if playing a_move was possible - NO if impossible. + */ +e_status play_move(s_utictactoe *p_uttt, s_move *p_move); + +/*Given usefull functions*/ +void draw_utictactoe(s_utictactoe *p_uttt); +void draw_utictactoe_history(s_utictactoe *p_uttt); +#endif /* MODEL_H */ \ No newline at end of file diff --git a/src/Makefile b/src/Makefile index 5dcf528..cf12cec 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,11 +7,11 @@ CC=gcc CFLAGS=-Wall -g -std=c99 -CPPFLAGS= +CPPFLAGS=-I../include all: utictactoe -utictactoe: utictactoe.c ## Compile utictactoe.c +utictactoe: utictactoe.c model.c## Compile utictactoe.c # Nettoyage .PHONY: clean help diff --git a/src/model.c b/src/model.c new file mode 100644 index 0000000..76fe898 --- /dev/null +++ b/src/model.c @@ -0,0 +1,221 @@ +#include "model.h" + + +/* + * Create empty move + */ + +s_move *create_empty_move(){ + s_move * value = (s_move*) malloc(sizeof(s_move)); + if ( value ) { + value->inner_position = FREE; + value->outer_position = FREE; + value->player = NOBODY; + } + return value; +} + + +/* + * Create an empty tictactoe + */ +s_tictactoe *create_empty_tictactoe() { + + // Create s_tictactoe structure + s_tictactoe * value = (s_tictactoe*) malloc(sizeof(s_tictactoe)); + if ( value ) { + // create player + value->winner = NOBODY; + value->content = (e_player*) malloc(sizeof(e_player) * TICTACTOE_SIZE); + if ( ! value->content ) { + return value->content; + } + for ( int i=0;icontent[i] = NOBODY; + } + } + return value; +} + +/* + * Create empty uTicTacToe + */ + +s_utictactoe *create_empty_utictactoe (uint inception_level) { + s_utictactoe * value = (s_utictactoe*) malloc(sizeof(s_utictactoe)); + if ( value ) { + + // then initiate outer_tictactoe amd inception_level + value->outer_tictactoe = create_empty_tictactoe(); + value->inception_level = inception_level; + value->history = NULL; // no history for now + + // initialize inner TTT + if (inception_level == 1){ + value->inner_tictactoes = NULL; + } + else { + // As inception level can't be more than 2 (for now), inner_ttts + // should be 9 simple ttt + + value->inner_tictactoes = (s_tictactoe**) + malloc(sizeof(s_tictactoe)); + + if ( ! value->inner_tictactoes ) { + return NULL; + } + + for ( int i=0; iinner_tictactoes[i] = create_empty_tictactoe(); + } + } + } + return value; +} + + +void free_move(s_move *p_move){ + if ( p_move == NULL ) { + free(p_move); + } +} + +void free_tictactoe(s_tictactoe *p_ttt){ + if ( p_ttt) { + free(p_ttt->content); + free(p_ttt); + p_ttt = NULL; + } +} + +void free_utictactoe(s_utictactoe *p_uttt){ + if ( p_uttt ) { + // if we have inner_ttt we need to remove inet + if ( p_uttt->inner_tictactoes != NULL ) { + for ( int i=0; iinner_tictactoes[i]); + } + free(p_uttt->inner_tictactoes); + } + free_tictactoe(p_uttt->outer_tictactoe); + free(p_uttt); + p_uttt = NULL; + } +} + +e_player get_next_player_to_play(s_utictactoe *p_uttt) { + if ( p_uttt->history->last_move->player == PLAYER_O ) { + return PLAYER_X; + } + else { + return PLAYER_O; + } +} + +e_location get_next_outer_position(s_utictactoe *p_uttt) { + if ( p_uttt->inner_tictactoes != NULL ) { + e_location pos = p_uttt->history->last_move->inner_position; + if ( p_uttt->inner_tictactoes->content[pos]->winner == NOBODY ) { + return pos; + } + } + return FREE; +} + +e_status is_move_valid(s_utictactoe *p_uttt, s_move *p_move){ + if ( get_next_player_to_play(p_uttt) != p_move->player ) { + return NO; + } + return YES; +} + +void set_tictactoe_winner(s_tictactoe *p_ttt){ + bool find; + int next; + + if ( p_ttt->winner == NOBODY ) { + for(int i = 0; i < TICTACTOE_WIDTH; i++){ + + /* + * Test for first diagonale + */ + if ( p_ttt->content[i] != NOBODY ) { + // if case 0 we need to test diagonale + if ( i == 0 ){ + int next; + find = true; + for (int l = 1; l < TICTACTOE_WIDTH; l++) { + // Maybe it is overkill to test diagonal but... + // ... no need to rewrite if we update TICTACTOE_WIDTH + next = l * TICTACTOE_WIDTH + l; + if ( p_ttt->content[i] != p_ttt ->content[next]) { + find = false; + break; + } + } + if (find == true) { + p_ttt->winner = p_ttt->content[i]; + return; + } + } + } + + /* + * second diagonal, from the end of line + */ + if ( i == TICTACTOE_WIDTH - 1 ) { + find = true; + for ( int l = 1; l < TICTACTOE_WIDTH; l++){ + next = (TICTACTOE_WIDTH - 1) * l; + if ( p_ttt->content[i] == p_ttt->content[next] ) { + find = false; + break; + } + } + if ( find == true ){ + p_ttt->winner = p_ttt->content[i]; + return; + } + } + + /* + * column + */ + find = true; + for (int c = 1; c < TICTACTOE_WIDTH; c++ ) { + next = TICTACTOE_WIDTH * c + i; + if ( p_ttt->content[i] != p_ttt->content[next] ) { + find = false; + break; + } + if ( find == true ){ + p_ttt->winner = p_ttt->content[i]; + return; + } + } + + /* + * line + */ + int line = i * TICTACTOE_WIDTH; + if (p_ttt->content[line] != NOBODY){ + find = true; + for ( int l = 1; l < TICTACTOE_WIDTH; l++ ) { + next = line + l; + if ( p_ttt->content[line] != p_ttt->content[next] ) { + find = false; + break; + } + } + if ( find == true ) { + p_ttt->winner = p_ttt->content[line]; + return; + } + } + } + } +} + +e_status play_move(s_utictactoe *p_ttt, s_move *p_move) { + return YES; +} diff --git a/src/utictactoe b/src/utictactoe new file mode 100755 index 0000000..972cf56 Binary files /dev/null and b/src/utictactoe differ diff --git a/src/utictactoe.c b/src/utictactoe.c index c7a7b0e..b23d427 100644 --- a/src/utictactoe.c +++ b/src/utictactoe.c @@ -1,11 +1,13 @@ -#include -#include -#include -#include -#include -#include -#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include #include "utictactoe.h" +#include "common.h" +#include "model.h" #define OPTIONAL_ARGUMENT_IS_PRESENT \ ((optarg == NULL && optind < argc && argv[optind][0] != '-') \ @@ -26,6 +28,9 @@ void help(){ } int check_int_value ( char *value, int min, int max){ + struct a { + int b; + }; char * end_ptr; int result; result = strtol(optarg, &end_ptr, 10); @@ -135,6 +140,15 @@ int main(int argc, char* argv[]) { exit (EXIT_FAILURE); } } - printf("Hello World!\n"); + s_move *test_move = create_empty_move(); + free_move(test_move); + s_tictactoe *test_ttt = create_empty_tictactoe(); + free_tictactoe(test_ttt); + s_utictactoe *test_uttt = create_empty_utictactoe(1); + free_utictactoe(test_uttt); + test_uttt = create_empty_utictactoe(2); + free_utictactoe(test_uttt); + test_uttt = create_empty_utictactoe(3); + free_utictactoe(test_uttt); return EXIT_SUCCESS; }