AI 2 - Game Playing (Artificial intelligence)

CODE 2

AI - Game PLaying (CODE-2)

CState, the class that holds the methods and data involved in manipulating the playing board.

This Class contains the following functions, and data.(source code is shown later)

  • char ThisMove; contains either HumanMarker constant, or ComputerMarker Constant. and shows which player made the last move.
  • char Grid[9]; constains an array representing the playing board, here is a chart showing each positions array index number.
    012
    345
    678
  • CState *Parent; pointer the the state from which this one was spawned
  • int MyScore; Holds the score assigned to this state
  • int NumOfChildren; Holds the number of child states spawned from this state
  • int ChildrenReported; Hold the number of children which have been assigned a score. remember what i said earlyer, we only pass back our score when all of our children have been assigned a score, to test for this we need to know how many children we have, and how many of them have been assigned a score
  • void _PrintBoard(int x, int y) Simply outputs the board to the screen at coordinates x,y
  • CState() zero parameter constructor, set all variables to default
  • CState(CState* Pter, int MoveToGrid) double parameter constructor, make an exact copy of Pter, then apply move MoveToGrid
  • int GetMyScore() Return the score assigned to this state
  • char GetThisMove() Return the constant of whoever made this move
  • void IncNumOfChildren() increment the NumOfChildren
  • bool IsDraw() Return true if this state is terminal, and there is no winner.
  • bool IsMoveLegal(int n) return false if grid[n] is not blank.
  • bool IsWin() return true if this some1 has won.
  • void MakeMove(int n) move whoever's turn it is marker to grid[n]
  • void PassBack() initiate the minni-max scoreing algorithm.
  • void PassBack(int TheScore)Part of the minni-max scoreing algorithm.
  • void setParent(CState *Pter)For accessing the parent pointer from outside the class.
  • void SetThisMove(char Who) for setting who is going first.
SOURCE CODE (State.h)

const char EmptyMarker = ' ';// drawn in empty spaces
const char HumanMarker = 'O';// drawn in human owned spaces
const char ComputerMarker = 'X';// drawn in computer owned spaces

const int HumanWinScore = 0;// score awarded for lose
const int DrawScore = 50;// score awarded for draw
const int ComputerWinScore = 100;// score awarded for win

class CState {

private:

    char Grid[9];
    char ThisMove;

    CState *Parent;
    int NumOfChildren;
    int MyScore;
    int ChildrenReported;

public:

    void setParent(CState *Pter) {
        Parent = Pter;
    }

    int GetMyScore() {
        return MyScore;
    }

    void MakeMove(int n) {

    // switch ThisMove variable
        if(ThisMove == HumanMarker) {
            ThisMove = ComputerMarker;
        }
        else {
            ThisMove = HumanMarker;
        }
        Grid[n] = ThisMove;
    }

    void SetThisMove(char Who) {
        ThisMove = Who;
    }

    char GetThisMove() {
        return ThisMove;
    }

    CState() {
        // Standard Initiator. (set everything to default)

        MyScore = HumanWinScore - 1;
        NumOfChildren = 0;

        Parent = 0;
        ChildrenReported = 0;

        ThisMove = HumanMarker;
        for(int n=0; n<9; n++) {
            Grid[n] = EmptyMarker;
        }
    }

    bool IsMoveLegal(int n) {
        return Grid[n] == EmptyMarker;
    }

    bool IsWin() {
        if(((Grid[0] == Grid[1]) && (Grid[1] == Grid[2]) && (Grid[2] != EmptyMarker)) ||
        ((Grid[3] == Grid[4]) && (Grid[4] == Grid[5]) && (Grid[5] != EmptyMarker)) ||
        ((Grid[6] == Grid[7]) && (Grid[7] == Grid[8]) && (Grid[8] != EmptyMarker)) ||
        ((Grid[0] == Grid[3]) && (Grid[3] == Grid[6]) && (Grid[6] != EmptyMarker)) ||
        ((Grid[1] == Grid[4]) && (Grid[4] == Grid[7]) && (Grid[7] != EmptyMarker)) ||
        ((Grid[2] == Grid[5]) && (Grid[5] == Grid[8]) && (Grid[8] != EmptyMarker)) ||
        ((Grid[0] == Grid[4]) && (Grid[4] == Grid[8]) && (Grid[8] != EmptyMarker)) ||
        ((Grid[2] == Grid[4]) && (Grid[4] == Grid[6]) && (Grid[6] != EmptyMarker)) ){

            if(ThisMove == ComputerMarker) {
                MyScore = ComputerWinScore;
            }
            else {
                MyScore = HumanWinScore;
            }

            return true;
        }
        else {
            return false;
        }
    }

