NegaMax
玩跳棋。我现在只是用深度0来测试它,这意味着当前玩家只是评估他的所有动作,而不考虑其他玩家接下来会做什么。它在游戏的一半时间里都能完美地工作(正确地计算分数),然后在游戏的一半时间里,它开始吐出无意义的答案。
例如,白人可能只剩下1个棋子,黑人只有5个棋子,但它会把白人的招式评价为7分,例如,当他们都应该是负数,因为他输了。布莱克下一步可能会赢,但它会把赢的一步评为-4,尽管应该是1000。
我可以理解它一直输出垃圾,但为什么它会在最初的几圈和几周工作
然后
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)
{
return BoardScore(color, board);
}
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));
}
我在6x6板上隔离了一个它不喜欢的板状态:
. . .
. w B
W . .
. . .
. w .
. . W
w = white, b = black, capital letter = king
看来这不是一个时间或动作数发挥的问题,它只是不喜欢特定的董事会状态。不过,我看不出这个州有什么特别之处。
在这种状态下,它将Black的所有4个动作计算为-13。如果你看看我是怎么得分的,上面写着每个人2分,每个国王3分,如果被其他球员拥有的话是负数。它看起来好像把所有的碎片都当成了白色…这是得到13个碎片的唯一方法。
我发现了另一条线索。在棋盘得分法中,我让它打印出它看到的东西。。这就是它告诉我的:
2: White
4: White
6: White
13: White
17: White
00 01 02
03 04 05
06 07 08
09 10 11
12 13 14
15 16 17
所以。。。现在我知道颜色不对了,但只对了
BoardScore
功能。我正常的显示程序从来没有注意到这一点,否则我几个小时前就会发现这个问题。我想可能是在
ApplyMove
颜色切换的功能。。
public Board ApplyMove(Move m)
{
if (m.IsJump)
{
bool indented = m.Start % Width < _rowWidth;
int offset = indented ? 1 : 0;
int enemy = (m.Start + m.End) / 2 + offset;
this[m.Color, enemy] = Tile.Empty;
}
this[m.Color, m.End] = this[m.Color, m.Start];
this[m.Color, m.Start] = Tile.Empty;
var checker = this[m.Color, m.End] as Checker;
if (m.IsCrowned) checker.Class = Class.King;
return this;
}
但这也没什么意义。。。工件只是从起始位置复制到结束位置。需要调查什么
m.Color