AI 2 - Game Playing (Artificial intelligence)

CODE 3

AI - Game PLaying (CODE-3)

Now we are going to code the main source file.
first add the following code.

#include&ltwindows.h>// for setting the console cursor positon

void gotoxy(int,int);

#include<iostream.h> // Console Input / Output
void PrintBoard(int,int);

#include"State.h" // State Class and State Constants
#include"TLList.h" // Linked List (storeage)

// Current Real State.
CState RealState;

// function prototypes
void MainLoop();
void HumanMove();
void ComputerMove();
double Think(int);
void cls();

The above is just the include list, function prototypes and global objects. Now we need to code the following functions

  • void main() Display a welcome message, and set a game in motion
  • void MainLoop() Loop between human and computer move, until the game is over
  • void HumanMove() get input from the human, and make the requested move
  • void ComputerMove() allow the computer to think, then make a move
  • double Think(int n) evalute game outcome if the next move is n
  • void PrintBoard(int x, int y) print the board to the screen
  • void gotoxy(int x, int y) set console cursor position
  • void cls() clear the screen

Lets strt with the simple functions
void cls() {
    system("cls");
}

void gotoxy(int x, int y) {

    COORD Position = {x,y};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Position);
}

void PrintBoard(int x, int y) {

    RealState._PrintBoard(x,y);
}

Now for the main loop
While the game is not over (the state is not a draw, and not a win)
Print the board to the screen, then call Human move or computer move, depending on who's turn it is void MainLoop() {

    char UserInput=0;

    while(!(RealState.IsDraw() || RealState.IsWin())) {

        cls();
        if(RealState.GetThisMove() == ComputerMarker) {
            PrintBoard(0,5);
            HumanMove();
        }
        else {
            PrintBoard(0,5);
            ComputerMove();
        }
    }

    // end of game !
}

Now the Human move.Prompt the user for input, validate the input (make sure the move is legal)Once a valid responce has been entered, perform the move void HumanMove() {

    int UserInput=0;
    bool Valid=false;

    gotoxy(0,0);
    cout << "Your Move" << endl;

    while(!Valid) {
        gotoxy(0,1);
        cout << "Where you Wanna go ? :";
        cin >> UserInput;

        if(UserInput < 9 && UserInput >=0) {
            if(RealState.IsMoveLegal(UserInput)) {
                Valid = true;
            }
            else {
                cout << "Invalid Move !" << endl;
            }
        }
        else {
            cout << "Invalid Move !" << endl;
        }
    }
    RealState.MakeMove(UserInput);
}

ComputerMove()
This function Thinks about every possible next move, then selects the next move which returned the highest score and performs it on the main board void ComputerMove() {

    int n=0;
    double HighScore = 0; // Lower than the lowest possible average.
    int HighMove = 0;
    double Results[9] = {0,0,0,0,0,0,0,0,0};

    gotoxy(0,0);

    cout << "My Move\nThinking...." << endl;

    for(n=0; n<9; n++) {
        Results[n] = Think(n); // think about all possible next moves
    }

    gotoxy(0,15);
    // which is the Highest legal move ???
    for(n=0; n<9; n++) {
        if((HighScore < Results[n]) && RealState.IsMoveLegal(n)) {
            HighScore = Results[n];
            HighMove = n;
        }
    }

    gotoxy(0,2);
    cout << "I will move to " << HighMove << endl;
    Sleep(1500);
    RealState.MakeMove(HighMove);
}

Think(int n): This function is the most important part of the AI.
It basically takes current state of the game, and expends to all the possible end game outcomes that could occus if the computer made the move 'n' from the current game state. It then remembers all the end game states, and calls their passback() function, triggering the domino effect within the objects (they all calll there parents passback(n) function) When the minni-max algorithm is finished, we simply return the score at the top of the tree ([the currentgame + n] move state). here is how it is done double Think(int n) {

    // data needs to STAY in memory, (no poping, only pushing)
    // instead of poping from the left, simply move the left read-from position
    // and use the overloaded [] operator for retrieving states

    double LeftReadPoint = 0; // start at very left

    CLList&ltCState&gt List;
    CLList&ltCState*>Terminal;
    // initiate current state to equal global real state
    CState Current(&RealState, n);

    // move is not legal, exit function
    if(!RealState.IsMoveLegal(n)) { return 0; }

    // set parent to 0, this is the top of the list
    Current.setParent(0); // stop passing back here

    // add the inital state to the expansion list
    List.Push(Current, Right);

    // continue while there are still more states to expand
    while(LeftReadPoint < List.GetTotalLinks()) {

        // is this state a terminal state ???
        if(List[LeftReadPoint].IsDraw() || List[LeftReadPoint].IsWin()) {
            // YES, add its address to the terminal pointer for later use
            // (initiate pass back later)
            Terminal.Push(&List[LeftReadPoint], Right);
        }
        else {
            // NO, not terminal, expand it, and put its children to the list
            for(int n=0; n<9; n++) {
                // loop through possible nexy moves
                if(List[LeftReadPoint].IsMoveLegal(n)) {
                    // only expand legal moves
                    // expand state at left read pos of list
                    // use dual parameter constuctor to make new state
                    // see dual parameter constructor of state class for more info
                    List.Push(CState(&List[LeftReadPoint], n), Right);
                }
            }
        }
        // next time, read the next state in the list
        LeftReadPoint++;
    }

    // The loop has terminated, our tree is fully drawn.
    // now use all the terminal states we remembered
    // go through terminal states, starting the PassBack domino effect.

    while(Terminal.GetTotalLinks() != 0) {

        Terminal.Pop(Right)->PassBack();
    }

    // return the score at the top of the tree
    return List[0].GetMyScore();
}

Now for the main() function,
Display a welcome message, Ask who is going first, kick off the main loop, congratulate the winner, then ask if the human wants to play again, nice and easy. lol, isnt that a slogan of sum shampoo comercial ?? anyway, back on the topic. void main() {

    // re initalise CState if this is not the first game
    RealState = CState();

    char UserInput=0;

    cls();

    gotoxy(25,10);
    cout << "****************************" << endl;
    gotoxy(25,11);
    cout << "* Tic Tac Toe, By Qwijibow *" << endl;
    gotoxy(25,12);
    cout << "****************************" << endl;
    gotoxy(0,0);

    Sleep(3000);

    // loop forever
    while(1) {

        RealState = CState(); // reinitalise

        cls();

        // loop until the human enters a valid character         while(UserInput != 'C' && UserInput != 'c' && UserInput != 'H' && UserInput != 'h') {
            cout << "Who is going to go first ? Human or Computer (H/C):";
            cin >> UserInput;
        }

        cls();

        // set up the real state for the first player         if(UserInput == 'C' || UserInput == 'c') {
            RealState.SetThisMove(HumanMarker);
        }
        else {
            RealState.SetThisMove(ComputerMarker);
        }

        // main loop, the game plays out
        MainLoop();
        // the game is now over
        PrintBoard(0,5);

        gotoxy(0,12);

        // congratulate the winner         if(RealState.IsDraw()) {
            cout << "A Draw" << endl;
        }
        else {
            if(RealState.GetThisMove() == HumanMarker) {
                cout << "You Win" << endl;
            }
            else {
                cout << "I Win" << endl;
            }
        }

        cout << "Wanna play again ??? (Y/N): ";

        cin >> UserInput;

        if(UserInput=='N' || UserInput == 'n') {
            // the human gives up, terminate forever loop             break;
        }
    }
}

1 more page, the conclusion

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.

“Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.” - Rich Cook