我正在尝试将minimax算法实施到井字游戏中,在该游戏中计算机将基于minimax算法播放最佳动作。我已经编写了整个算法,但是AI产生了奇怪且看似随机的动作。例如,当井字游戏板 的布局如图所示:
' ' 'o' 'x' ' ' 'o' ' ' 'x' ' ' ' '
然后,Minimax算法选择第一个位置,这显然不是最佳选择:
'o' 'o' 'x' ' ' 'o' ' ' 'x' ' ' ' '
这是我的代码:
namespace MinimaxAlg
{
class Program
{
static void Main(string[] args)
{
char[,] board = { { '-', 'o', 'x'},
{ '-', 'o', '-'},
{ 'x', '-', '-'} };
int bestScore = int.MinValue;
int moveI = -1;
int moveJ = -1;
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 3; j++)
{
if (board[i, j] == '-')
{
board[i, j] = 'o';
var score = Minimax(board, 'o');
board[i, j] = '-';
Console.WriteLine("Score: " + score);
Console.WriteLine("BestScore: " + bestScore);
if (score > bestScore)
{
bestScore = score;
moveI = i;
moveJ = j;
}
}
}
}
board[moveI, moveJ] = 'p';
foreach (var i in board)
{
Console.WriteLine(i);
}
}
static int Minimax(char[,] board, char forWho)
{
if (CheckWhoWins(board, forWho))
{
return 1;
}
if (forWho == 'o')
{
var bestScore = int.MinValue;
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 3; j++)
{
if (board[i, j] == '-')
{
board[i, j] = forWho;
var score = Minimax(board, 'x');
board[i, j] = '-';
bestScore = Math.Max(bestScore, score);
}
}
}
return bestScore;
}
else
{
var bestScore = int.MaxValue;
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 3; j++)
{
if (board[i, j] == '-')
{
board[i, j] = forWho;
var score = Minimax(board, 'o');
board[i, j] = '-';
bestScore = Math.Min(bestScore, score);
}
}
}
return bestScore;
}
}
static bool CheckWhoWins(char[,] board, char forWho)
{
if ((board[0, 0] == forWho && board[0, 1] == forWho && board[0, 2] == forWho) || (board[1, 0] == forWho && board[1, 1] == forWho && board[1, 2] == forWho) ||
(board[2, 0] == forWho && board[2, 1] == forWho && board[2, 2] == forWho) || (board[0, 0] == forWho && board[1, 0] == forWho && board[2, 0] == forWho) ||
(board[0, 1] == forWho && board[1, 1] == forWho && board[2, 1] == forWho) || (board[0, 2] == forWho && board[1, 2] == forWho && board[2, 2] == forWho) ||
(board[0, 0] == forWho && board[1, 1] == forWho && board[0, 0] == forWho) || (board[0, 2] == forWho && board[1, 1] == forWho && board[2, 0] == forWho))
return true;
else
return false;
}
}
}
如果任何人对可能出什么问题有任何想法,将不胜感激。
答案 0 :(得分:1)
您的代码中存在三个问题。
首先,一个简单的错字。您获胜的条件之一是board[0, 0] == forWho && board[1, 1] == forWho && board[0, 0] == forWho
。显然,最后一个应该是board[2, 2]
。
第二,您马上给o
两笔。这些行显示出来:
board[i, j] = 'o';
var score = Minimax(board, 'o');
第二行应为var score = Minimax(board, 'x');
。
最后,user3386109钉住了它。您要给长游戏和短游戏赋予相同的分数。
如果我们改变计分系统,以便为最少的动作提供更大的分数,那么它就可以正常工作。
static int CheckWhoWins(char[,] board, char forWho)
{
if ((board[0, 0] == forWho && board[0, 1] == forWho && board[0, 2] == forWho)
|| (board[1, 0] == forWho && board[1, 1] == forWho && board[1, 2] == forWho)
|| (board[2, 0] == forWho && board[2, 1] == forWho && board[2, 2] == forWho)
|| (board[0, 0] == forWho && board[1, 0] == forWho && board[2, 0] == forWho)
|| (board[0, 1] == forWho && board[1, 1] == forWho && board[2, 1] == forWho)
|| (board[0, 2] == forWho && board[1, 2] == forWho && board[2, 2] == forWho)
|| (board[0, 0] == forWho && board[1, 1] == forWho && board[2, 2] == forWho)
|| (board[0, 2] == forWho && board[1, 1] == forWho && board[2, 0] == forWho))
{
var score = 1;
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 3; j++)
{
if (board[i, j] == '-')
{
score++;
}
}
}
return score;
}
else
return 0;
}
Minimax
(应该只是MinMax
)现在是:
static int Minimax(char[,] board, char forWho)
{
var score = CheckWhoWins(board, forWho);
if (score != 0)
{
return score;
}
if (forWho == 'o')
{
var bestScore = int.MinValue;
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 3; j++)
{
if (board[i, j] == '-')
{
board[i, j] = forWho;
var currentScore = Minimax(board, 'x');
board[i, j] = '-';
bestScore = Math.Max(bestScore, currentScore);
}
}
}
return bestScore;
}
else
{
var bestScore = int.MaxValue;
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 3; j++)
{
if (board[i, j] == '-')
{
board[i, j] = forWho;
var currentScore = Minimax(board, 'o');
board[i, j] = '-';
bestScore = Math.Min(bestScore, currentScore);
}
}
}
return bestScore;
}
}
运行此命令可获得以下结果:
在我看来,关于奖励积分,这是Minimax
的一个更好的版本:
static int Minimax(char[,] board, char forWho)
{
var score = CheckWhoWins(board, forWho);
if (score != 0)
{
return score;
}
var bestScore = forWho == 'o' ? int.MinValue : int.MaxValue;
int CalcBest(int x, int y) => (forWho == 'o' ? x > y : y > x) ? x : y;
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 3; j++)
{
if (board[i, j] == '-')
{
board[i, j] = forWho;
var currentScore = Minimax(board, forWho == 'o' ? 'x' : 'o');
board[i, j] = '-';
bestScore = CalcBest(bestScore, currentScore);
}
}
}
return bestScore;
}