    bool IsDraw() {

        if(IsWin()) {
            return false;
        }
        else {
            for(int n=0; n<9; n++) {
                if(Grid[n] == EmptyMarker) { return false;}
            }
            MyScore = DrawScore;
            return true;
        }
    }

    void IncNumOfChildren() {
        NumOfChildren++;
    }

    CState(CState* Pter, int MoveToGrid) {

        // make equal to Pter state
        *this = *Pter;

        MyScore = HumanWinScore - 1;
        NumOfChildren = 0;
        ChildrenReported = 0;

        // Make the move
        MakeMove(MoveToGrid);

        Parent = Pter;
        Pter->IncNumOfChildren();

    }

    void _PrintBoard(int x, int y) {

        gotoxy(x,y);
        cout << Grid[0] << '|' << Grid[1] << '|' << Grid[2] << endl;
        gotoxy(x,y+1);
        cout << "-----" << endl;
        gotoxy(x,y+2);
        cout << Grid[3] << '|' << Grid[4] << '|' << Grid[5] << endl;
        gotoxy(x,y+3);
        cout << "-----" << endl;
        gotoxy(x,y+4);
        cout << Grid[6] << '|' << Grid[7] << '|' << Grid[8] << endl;
        cout << endl;
    }

    void PassBack() {
        if(Parent != 0) { Parent->PassBack(MyScore); }
    }

    void PassBack(int TheScore) {

        ChildrenReported++;

        // minnimise, or maximise ?
        if(ThisMove == HumanMarker) {
        if(TheScore >= MyScore) { MyScore = TheScore; }
        }
        else {
            if(TheScore <= MyScore) { MyScore = TheScore; }
        }

        if(MyScore == HumanWinScore - 1) {
            MyScore = TheScore;
        }

        if((NumOfChildren == ChildrenReported) && Parent != 0) {
            Parent->PassBack(MyScore);
        }
    }
};

As you can see, this class contains all of the same functionality as the State class from the first AI tutorial, with the exception of the PassBack() functions (which is the implementation of the minni-max algorithm). Remember the scary theory bit about them, well here is a nice explanation of the simple code...

void PassBack() {
    // After a list of terminal states has been generated and assigned a score,
    // loop through them all calling this function.
    // Basically, if this state has a parent (which it will)
    // call its parents passback function, and pass this states score as a parameter.
    // the if stateman it basically there to follow the 1st commandment.
    // Thou Shalt Not Follow The NULL Pointer !!!!
    if(Parent != 0) { Parent->PassBack(MyScore); }
}

void PassBack(int TheScore) {

    // 1 of our children called this function, record this
    ChildrenReported++;

    // minnimise, or maximise ?
    if(ThisMove == HumanMarker) {
        if(TheScore >= MyScore) { MyScore = TheScore; }
    }
    else {
        if(TheScore <= MyScore) { MyScore = TheScore; }
    }

    // if the myscore is still at its default value, assign it NOW !
    if(MyScore == HumanWinScore - 1) {
        MyScore = TheScore;
    }

    //if all children have reported, and a parent exists, Pass back again
    if((NumOfChildren == ChildrenReported) && Parent != 0) {
        Parent->PassBack(MyScore);
    }
}

See, this whole minni max isnt anything special, on the next page, we will code the main source file, wich will make all this class code work

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Owning a computer without programming is like having a kitchen and using only the microwave oven” - Charles Petzold