这是一个跳棋游戏。请参阅旧版代码的修订历史记录。
private static Move GetBestMove(Color color, Board board, int depth)
{
var bestMoves = new List<Move>();
var validMoves = board.GetValidMoves(color);
int highestScore = int.MinValue;
Board boardAfterMove;
int tmpScore;
var rand = new Random();
Debug.WriteLine("{0}'s Moves:", color);
foreach (var move in validMoves)
{
boardAfterMove = board.Clone().ApplyMove(move);
if(move.IsJump && !move.IsCrowned && boardAfterMove.GetJumps(color).Any())
tmpScore = NegaMax(color, boardAfterMove, depth);
else
tmpScore = -NegaMax(Board.Opposite(color), boardAfterMove, depth);
Debug.WriteLine("{0}: {1}", move, tmpScore);
if (tmpScore > highestScore)
{
bestMoves.Clear();
bestMoves.Add(move);
highestScore = tmpScore;
}
else if (tmpScore == highestScore)
{
bestMoves.Add(move);
}
}
return bestMoves[rand.Next(bestMoves.Count)];
}
private static int NegaMax(Color color, Board board, int depth)
{
var validMoves = board.GetValidMoves(color);
int highestScore = int.MinValue;
Board boardAfterMove;
if (depth <= 0 || !validMoves.Any())
return BoardScore(color, board);
foreach (var move in validMoves)
{
boardAfterMove = board.Clone().ApplyMove(move);
if(move.IsJump && !move.IsCrowned && boardAfterMove.GetJumps(color).Any())
highestScore = Math.Max(highestScore, NegaMax(color, boardAfterMove, depth));
else
highestScore = Math.Max(highestScore, -NegaMax(Board.Opposite(color), boardAfterMove, depth - 1));
}
return highestScore;
}
private static int BoardScore(Color color, Board board)
{
if (!board.GetValidMoves(color).Any()) return -1000;
return board.OfType<Checker>().Sum(c => (c.Color == color ? 1 : -1) * (c.Class == Class.Man ? 2 : 3));
}
我正在尝试深度为0,并且大约一半比赛的分数是正确的,然后突然间它开始搞砸了。其中一名球员将开始宣称他的得分高于实际得分。为什么它只适用于半场比赛?!
答案 0 :(得分:2)
有趣的方法,我第一次看到MaxiMax。但我在这里看到一个问题:
var minMove = GetBestMove(... board.Clone().ApplyMove(move), ...);
float score = ... BoardScore(color, board.Clone().ApplyMove(minMove));
在此代码中,move
和minMove
是针对不同方面的移动,但您在此处同等地应用它们。第二行应该是这样的:
float score = ... BoardScore(... board.Clone().ApplyMove(move).ApplyMove(minMove));
您当然可以存储和重复使用board.Clone().ApplyMove(move)
部分。
但是你仍然没有松散的信息:在深度100你过滤掉了最好的boardScore在深度99,但你没有/使用98..0级别的任何东西,除非没有移动(null),但是当你注意到自己那部分出了问题。
试着看着一些伪 算法,但所有似乎都返回 得分。这让我感到困惑,因为我 真的不想得分 我希望得到一个回归。
不过,这是要走的路。树搜索的主要结果是最佳分支的值。此举本身只是根本层面必不可少的。保留它直到你开始实现alpha / beta,然后你就可以将最好的分支存储在一个表中。
我建议切换到常规的NegaMax,
另见this SO question。
答案 1 :(得分:0)
发现错误:What could cause this to start miscalculating after awhile?
新代码:
private static Move GetBestMove(Color color, Board board, int depth)
{
var bestMoves = new List<Move>();
IEnumerable<Move> validMoves = board.GetValidMoves(color);
int highestScore = int.MinValue;
Board boardAfterMove;
int tmpScore;
var rand = new Random();
Debug.WriteLine("{0}'s Moves:", color);
foreach (Move move in validMoves)
{
boardAfterMove = board.Clone().ApplyMove(move);
if (move.IsJump && !move.IsCrowned && boardAfterMove.GetJumps(color).Any())
tmpScore = NegaMax(color, boardAfterMove, depth);
else
tmpScore = -NegaMax(Board.Opposite(color), boardAfterMove, depth);
Debug.WriteLine("{0}: {1}", move, tmpScore);
if (tmpScore > highestScore)
{
bestMoves.Clear();
bestMoves.Add(move);
highestScore = tmpScore;
}
else if (tmpScore == highestScore)
{
bestMoves.Add(move);
}
}
return bestMoves[rand.Next(bestMoves.Count)];
}
private static int NegaMax(Color color, Board board, int depth)
{
IEnumerable<Move> validMoves = board.GetValidMoves(color);
int highestScore = int.MinValue;
Board boardAfterMove;
if (depth <= 0 || !validMoves.Any())
return BoardScore(color, board);
foreach (Move move in validMoves)
{
boardAfterMove = board.Clone().ApplyMove(move);
if (move.IsJump && !move.IsCrowned && boardAfterMove.GetJumps(color).Any())
highestScore = Math.Max(highestScore, NegaMax(color, boardAfterMove, depth));
else
highestScore = Math.Max(highestScore, -NegaMax(Board.Opposite(color), boardAfterMove, depth - 1));
}
return highestScore;
}
private static int BoardScore(Color color, Board board)
{
if (!board.GetValidMoves(color).Any()) return -1000;
return board.OfType<Checker>().Sum(c => (c.Color == color ? 1 : -1) * (c.Class == Class.Man ? 2 : 3));
}
我并不是100%确信这完美无缺。它似乎适用于深度0,通常深度为1 ......除此之外,我不知道计算机在想什么。仍然似乎没有超级聪明地发挥。
编辑:运行此速度和最高速度... NegaMax代理与随机。 NegaMax总能获胜。观看“1000”出现的分数。在那之后他总是在几圈之内获胜,所以它似乎确实起作用了,最后!