diff --git a/include/common.h b/include/common.h index 371b0f6..97101b6 100644 --- a/include/common.h +++ b/include/common.h @@ -24,4 +24,9 @@ typedef enum { ALMOST, } e_status; +typedef enum { + HUMAN, + RANDOM, + CLEVER, +} e_tactic; #endif /*COMMON*/ diff --git a/include/ia.h b/include/ia.h new file mode 100644 index 0000000..f61ce40 --- /dev/null +++ b/include/ia.h @@ -0,0 +1,17 @@ +#ifndef IA_H +#define IA_H +#include "common.h" +#include "model.h" +/*! + * This function modify the move in parameter in order to get a valid move (1) randomly if tactic is 0 or + * (2) in a clever way if tactic is 1 in the corresponding utictactoe u. + * + * \param p_uttt a pointer on a s_utictactoe. + * \param p_move a pointer on a s_move to be modified. + * \param tactic an e_tactic set to 0 for random strategy and 1 for clever one. + */ +void best_move(s_utictactoe* p_uttt, s_move* p_move, e_tactic tactic); + +s_tictactoe * clone_ttt( s_tictactoe * p_ttt ); +e_location get_best_random_position( s_tictactoe * p_uttt, e_player player); +#endif diff --git a/include/view.h b/include/view.h index 9dee319..a5d5e5d 100644 --- a/include/view.h +++ b/include/view.h @@ -25,8 +25,9 @@ int elocation_to_coord(e_location l); * \param p_move a pointer on a s_move to be modified. * \param v a pointer on the view to use. */ -void set_next_player_move(s_move * p_move, p_view v); +void set_next_player_move(s_move * p_move, p_view v, e_tactic tactic); +void display_winner(p_view v); /*! * This function free all the memory used by a given view which * reference is given. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4812c33..996dcc8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,4 +3,4 @@ set(CMAKE_C_FLAGS "-std=c99 -lncurses -g -Wall") set(CMAKE_INSTALL_PREFIX ".") include_directories(../include) project(utictactoe) -add_executable(${PROJECT_NAME} utictactoe.c model.c view.c) +add_executable(${PROJECT_NAME} utictactoe.c model.c view.c ia.c) diff --git a/src/ia.c b/src/ia.c new file mode 100644 index 0000000..64a73ff --- /dev/null +++ b/src/ia.c @@ -0,0 +1,76 @@ +#include "common.h" +#include "model.h" +#include "view.h" +#include "ia.h" + +void best_move (s_utictactoe * p_uttt, s_move * m ,e_tactic tactic) +{ + //do{ + if ( p_uttt->inception_level == 1 ) { + m->outer_position = get_best_random_position( + p_uttt->outer_tictactoe, + m->player + ); + } + else { + m->outer_position = get_next_outer_position(p_uttt); + if ( m->outer_position == FREE ) { + do { + m->outer_position = (e_location)(TOPLEFT + rand() % TICTACTOE_SIZE); + } while(p_uttt->inner_tictactoes[m->outer_position]->winner != NOBODY); + } + + m->inner_position = get_best_random_position( + p_uttt->inner_tictactoes[m->outer_position], + m->player + ); + } + //} while (is_move_valid(p_uttt,m) != YES); + return; +} + +s_tictactoe * clone_ttt( s_tictactoe * p_ttt ) { + s_tictactoe * t = create_empty_tictactoe(); + for (int i=0; icontent[i] = p_ttt->content[i]; + } + return t; +} + +e_location get_best_random_position (s_tictactoe * p_ttt, e_player player) { + mvwprintw(stdscr, 13, 0, " "); + s_tictactoe * c_ttt = clone_ttt(p_ttt); + e_player opponent = ( player == PLAYER_O )?PLAYER_X:PLAYER_O; + + // Check if IA player can win + for(int i=0; icontent[i] == NOBODY) { + c_ttt->content[i] = player; + set_tictactoe_winner(c_ttt); + if ( c_ttt->winner != NOBODY ) { + free_tictactoe(c_ttt); + mvwprintw(stdscr, 13, 0, "Je vais gagner "); + return i; + } + c_ttt->content[i] = NOBODY; + } + } + + // avoid loosing + for(int i=0; icontent[i] == NOBODY) { + c_ttt->content[i] = opponent; + set_tictactoe_winner(c_ttt); + if ( c_ttt->winner != NOBODY ) { + free_tictactoe(c_ttt); + mvwprintw(stdscr, 13, 0, "Je ne peux pas te laisser gagner!"); + return i; + } + c_ttt->content[i] = NOBODY; + } + } + + // We have not a winnner move... + free_tictactoe(c_ttt); + return (e_location)(rand() % TICTACTOE_SIZE); +} diff --git a/src/utictactoe.c b/src/utictactoe.c index 67f2f02..e3d957b 100644 --- a/src/utictactoe.c +++ b/src/utictactoe.c @@ -9,6 +9,7 @@ #include "common.h" #include "model.h" #include "view.h" +#include "ia.h" #define OPTIONAL_ARGUMENT_IS_PRESENT \ ((optarg == NULL && optind < argc && argv[optind][0] != '-') \ @@ -46,15 +47,15 @@ int check_int_value ( char *value, int min, int max){ int main(int argc, char* argv[]) { int optc; - int cross_ai, round_ai = 0; - int inception_level = 0; + e_tactic tactic_cross = HUMAN, tactic_round = HUMAN; + int inception_level = 2; bool verbose, contest_mode = false; char * contest_file; static struct option long_opts[] = { {"inception-level", optional_argument, 0, 'i'}, - {"cross-ai", required_argument, 0, 'x'}, - {"round-ai", required_argument, 0, 'o'}, + {"tactic_cross", required_argument, 0, 'x'}, + {"tactic_round", required_argument, 0, 'o'}, {"contest", required_argument, 0, 'c'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, @@ -80,8 +81,8 @@ int main(int argc, char* argv[]) { case 'x': printf ("cross ai\n"); if ( optarg ) { - cross_ai = check_int_value(optarg, 0, 1); - if ( cross_ai == -1 ) { + tactic_cross = check_int_value(optarg, 0, 2); + if ( tactic_cross == -1 ) { fprintf(stderr, "Error: incorrect cross ai value\n"); exit (EXIT_FAILURE); } @@ -96,8 +97,8 @@ int main(int argc, char* argv[]) { case 'o': printf ("round ai\n"); if ( optarg ) { - round_ai = check_int_value(optarg, 0, 1); - if ( round_ai == -1 ) { + tactic_round = check_int_value(optarg, 0, 2); + if ( tactic_round == -1 ) { fprintf(stderr, "Error: incorrect round ai value\n"); exit (EXIT_FAILURE); } @@ -141,35 +142,23 @@ int main(int argc, char* argv[]) { exit (EXIT_FAILURE); } } - s_utictactoe *s = create_empty_utictactoe(1); + srand(time(NULL)); + s_utictactoe *s = create_empty_utictactoe(inception_level); s_move *m = create_empty_move(); p_view v = create_view(s); - while (s->outer_tictactoe->winner == NOBODY) { - m->player = get_next_player_to_play(s); - m->outer_position=get_next_outer_position(s); - set_next_player_move(m,v); - play_move(s, m); - } - free_view(v); - draw_utictactoe(s); - draw_utictactoe_history(s); - printf("The winner is : %c\n", s->outer_tictactoe->winner); - free_move(m); - free_utictactoe(s); - - s = create_empty_utictactoe(2); - m = create_empty_move(); - v = create_view(s); while (s->outer_tictactoe->winner == NOBODY) { m->player = get_next_player_to_play(s); - m->outer_position=get_next_outer_position(s); - set_next_player_move(m,v); + m->outer_position = get_next_outer_position(s); + if (m->player == PLAYER_X) { + set_next_player_move(m, v, tactic_cross); + } else { + set_next_player_move(m, v, tactic_round); + } play_move(s, m); - m->outer_position = m->inner_position; } + display_winner(v); + getchar();//just to pause before quitting the program free_view(v); - draw_utictactoe_history(s); - printf("The winner is : %c\n", s->outer_tictactoe->winner); free_move(m); free_utictactoe(s); } diff --git a/src/view.c b/src/view.c index 28b3c29..45a1ea6 100644 --- a/src/view.c +++ b/src/view.c @@ -1,6 +1,7 @@ #include "common.h" #include "model.h" #include "view.h" +#include "ia.h" struct view{ s_utictactoe * p_uttt; @@ -66,8 +67,15 @@ void draw_ttt(WINDOW * w, s_tictactoe * u){ } } -void set_next_player_move(s_move * m, p_view v) +void set_next_player_move(s_move * m, p_view v, e_tactic tactic ) { + + // computer player + if(tactic != HUMAN) { + best_move(v->p_uttt, m, tactic); + return ; + } + char * s="Player to play:%c"; int in_x = 3, out_x = 3; int out_y = 2, in_y = 2; @@ -120,7 +128,7 @@ void set_next_player_move(s_move * m, p_view v) wrefresh(v->w_uttt); if (v->p_uttt->inception_level == 2) wrefresh(v->w_ttt); wrefresh(stdscr); - + ch = wgetch(stdscr); switch(ch) @@ -242,6 +250,21 @@ int elocation_to_coord(e_location l){ } } +void display_winner(p_view v){ + int ch = ' '; + draw_ttt(v->w_uttt, v->p_uttt->outer_tictactoe); + wrefresh(v->w_uttt); + if (v->p_uttt->inception_level == 2){ + draw_ttt(v->w_ttt, v->p_uttt->inner_tictactoes[TOPLEFT]); + } + wrefresh(stdscr); + do { + mvwprintw(stdscr, 1, 0, "le gagnant est : %c, apputez sur 'entree' pour quitter", + v->p_uttt->outer_tictactoe->winner); + ch = wgetch(stdscr); + } while (ch != '\n'); + +} void free_view(p_view v){ delwin(v->w_uttt); v->w_uttt = NULL;