AI is harder than I thought

Started by
38 comments, last by LAURENT* 9 years, 12 months ago

So I wanted to make an AI for my tic-tac-toe game that was really random. I tried a LOT of ideas that failed and still have more but, now I think I need some assitances. Sorry but I don't have code now. I'm making this thread to force myself to commit to ask for help later. See ya in 7 hours!

Advertisement

You probably don't want a truly random AI, as it would have a fair chance at playing something incredibly stupid (e.g. the opponent has 2 in row, and doesn't place to win, but just picks a random open tile).

Tic-Tac-Toe is a solved game -- there exists a strategy which will allow you to never lose (and if the opponent doesn't play perfectly, you will always win).1

Most people generally don't know this, so you can still make an AI which is challenging enough for this type of player.

What I'd suggest is something like, from highest to lowest priority:

Place a winning move if you can.

If you can't, block other player if he has winning move next turn.

Pick a random open tile.

This could be further tweaked, e.g. by adding a chance to not do the correct thing, but it should hopefully get you a good start.

1If you're interested in more about this, wikipedia has it explained fairly nicely, as far as I can recall. Also of note as a reference is "minimax".

Hello to all my stalkers.

If you want you can have a look at this code: click

Specifically line 146 - computerMove() function.

I have written this version in my early years when I was learning C++ and some parts of the code look horrible :D,

but the algorithm for the AI should work just fine.

Yeah, you should look for a tic-tac-toe algorithm and use that, because if it is a soloved game, there is not really any way that you can make the computer 100% intelligent yet fair (If the computer was programmed to know the solution to the game it would win every time. Then it comes down to who goes first, or second (it depends on the solution of tic tac toe, which I don't know myself.)

They call me the Tutorial Doctor.

You can used the 'solved' solution, and yes that will make it a better (perfect) tic tac toe machine, but I don't know if that really helps you with AI.

If anything, it would give you practice with matrix rotations and comparisons.

The problem you are going to run into is most 'trivial' games have been solved. A few you might try that would give you more room to play with the AI:

1) Don't know the name of it - 'game board' is lines of dots. You take away dots on your turn. You win if you opponent picks up the last dot.

2) Fox and the Hounds and its many variants - the simplest of which simply start with a 'character marker' on a hex grid. That players goal is to reach the edge of the board and 'escape'. Player 2 places blocking markers - 1 per turn. His goal is to 'trap' the fox.

3) You could go into games without perfect information: blackjack is a nice simple game to get started with there.

"The multitudes see death as tragic. If this were true, so then would be birth"

- Pisha, Vampire the Maquerade: Bloodlines

1) Don't know the name of it - 'game board' is lines of dots. You take away dots on your turn. You win if you opponent picks up the last dot.

It's called Nim, and it has been solved for over a hundred years.

Sorry for the delay, my network was acting up and it look like my a driver got corrupted while I was updating my tablet. Anyways I've fix the problem and now i'm ready to code.

Here are 2 of my files. What I thought would be easy isn't so easy. In the first file in the while statement there is a switch case statement. Within one of the options it check for X and O turn and blit the surface after a button event. I just need the computer to blit the surface without a button event or make it own turn.

Thanks guys for the resources. I've try them out right now.

I screwed up the formatting in these 2. Ignore and look at the reply below


#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <time.h>
#include "Game.h"
Game::Game()
{ 
cmark= IMG_Load("cmark.jpg");    
xmark= IMG_Load("xmark.jpg");    
board= IMG_Load("board.jpg");    
horizontale=IMG_Load("horizontale.jpg");    
verticale=IMG_Load("verticale.jpg");    
diagonale1=IMG_Load("diagonale1.png");    
diagonale2=IMG_Load("diagonale2.png");
}

void Game::play(SDL_Surface *screen)
{    int continuer=1, turn=0, end=0; 
position.x=0;    
position.y=0;
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255));    
SDL_BlitSurface(board, NULL, screen, &position);    
SDL_Flip(screen);
    for(i=0; i<3; i++)
    {        
	for(j=0; j<3; j++)        
	{            
	grid[i][j]=EMPTY;        
	}    }    
while(continuer)    
{        
SDL_WaitEvent(&event);        
switch(event.type)        
{        
    case SDL_QUIT:                
continuer=0;                
break;            
//Click management            
case SDL_MOUSEBUTTONDOWN:                
if(!end && grid[event.button.y/70][event.button.x/70]==EMPTY)                
{                    
positionforme.x=((event.button.x/70)*70)+15;                    
positionforme.y=((event.button.y/70)*70)+15;
   
if(turn)                    
{   //Check for circles                        

grid[event.button.y/70][event.button.x/70]=CIRCLE;                        
SDL_BlitSurface(cmark, NULL, screen, 
&positionforme);                        
SDL_Flip(screen);                        
turn=0;                    
}
//The type of AI I want is a random AI. I was going to use rand operator but I didn't have any idea for it at the time.

                    
else 
if(!turn)                    
{   //Check for X 
            
grid[event.button.y/70][event.button.x/70]=CROSS;                      
SDL_BlitSurface(xmark, NULL, screen, &positionforme);                        
SDL_Flip(screen);                        
turn=1;                    
}                
}                
break;        
}        
continuer=check_victory(screen);    }}


