MiniMax井字游戏AI

时间:2020-06-15 17:05:36

标签: c# unity3d artificial-intelligence tic-tac-toe minimax

我正在尝试实现MiniMax以创建TicTacToe AI。我正在使用C#和Unity。我正在关注CodingTrain's video。该教程使用JavaScript,但是我遵循C#。我曾尝试从他的网站查看MiniMax代码,但无法弄清楚为什么我的“翻译”无效:

using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{

    public SpriteRenderer[] sprites;

    char[] board = new char[] { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
    Dictionary<char, Color> boardColor = new Dictionary<char, Color>()
    {
        { ' ', Color.white },
        { 'O', Color.red },
        { 'X', Color.blue }
    };

    char ai = 'O';
    char player = 'X';

    Camera cam;
    bool gameOver = false;
    bool playerTurn;

    private void Awake()
    {
        playerTurn = Random.value > .5f;
        cam = Camera.main;
    }

    private void Start()
    {
        DrawBoard();
    }

    private void Update()
    {
        if (gameOver) return;

        if (playerTurn)
            PlayerMove();
        else
            CompMove();

        DrawBoard();

        if (IsWinner(player))
        {
            print("Good job, you won!");
            gameOver = true;
        }

        else if (IsWinner(ai))
        {
            print("Too bad, you lost!");
            gameOver = true;
        }

        else if (BoardIsFull())
        {
            print("Close one, it's a tie!");
            gameOver = true;
        }
    }

    void PlayerMove()
    {
        if (Input.GetMouseButtonDown(0))
        {
            RaycastHit2D hit = Physics2D.Raycast(cam.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);

            if (hit)
            {
                int pos = hit.transform.GetComponent<SpritePos>().pos;
                if (SpaceIsFree(pos))
                {
                    InsertLetter(player, pos);
                    playerTurn = false;
                }
            }
        }
    }

    void CompMove()
    {
        float bestScore = -Mathf.Infinity;
        int bestMove = 0;

        for (int i = 0; i < board.Length; i++)
            if(SpaceIsFree(i))
            {
                board[i] = ai;
                float score = Minimax(board, 0, false);
                board[i] = ' ';
                bestScore = Mathf.Max(score, bestScore);
                bestMove = i;
            }


        InsertLetter(ai, bestMove);
        playerTurn = true;
    }

    float Minimax(char[] board, int depth, bool isMaximizer)
    {
        if (IsWinner(ai))
            return 1;
        if (IsWinner(player))
            return -1;
        if (BoardIsFull())
            return 0;

        if (isMaximizer)
        {
            float bestScore = -Mathf.Infinity;
            for (int i = 0; i < board.Length; i++)
            {
                if (SpaceIsFree(i))
                {
                    board[i] = ai;
                    float score = Minimax(board, depth + 1, false);
                    board[i] = ' ';
                    bestScore = Mathf.Max(score, bestScore);
                }
            }
            return bestScore;
        }
        else
        {
            float bestScore = Mathf.Infinity;
            for (int i = 0; i < board.Length; i++)
            {
                if (SpaceIsFree(i))
                {
                    board[i] = player;
                    float score = Minimax(board, depth + 1, true);
                    board[i] = ' ';
                    bestScore = Mathf.Min(score, bestScore);
                }
            }
            return bestScore;
        }
    }

    void InsertLetter(char letter, int pos)
    {
        board[pos] = letter;
    }

    bool SpaceIsFree(int pos)
    {
        return board[pos] == ' ';
    }

    bool IsWinner(char letter)
    {
        return (board[0] == letter && board[1] == letter && board[2] == letter) ||
               (board[4] == letter && board[5] == letter && board[6] == letter) ||
               (board[0] == letter && board[1] == letter && board[2] == letter) ||
               (board[0] == letter && board[3] == letter && board[6] == letter) ||
               (board[1] == letter && board[4] == letter && board[7] == letter) ||
               (board[2] == letter && board[5] == letter && board[8] == letter) ||
               (board[0] == letter && board[4] == letter && board[8] == letter) ||
               (board[6] == letter && board[4] == letter && board[2] == letter);
    }

    void DrawBoard()
    {
        for (int i = 0; i < board.Length; i++)
            sprites[i].color = boardColor[board[i]];
    }

    bool BoardIsFull()
    {
        foreach (char space in board)
            if (space == ' ')
                return false;
        return true;
    }
}

它似乎始于右下角,然后每次都向左走。

1 个答案:

答案 0 :(得分:1)

如注释中所述,您没有考虑bestScore,因此bestMove始终只是循环后的最后一个空闲i

您可能宁愿做类似的事情(不必深入研究其余部分)

    void CompMove()
    {
        float bestScore = -Mathf.Infinity;
        int bestMove = 0;

        for (int i = 0; i < board.Length; i++)
        {
            if(SpaceIsFree(i))
            {
                board[i] = ai;
                float score = Minimax(board, 0, false);
                board[i] = ' ';
                if(score > bestScore)
                {
                    bestScore = score;
                    bestMove = i;
                }
            }
        }

        InsertLetter(ai, bestMove);
        playerTurn = true;
    }