简体   繁体   中英

Determine best move in tic tac toe

i want to code a recursive function to determine the best move in a given tic - tac - toe game

int nextMove(struct Game g, enum Symbol player) {
if (game_over(g) != 0) {
return -1;
}
int i, j;
int score, end;
for(i = 0; i < 3; i += 1) {
    for (j = 0; j < 3; j += 1) {
        if(g.board.fields[i][j] == 0) {
            g.board.fields[i][j] = player;
            score = nextMove(g, -player);
        }
    }
}
end = game_over(g)
}

My game_over function :

enum Symbol game_over(struct Game g)
{
int x, y = x = 0;
int full = 0;

for (y = 0; y < SIZE_Y_AXIS; y += 1)
{
    for (x = 0; x < SIZE_X_AXIS; x += 1)
    {
        if (g.board.fields[x][y] == NONE)
            full++;
        else if (x < SIZE_X_AXIS - 2 &&
                 g.board.fields[x][y] == g.board.fields[x+1][y] &&
                 g.board.fields[x][y] == g.board.fields[x+2][y])
            return g.board.fields[x][y];
        else if (y < SIZE_Y_AXIS - 2 &&
                 g.board.fields[x][y] == g.board.fields[x][y+1] &&
                 g.board.fields[x][y] == g.board.fields[x][y+2])
            return g.board.fields[x][y];
        else if (x < SIZE_X_AXIS - 2 && y < SIZE_Y_AXIS - 2 &&
                 g.board.fields[x][y] == g.board.fields[x+1][y+1] &&
                 g.board.fields[x][y] == g.board.fields[x+2][y+2])
            return g.board.fields[x][y];
        else if (x >= 2 && y < SIZE_Y_AXIS - 2 &&
                 g.board.fields[x][y] == g.board.fields[x-1][y+1] &&
                 g.board.fields[x][y] == g.board.fields[x-2][y+2])
            return g.board.fields[x][y];
    }
}
if (full == 0)
    return FULL;
return NONE;
}

I think the leaf production works fine, but i don't know how to determine which leaf (or which move) is the best one? Any suggestions by now?

Thanks

In a game like tic-tac-toe, the search tree is so small that all leaf nodes can be evaluated (unlike in a game like chess or Go where the search is cut short). Since all nodes are examined, the leaf nodes can be evaluated by checking if they are a win, lose, or draw. You can use 1,-1, and 0 respectively to represent these values. Once you do that, return the value of the node to its parent. For non-leaf nodes, it must choose either the highest value of its children, or the lowest, depending on if it is a max node (the computer) or min node (its opponent).This will back up the tree all the way to the root, giving it a value for all its possible moves. The move at the root of the tree with the highest value is the best move for that position This is the minimax algorithm. Additionally, in the code sample you provided, you failed to check if the game was over before all fields are full. Instead, check if a player has already gotten three in a row, as then the game is already over. Note:Your nextMove function claims to return an int but doesn't in most cases. That has to be fixed. Here is what I would add to your code (the added parts in psuedo-code). I am not sure exactly what the game_over function does, so I can't be sure of what the exact code should be. Therefore, I am going to take it out and add psuedocode to take its place.

int nextMove(struct Game g, enum Symbol player) {
    if (computerWon) {
    return 1;
    }
    if (OpponnentWon) {
    return -1;
    }
    if (allSquaresAreFull) {
    return 0;
    }
    int i, j;
    int bestScore;//use this to calculate which move to return
    int score, end;
    //now check whose turn it is
    if(player == 1){//I'm assuming this is the computer player
        bestScore = -100;//start with an arbitrary low value 
        for(i = 0; i < 3; i += 1) {
            for (j = 0; j < 3; j += 1) {
                if(g.board.fields[i][j] == 0) {
                    g.board.fields[i][j] = player;
                    score = nextMove(g, -player);
                    g.board.fields[i][j] = 0;//make sure to undo every move made in the search
                    if(score > bestScore){//a better move for this player
                         bestScore = score;//update bestScore
                    }
               }
           }
        }
        return bestScore;//return best move to parent;

    }
    if(player == -1){//I'm assuming this is the opponent
        bestScore = 100;//start with an arbitrary high value 
        for(i = 0; i < 3; i += 1) {
            for (j = 0; j < 3; j += 1) {
                if(g.board.fields[i][j] == 0) {
                    g.board.fields[i][j] = player;
                    score = nextMove(g, -player);
                    g.board.fields[i][j] = 0;//make sure to undo every move made in the search
                    if(score < bestScore){//a better move for the opponent is a lower move
                         bestScore = score;//update bestScore
                    }
               }
           }
        }
        return bestScore;//return best move to parent;

    }
end = game_over(g)//this variable is never used. Not sure what it does. I would remove it, it seems useless
}

This should return the value of the position(if it is won, lost, or drawn). To determine which move to take, this would have to be slightly modified. Add a test to see if we are in the first time nextMove is called (ie the root) if we are, instead of keeping track of ony bestMove, which is the value of the move, also keep track of what the actual best move is (perhaps in a move struct). Return that instead if best move. Now nextMove will return which move to take.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM