Dumb but not dumber IA

This commit is contained in:
Yorick Barbanneau 2021-10-24 23:22:43 +02:00
parent 033a436be2
commit 87e7ff5829
7 changed files with 145 additions and 34 deletions

View file

@ -24,4 +24,9 @@ typedef enum {
ALMOST,
} e_status;
typedef enum {
HUMAN,
RANDOM,
CLEVER,
} e_tactic;
#endif /*COMMON*/

17
include/ia.h Normal file
View file

@ -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

View file

@ -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.

View file

@ -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)

76
src/ia.c Normal file
View file

@ -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; i<TICTACTOE_SIZE; i++){
t->content[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; i<TICTACTOE_SIZE; i++) {
if(c_ttt->content[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; i<TICTACTOE_SIZE; i++) {
if(c_ttt->content[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);
}

View file

@ -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);
}

View file

@ -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;