int Game::check_victory(SDL_Surface* screen)
{  
int 
nowinner=0;     //It verifies if there is a winner 
for(i=0; i<3; i++)
        {    
//horizontal Win Line            
if((grid[i][0]==CROSS && grid[i][1]==CROSS && grid[i][2]==CROSS) || (grid[i][0]==CIRCLE && grid[i][1]==CIRCLE && grid[i][2]==CIRCLE))            
{                
positionwon.x=20;                
positionwon.y=i*70+34;                
SDL_BlitSurface(horizontale, NULL, screen, 
&positionwon);                
SDL_Flip(screen);                
end=1;                
return 0;            
}            
//Vertical Win 
Line            
if((grid[0][i]==CROSS && grid[1][i]==CROSS && grid[2][i]==CROSS) || (grid[0][i]==CIRCLE && grid[1][i]==CIRCLE && grid[2][i]==CIRCLE))            
{                
positionwon.x=i*70+34;                
positionwon.y=20;                
SDL_BlitSurface(verticale, NULL, screen, 
&positionwon);                
SDL_Flip(screen);                
end=1;                
return 0;            
}        
}        //Diagonal Win 
Line        if((grid[0][0]==CROSS 
&& grid[1][1]==CROSS && grid[2][2]==CROSS) || 
(grid[0][0]==CIRCLE && grid[1][1]==CIRCLE && 
grid[2][2]==CIRCLE))        
{            
positionwon.x=20;            
positionwon.y=20;            
SDL_BlitSurface(diagonale1, NULL, screen, 
&positionwon);            
SDL_Flip(screen);            
end=1;            
return 0;        
}        if((grid[0][2]==CROSS && 
grid[1][1]==CROSS && grid[2][0]==CROSS) || (grid[0][2]==CIRCLE 
&& grid[1][1]==CIRCLE && 
grid[2][0]==CIRCLE))        
{            
positionwon.x=22;            
positionwon.y=20;            
SDL_BlitSurface(diagonale2, NULL, screen, 
&positionwon);            
SDL_Flip(screen);            
end=1;            
return 0;        
}        for(i=0; i<3; 
i++)        
{            for(j=0; 
j<3; 
j++)            
{                
if(grid[i][j]!=EMPTY)                
{                    
nowinner++;                
}            
}        
}        
if(nowinner==9)        
{            
end=1;            
return 0;        
}        return 1;}
Game::~Game(){    
SDL_FreeSurface(horizontale);    
SDL_FreeSurface(verticale);    
SDL_FreeSurface(diagonale1);    
SDL_FreeSurface(diagonale2);    
SDL_FreeSurface(xmark);    SDL_FreeSurface(cmark);}

#ifndef GAME_H_INCLUDED#define GAME_H_INCLUDED
enum {EMPTY, CIRCLE, CROSS};class Game{    
public:        
Game();        void play(SDL_Surface* 
screen);        int 
check_victory(SDL_Surface* 
screen);        ~Game();
    private:        
SDL_Surface *board, *cmark, *xmark, *horizontale, *verticale, *diagonale1, 
*diagonale2;        SDL_Event 
event;        int grid[3][3], continuer, 
i, j, turn, end, nowinner;        
SDL_Rect position, positionforme, positionwon;};
#endif // GAME_H_INCLUDED

Well, this is my first opportunity to experiment with this new subject I am looking into called Fuzzy Logic. And actually, I have been making an AI system that does stuff based on senses like sight and hearing, and touch. But this type of intellectual intelligence I haven't considered.

Yet, it seems that this is the perfect scenario to use Fuzzy Logic in. I am actually just now getting ready to write a program that implements fuzzy logic, perhaps I can use tic-tac-toe as a test case.

They call me the Tutorial Doctor.


#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <time.h>
#include "Game.h"

