私はイタリア人なので、英語が下手で申し訳ありません。
私は C# でチェス ゲームの完全な実装、Player vs Player、Player vs Computer を書いていますが、今は NegaMax アルゴリズムの実装に苦労しています。興味のある方は、こちらが私の github リポジトリです: https://github.com/crybot/ChessEngine_NOGUI/tree/master/Chess%20Engine%20-%20NOGUI
私はこのプロジェクトを可能な限り OO にしようと試みたので、私の設計が間違っていると思われる場合は教えてください :)
ここに私の問題があります:
すべてのプレイヤーに対して対称的に機能する非常に単純な評価関数を実装しました。
public static float Evaluate(PieceColor playerColor, Game game)
{
float score = 0;
score += 1 * (game.board.GetNumberOfPieces(PieceType.Pawn, playerColor)
- game.board.GetNumberOfPieces(PieceType.Pawn, playerColor.GetOpposite()));
score += 3 * (game.board.GetNumberOfPieces(PieceType.Bishop, playerColor)
- game.board.GetNumberOfPieces(PieceType.Bishop, playerColor.GetOpposite()));
score += 3 * (game.board.GetNumberOfPieces(PieceType.Knight, playerColor)
- game.board.GetNumberOfPieces(PieceType.Knight, playerColor.GetOpposite()));
score += 5 * (game.board.GetNumberOfPieces(PieceType.Rook, playerColor)
- game.board.GetNumberOfPieces(PieceType.Rook, playerColor.GetOpposite()));
score += 9 * (game.board.GetNumberOfPieces(PieceType.Queen, playerColor)
- game.board.GetNumberOfPieces(PieceType.Queen, playerColor.GetOpposite()));
score += 0.1f * (game.GetPlayer(playerColor).GetMoves(game).Count);
return score;
}
そして、ここに私の NegaMax 関数があります。この関数は、Game パラメーター (ボード、プレーヤー、ecc.ecc を含む)、enum によって提供される playerColor、および深度検索を受け入れます。
まず、EnginePlayer のすべての可能な動きをスキャンしてから、NegaMax 関数からスコアを取得しますが、何かが機能していません...
private float NegaMax(Game game, PieceColor playerColor, int depth)
{
if (depth == 0)
return EvaluateMove(playerColor, game);
float max = float.MinValue;
float score;
foreach (Move move in game.GetPlayer(playerColor.GetOpposite()).GetMoves(game))
{
game.board.SimulateMove(move);
score = Math.Max(max, -NegaMax(game, playerColor.GetOpposite(), depth - 1));
game.board.CancelMove(move);
if (score > max)
max = score;
}
return max;
}
public Move ThinkMove(Game game, PieceColor playerColor, int depth)
{
Move bestMove = new NullMove();
float bestScore = float.MinValue;
float temp = 0;
foreach (Move move in GetMoves(game))
{
game.board.SimulateMove(move);
temp = NegaMax(game, playerColor, depth);
game.board.CancelMove(move);
if (temp > bestScore)
{
if (Judge.IsLegal(move, game))
{
bestMove = move;
bestScore = temp;
}
}
}
if (bestMove is NullMove)
throw new NotImplementedException();
return bestMove;
}
これですべてだと思います...私が間違っていることを見つけていただければ幸いです:)ありがとう。
編集: ムーブ ジェネレーターの不正解を示す Perft を実装しました。比較的見つけやすいバグを見つけるのに大いに役立ちましたが、最終的にいくつかの結果はまだ間違っています。結果は次のとおりです。
Perft Depth: 1
Nodes: 20 Captures: 0 Checks: 0 Castles: 0 Mates: 0 EnPassant: 0
Perft Depth: 2
Nodes: 400 Captures: 0 Checks: 0 Castles: 0 Mates: 0 EnPassant: 0
Perft Depth: 3
Nodes: 8902 Captures: 34 Checks: 12 Castles: 0 Mates: 0 EnPassant: 0
Perft Depth: 4
Nodes: 197281 Captures: 1610 Checks: 473 Castles: 0 Mates: 8 EnPassant: 0
正しい結果は次のとおりです: https://chessprogramming.wikispaces.com/Perft+Results
ご覧のように、深さ 4 では正しいノードが分析されますが、キャプチャとチェックの値は正しくありません (メイトは正しいのに)。
これらの結果のおかげで、深さ 4 で移動ごとに分析されたノードを分割することでバグを分離しようとしました。これらの結果が得られました。
Move Nodes
a2a3 8457
a2a4 9329
b2b3 9345
b2b4 9332
c2c3 9272
c2c4 9744
d2d3 11959
d2d4 12435
e2e3 13134
e2e4 13160
f2f3 8457
f2f4 8929
g2g3 9345
g2g4 9328
h2h3 8457
h2h4 9329
b1a3 8885
b1c3 9755
g1f3 9748
g1h3 8881
Total Nodes: 197281
そして、Sharper から取得したこれらの結果と比較します。
Sharper v0.17 by Albert Bertilsson
divide 4
b1c3 9755
b1a3 8885
g1h3 8881
g1f3 9748
a2a3 8457
a2a4 9329
b2b3 9345
b2b4 9332
c2c3 9272
c2c4 9744
d2d3 11959
d2d4 12435
e2e3 13134
e2e4 13160
f2f3 8457
f2f4 8929
g2g3 9345
g2g4 9328
h2h3 8457
h2h4 9329
Nodes: 197281
Moves: 20
しかし、ここでも値は正しいです...だから私はそれらの結果を得るための深さ5のperftを試しました:
Move Nodes
a2a3 181046
a2a4 217813
b2b3 215255
b2b4 216110
c2c3 222861
c2c4 240044
d2d3 328511
d2d4 361753
e2e3 402988
e2e4 405348
f2f3 178891
f2f4 198437
g2g3 217210
g2g4 214017
h2h3 181044
h2h4 218810
b1a3 198572
b1c3 234656
g1f3 233491
g1h3 198502
Total Nodes: 4865359
次に、Sharper の結果と比較します。
Sharper v0.17 by Albert Bertilsson
divide 5
b1c3 234656
b1a3 198572
g1h3 198502
g1f3 233491
a2a3 181046
a2a4 217832
b2b3 215255
b2b4 216145
c2c3 222861
c2c4 240082
d2d3 328511
d2d4 361790
e2e3 402988
e2e4 405385
f2f3 178889
f2f4 198473
g2g3 217210
g2g4 214048
h2h3 181044
h2h4 218829
Nodes: 4865609
Moves: 20
それで、ポーンのダブルプッシュによって生成された動きが問題の原因であることに気付きました...しかし、実際にはバグを見つけることができません... 誰か同じ問題がありましたか? または同様のもの、またはそのバグを見つけるための単なるヒント...
ありがとうございます :)