问题描述
我正在尝试将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'},{ '-','-'},{ '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,'o');
board[i,j] = '-';
bestscore = Math.Min(bestscore,score);
}
}
}
return bestscore;
}
}
static bool CheckWhoWins(char[,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[0,1] == forWho) || (board[0,2] == forWho && board[1,2] == forWho && board[2,2] == forWho) ||
(board[0,0] == forWho) || (board[0,0] == forWho))
return true;
else
return false;
}
}
}
如果任何人对可能出什么问题有任何想法,将不胜感激。
解决方法
您的代码中存在三个问题。
首先,一个简单的错字。您获胜的条件之一是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,2] == 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[0,1] == forWho)
|| (board[0,2] == forWho && board[1,2] == 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[,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,'o');
board[i,j] = '-';
bestScore = Math.Min(bestScore,currentScore);
}
}
}
return bestScore;
}
}
运行此命令可获得以下结果:
在我看来,关于奖励积分,这是Minimax
的一个更好的版本:
static int Minimax(char[,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;
}