Game::Game()
{
    cmark= IMG_Load("cmark.jpg");
    xmark= IMG_Load("xmark.jpg");
    board= IMG_Load("board.jpg");
    horizontale=IMG_Load("horizontale.jpg");
    verticale=IMG_Load("verticale.jpg");
    diagonale1=IMG_Load("diagonale1.png");
    diagonale2=IMG_Load("diagonale2.png");
}
void Game::play(SDL_Surface *screen)
{
    int continuer=1, turn=0, end=0;
    position.x=0;
    position.y=0;
    SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255));
    SDL_BlitSurface(board, NULL, screen, &position);
    SDL_Flip(screen);
    for(i=0; i<3; i++)
    {
        for(j=0; j<3; j++)
        {
            grid[i][j]=EMPTY;
        }
    }
    while(continuer)
    {
        SDL_WaitEvent(&event);
        switch(event.type)
        {
            case SDL_QUIT:
                continuer=0;
                break;
            //Click management
            case SDL_MOUSEBUTTONDOWN:
                if(!end && grid[event.button.y/70][event.button.x/70]==EMPTY)
                {
                    positionforme.x=((event.button.x/70)*70)+15;
                    positionforme.y=((event.button.y/70)*70)+15;//
                    
					
					
					if(turn)
                    {   //Check for circles turn
                        grid[event.button.y/70][event.button.x/70]=CIRCLE;
                        SDL_BlitSurface(cmark, NULL, screen, &positionforme);
                        SDL_Flip(screen);
                        turn=0;
                    }

//The type of AI I want is a random AI. I was going to use rand operator but I didn't have any idea for it at the time.
//Goodluck and thank you very much for this support

                    else if(!turn)
                    {   //Check for X turn
                        grid[event.button.y/70][event.button.x/70]=CROSS;                      						
						SDL_BlitSurface(xmark, NULL, screen, &positionforme);
                        SDL_Flip(screen);
                        turn=1;
                    }
                }
                break;
        }
        continuer=check_victory(screen);
    }
}

int Game::check_victory(SDL_Surface* screen)
{
    int nowinner=0;
     //It verifies if there is a winner
        for(i=0; i<3; i++)
        {    //horizontal Win Line
            if((grid[i][0]==CROSS && grid[i][1]==CROSS && grid[i][2]==CROSS) || (grid[i][0]==CIRCLE && grid[i][1]==CIRCLE && grid[i][2]==CIRCLE))
            {
                positionwon.x=20;
                positionwon.y=i*70+34;
                SDL_BlitSurface(horizontale, NULL, screen, &positionwon);
                SDL_Flip(screen);
                end=1;
                return 0;
            }
            //Vertical Win Line
            if((grid[0][i]==CROSS && grid[1][i]==CROSS && grid[2][i]==CROSS) || (grid[0][i]==CIRCLE && grid[1][i]==CIRCLE && grid[2][i]==CIRCLE))
            {
                positionwon.x=i*70+34;
                positionwon.y=20;
                SDL_BlitSurface(verticale, NULL, screen, &positionwon);
                SDL_Flip(screen);
                end=1;
                return 0;
            }
        }
        //Diagonal Win Line
        if((grid[0][0]==CROSS && grid[1][1]==CROSS && grid[2][2]==CROSS) || (grid[0][0]==CIRCLE && grid[1][1]==CIRCLE && grid[2][2]==CIRCLE))
        {
            positionwon.x=20;
            positionwon.y=20;
            SDL_BlitSurface(diagonale1, NULL, screen, &positionwon);
            SDL_Flip(screen);
            end=1;
            return 0;
        }
        if((grid[0][2]==CROSS && grid[1][1]==CROSS && grid[2][0]==CROSS) || (grid[0][2]==CIRCLE && grid[1][1]==CIRCLE && grid[2][0]==CIRCLE))
        {
            positionwon.x=22;
            positionwon.y=20;
            SDL_BlitSurface(diagonale2, NULL, screen, &positionwon);
            SDL_Flip(screen);
            end=1;
            return 0;
        }
        for(i=0; i<3; i++)
        {
            for(j=0; j<3; j++)
            {
                if(grid[i][j]!=EMPTY)
                {
                    nowinner++;
                }
            }
        }
        if(nowinner==9)
        {
            end=1;
            return 0;
        }
        return 1;
}

Game::~Game()
{
    SDL_FreeSurface(horizontale);
    SDL_FreeSurface(verticale);
    SDL_FreeSurface(diagonale1);
    SDL_FreeSurface(diagonale2);
    SDL_FreeSurface(xmark);
    SDL_FreeSurface(cmark);
}

#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED

enum {EMPTY, CIRCLE, CROSS};
class Game
{
    public:
        Game();
        void play(SDL_Surface* screen);
        int check_victory(SDL_Surface* screen);
        ~Game();

    private:
        SDL_Surface *board, *cmark, *xmark, *horizontale, *verticale, *diagonale1, *diagonale2;
        SDL_Event event;
        int grid[3][3], continuer, i, j, turn, end, nowinner;
        SDL_Rect position, positionforme, positionwon;
};


#endif // GAME_H_INCLUDED

MUCH MUCH Better! Sorry I had formatting problems. Man it just one problem after another today

This topic is closed to new replies.

Advertisement