首页 > 解决方案 > C++井字游戏极小极大

问题描述

我正在尝试创建一个 c++ 无与伦比的井字游戏 AI。在看了几个关于这个话题的视频后,我想我已经明白了。屏幕上会弹出一个错误,提示“表达式:向量下标超出范围”。我相信错误来自 availableMoves() 函数。但是我不知道为什么。游戏本身运行良好。任何帮助,将不胜感激。

#include <iostream>
#include <vector>
#include <ctime>


bool in(std::vector<int> v, int element)
{
for (int i = 0; i < v.size(); i++)
{
    if (element == v[i])
    {
        return true;
    }
}

return false;
}

class Board
{
private:
char board[3][3] = { {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'} };
public:

void displayBoard()
{

    std::cout << "___________________" << std::endl;
    for (int i = 0; i < 3; i++)
    {
        std::cout << "|  ";
        for (int j = 0; j < 3; j++)
        {
            std::cout << board[i][j] << "  |  ";
        }
        std::cout << std::endl;
    }
    std::cout << "___________________" << std::endl;
}

std::vector<int> availableMoves()
{
    std::vector<int> moves;

    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            if (board[i][j] != 'X' && board[i][j] != 'O')
            {
                moves.push_back(i * 3 + j);
            }
        }
    }


    return moves;
}

void move(int choice, char mark)
{
    int y = choice / 3;
    int x = choice - y * 3;
    board[y][x] = mark;
}

void revert(int choice)
{
    int y = choice / 3;
    int x = choice - y * 3;
    board[y][x] = (char)choice + 48;
}

int checkWin()
{

    for (int i = 0; i < 3; i++)
    {
        if (board[i][0] == board[i][1] && board[i][1] == board[i][2])
        {
            if (board[i][0] == 'X')
            {
                return 1;
            }
            else if (board[i][0] == 'O')
            {
                return -1;
            }
        }
    }


    for (int i = 0; i < 3; i++)
    {
        if (board[0][i] == board[1][i] && board[1][i] == board[2][i])
        {
            if (board[0][i] == 'X')
            {
                return 1;
            }
            else if (board[0][i] == 'O')
            {
                return -1;
            }
        }
    }


    if (board[0][0] == board[1][1] && board[1][1] == board[2][2])
    {
        if (board[0][0] == 'X')
        {
            return 1;
        }
        else if (board[0][0] == 'O')
        {
            return -1;
        }
    }


    if (board[0][2] == board[1][1] && board[1][1] == board[2][0])
    {
        if (board[0][2] == 'X')
        {
            return 1;
        }
        else if (board[0][2] == 'O')
        {
            return -1;
        }
    }


    return 0;
}


int evaluate()
{


    return (checkWin() * -1) * (availableMoves().size() + 1);
}


Board& operator=(Board& b)
{
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            board[i][j] = b.board[i][j];
        }
    }
    

    return (*this);
}

};


class TicTacToe
{
private:
Board board;
int turn;
int searches = 0;
public:

TicTacToe()
{
    std::srand(time(0));
    turn = std::rand() % 2;
}

int minimax(int depth, Board curBoard, bool is_max)
{
    searches++;
    if (depth == 0 || curBoard.checkWin() != 0)
    {
        return board.evaluate();
    }

    if (is_max)
    {
        int max_eval = -2147483647;
        
        for (int i = 0; i < curBoard.availableMoves().size(); i++)
        {

            curBoard.move(curBoard.availableMoves()[i], 'O');
            depth -= 1;
            int eval = minimax(depth, curBoard, false);
            curBoard.revert(curBoard.availableMoves()[i]);
            if (eval > max_eval)
            {
                max_eval = eval;
            }
        }
        return max_eval;

    }


    if (!is_max)
    {
        int min_eval = 2147483647;
        for (int i = 0; i < curBoard.availableMoves().size(); i++)
        {
            curBoard.move(curBoard.availableMoves()[i], 'X');
            depth -= 1;
            int eval = minimax(depth, curBoard, true);
            curBoard.revert(curBoard.availableMoves()[i]);
            if (eval < min_eval)
            {
                min_eval = eval;
            }
        }
        return min_eval;

    }
}


void game()
{

    while (board.checkWin() == 0 && board.availableMoves().size() != 0)
    {
        
        board.displayBoard();
        if (turn % 2 == 0)
        {
            std::cout << std::endl;
            int choice;
            std::cout << "Enter Your Move: ";
            std::cin >> choice;
            choice -= 1;
            while (!in(board.availableMoves(), choice))
            {
                std::cout << "Enter A Valid Move: ";
                std::cin >> choice;
            }
            board.move(choice, 'X');
            std::cout << std::endl;
            turn++;
        }
        


        board.displayBoard();

        if (board.checkWin() != 0)
        {
            break;
        }

        if (turn % 2 == 1)
        {

            int ai = minimax(9 - (turn % 2), board, true);
            std::cout << searches;
            std::cin.get();
            turn++;
        }
        
        

    }


    if (board.checkWin() == 1)
    {
        std::cout << "You Won" << std::endl;
    }
    else if (board.checkWin() == -1)
    {
        std::cout << "You Lost" << std::endl;
    }
    else
    {
        std::cout << "Tie" << std::endl;
    }



    std::cout << "Would You Like To Play Again Y/N: ";
    char playAgain;
    std::cin >> playAgain;
    if (playAgain == 'Y')
    {
        Board newBoard;
        board = newBoard;
        game();
    }

}

};


int main()
{

TicTacToe ticTacToe;
ticTacToe.game();



}

标签: c++minimax

解决方案


你知道如何调试吗?如果没有,您绝对应该学习这一点,它非常有帮助。但这是我发现的一些事情。

问题不在于availableMoves(),而在于minimax(),更准确地说是在程序调用的第 215 行curBoard. revert(curBoard. availableMoves()[i])

void revert(int choice)
{
    int y = choice / 3;
    int x = choice - y * 3;
    board[y][x] = (char)choice + 48;
}

for (int i = 0; i < curBoard.availableMoves().size(); i++)
        {
            curBoard.move(curBoard.availableMoves()[i], 'X');
            depth -= 1;
            int eval = minimax(depth, curBoard, true);
            curBoard.revert(curBoard.availableMoves()[i]);
            if (eval < min_eval)
            {
                min_eval = eval;
            }
        }

错误发生在函数revert中,但我不知道为什么。也许availableMoves还会返回错误的东西。变量i在 for 循环中永久为 0。因此,向量的位置 0 可能有问题,moves无法revert处理。尝试自己调试,也许你会发现问题。


推荐阅读