- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
好吧,我先承认这个会有点长。我正在为 C# 编写国际象棋引擎,最终目标包括 UCI 实现。我已经做到了,给定一个棋盘,引擎将生成所有有效 Action 的列表;然而,我的评估代码似乎很挣扎,因为在与自己进行游戏时,引擎会在两边移动两个棋子,然后在两边来回移动一个棋子。我将在下面概述程序的关键部分,以便最好地让您了解我的代码在什么条件下被调用和使用,希望它能帮助您回答我的问题。
这只是我的接口(interface)调用的主要方法,这里没有什么令人兴奋的。
class BreezeEngine
{
// Declares Piece Values
public const int pawn = 1, knight = 4, bishop = 6, rook = 8, queen = 16, king = 60;
public const int toDepth = 4;
public static void BoardGen(string mode)
{
Board chessBoard = new Board(new int[8, 8] {
{ 8, 4, 6,16,60, 6, 4, 8 },
{ 1, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{-1,-1,-1,-1,-1,-1,-1,-1 },
{-8,-4,-6,-16,-60,-6,-4,-8 }
}, 0, true, true, true);
PlayGame(chessBoard, true);
return;
}
这个方法很好用。它返回带有格式的移动列表x1, y1, x2, y2, 重量此方法生成的权重是被杀死的任何部分的值。如果您有任何疑问,请告诉我。
private static List<int[]> CalcFutures(Board chessBoard)
{
// Move generation stuff.
}
此方法尚未完成(因为它不处理转换或过路),但它基本上只是从任何给定的着法生成一个新的棋盘对象。
private static Board MoveToBoard(int[] move, Board board)
{
int[,] newBoard = new int[8, 8];
Array.Copy(board.Pieces(), newBoard, 64);
newBoard[move[3], move[2]] = newBoard[move[1], move[0]];
newBoard[move[1], move[0]] = 0;
if (newBoard[move[3], move[2]] == pawn && move[3] == 7) newBoard[move[3], move[2]] = queen;
if (newBoard[move[3], move[2]] == -pawn && move[3] == 0) newBoard[move[3], move[2]] = -queen;
return new Board(newBoard, board.Depth() + 1, !board.IsTurn(), true, true);
}
这段代码可能不需要,但我将其包括在内是因为这里的拼写错误导致了错误。这只是一个非常基本的用户界面,允许我与我的引擎玩游戏,或者让引擎自己玩。
private static void PlayGame(Board chessBoard, bool demo)
{
int[] move = new int[5];
if (!(chessBoard.IsTurn() || demo))
{
Console.WriteLine("Type in your move one integer at a time: x1,y1,x2,y2");
move[0] = Convert.ToInt32(Console.ReadLine());
move[1] = Convert.ToInt32(Console.ReadLine());
move[2] = Convert.ToInt32(Console.ReadLine());
move[3] = Convert.ToInt32(Console.ReadLine());
}
else
{
Console.WriteLine("Calculating Move..." + chessBoard.IsTurn());
move = Evaluate(CalcFutures(chessBoard), chessBoard);
}
if (Math.Abs(chessBoard.Pieces()[move[3], move[2]]) == king)
{
if (chessBoard.IsTurn()) Console.Write("White Wins");
else Console.Write("Black Wins");
return;
}
chessBoard = MoveToBoard(move, chessBoard);
chessBoard.SetDepth(0);
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
Console.Write(chessBoard.Pieces()[i, j].ToString().PadLeft(3, ' '));
}
Console.WriteLine();
}
PlayGame(chessBoard, demo);
}
}
现在,在介绍评估算法本身之前,我将简要介绍一下。这是您在整个代码中多次看到的 board 对象。它包含一个棋盘数组,以及定义游戏当前状态所需的其他变量。
class Board
{
bool isTurn;
bool castling;
bool enemyCastling;
int[,] pieces = new int[8, 8];
int weight = 0;
int depth;
public Board(int[,] inBoard, int inDepth, bool inIsTurn, bool inCastling, bool inEnemyCastling)
{
Array.Copy(inBoard, pieces, 64);
isTurn = inIsTurn;
castling = inCastling;
enemyCastling = inEnemyCastling;
depth = inDepth;
}
public int Weight()
{
int sum = 0;
foreach (int i in pieces)
sum += i;
weight = sum;
return weight;
}
public int[,] Pieces() { return pieces; }
public bool IsTurn() { return isTurn; }
public void ToggleTurn() { isTurn = !isTurn; return; }
public int Depth() { return depth; }
public void SetDepth(int inDepth)
{
depth = inDepth;
}
}
现在我已经概述了程序的其余部分,下面是评估方法本身。该代码接受一个移动列表,如果它是应该搜索的最深深度,它只返回具有最大绝对值的移动。如果它没有到达底部,它会简单地生成一个 future 列表,对于它收到的 future 列表中的每一个 Action ,然后再次调用自己。然后将返回的值添加到原始移动的权重,并与迄今为止找到的最佳移动进行比较。但是,我一直对这种方法有疑问,我猜这要么是因为我误解了 negamax 应该如何工作,要么是我在某个地方打错了字。知道发生了什么事吗?
private static int[] Evaluate(List<int[]> futures, Board chessBoard)
{
int[] bestMove = new int[5];
bestMove[0] = 30;
if (chessBoard.Depth() >= toDepth)
{
foreach (int[] move in futures)
{
if (Math.Abs(move[4]) > Math.Abs(bestMove[4]))
{
Array.Copy(move, bestMove, 5);
}
}
}
else
{
foreach (int[] move in futures)
{
Board newBoard = MoveToBoard(move, chessBoard);
int[] testMove = Evaluate(CalcFutures(newBoard), newBoard);
move[4] += testMove[4];
if (bestMove[0] == 30) bestMove = move;
if (chessBoard.IsTurn())
{
if (move[4] > bestMove[4])
{
Array.Copy(move, bestMove, 5);
}
}
else
{
if (move[4] < bestMove[4])
{
Array.Copy(move, bestMove, 5);
}
}
}
}
return bestMove;
}
最佳答案
您的评估有误。你必须确保任何一方都在选择自己最好的 future 。老实说,给定您的移动数据结构,minimax 很容易实现。这是固定的评估函数。
public static int[] Evaluate(List<int[]> futures, Board chessBoard)
{
int[] bestMove = new int[5];
Random rndMove = new Random();
Array.Copy(futures[rndMove.Next(futures.Count)], bestMove, 5);
if (chessBoard.Depth() == toDepth)
{
if (chessBoard.IsTurn())
{
// Maximum
//bestMove[4] = -1000000;
foreach (int[] move in futures)
{
if (move[4] > bestMove[4])
{
Array.Copy(move, bestMove, 5);
}
}
}
else
{
// Minimum
//bestMove[4] = 1000000;
foreach (int[] move in futures)
{
if (move[4] < bestMove[4])
{
Array.Copy(move, bestMove, 5);
}
}
}
}
else
{
if (chessBoard.IsTurn())
{
// Maximum
//bestMove[4] = -1000000;
foreach (int[] move in futures)
{
if (Math.Abs(chessBoard.Pieces()[move[3], move[2]]) == king) return move;
Board newBoard = MoveToBoard(move, chessBoard);
move[4] += Evaluate(CalcFutures(newBoard), newBoard)[4];
if (move[4] > bestMove[4])
{
Array.Copy(move, bestMove, 5);
}
}
}
else
{
// Minimum
//bestMove[4] = 1000000;
foreach (int[] move in futures)
{
if (Math.Abs(chessBoard.Pieces()[move[3], move[2]]) == king) return move;
Board newBoard = MoveToBoard(move, chessBoard);
move[4] += Evaluate(CalcFutures(newBoard), newBoard)[4];
if (move[4] < bestMove[4])
{
Array.Copy(move, bestMove, 5);
}
}
}
}
//Console.WriteLine(bestMove[4]);
return bestMove;
}
关于c# - 国际象棋 negamax 算法来回移动棋子。怎么了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35214748/
只是想知道 Jquery Mobile 是否足够稳定以用于实时生产企业移动应用程序。 有很多 HTML5 框架,因为我们的团队使用 JQuery 已经有一段时间了,我们更愿意使用 Jquery 移动框
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 3 年前。 Improve t
所以我尝试在 JavaScript 中对元素进行拖放。我使用的视频教程在这里; https://www.youtube.com/watch?v=KTlZ4Hs5h80 。我已经按照它的说明进行了编码,
无法在移动 iOS(safari 和 chrome)上自动播放以前缓存的 mp3 音频 我正在 Angular 8 中开发一个应用程序,在该应用程序的一部分中,我试图在对象数组中缓存几个传入的音频 m
Git 基于内容而不是文件,所以我目前理解以下行为,但我想知道是否有特殊选项或 hack 来检测此类事情: git init mkdir -p foo/bar echo "test" foo/a.tx
我正在寻找语义 ui 正确的类来隐藏例如移动 View 中的 DIV。在 Bootstrap 中,我们有“visible-xs”和“hidden-xs”。 但是在语义ui上我只找到了“仅移动网格” 最
我正在使用 ubuntu 和 想要移动或复制大文件。 但是当我与其他人一起使用服务器时,我不想拥有所有内存并使其他进程几乎停止。 那么有没有办法在内存使用受限的情况下移动或复制文件? 最佳答案 如果你
这些指令有什么区别?以 ARM9 处理器为例,它不应该是: ASM: mov r0, 0 C: r0 = 0; ASM: ld r0, 0 C: r0 = 0; ? 我不知道为什么要使用一个或另一个:
我有一个文件夹,其中包含一些随机命名的文件,其中包含我需要的数据。 为了使用数据,我必须将文件移动到另一个文件夹并将文件命名为“file1.xml” 每次移动和重命名文件时,它都会替换目标文件夹中以前
我经常在 IB/Storyboard 中堆叠对象,几乎不可能拖动其他对象后面的对象而不移动前面的对象。无论如何我可以移动已经选择但位于其他对象后面的对象吗?当我尝试移动它时,它总是选择顶部的对象,还是
几个月前,我看到 Safari 7 允许推送通知,它似乎是一个非常有用的工具,除了我看到的每个示例都专注于桌面浏览,而不是移动设备。 Safari 推送通知是否可以在移动设备上运行,如果没有,是否有计
我有一个简单的 View 模型,其中包含修改后的 ObservableCollection使用 SynchronizationContext.Current.Send在 UI 线程上执行对集合的更改。
关于cassandra创建的数据文件和系统文件的位置,我需要移动在“cassandra.yaml”配置文件中设置的“commitlog_directory”、“data_file_directorie
我有这个代码 $(function() { var message = 'Dont forget us'; var original; var txt1 = ' - '; $(wind
我的客户报告说他的网站有一个奇怪的问题。该网站的 URL 是 your-montenegro.me 在 基于 Android 的浏览器 上加载时,页面底部会出现一个奇怪的空白区域。以下是屏幕截图: 华
我有这个 HTML 标记: Express 300 bsf Sign Up 我需要将元素从 DOM 上的一个
我有一个可重新排序的 TableView (UITableView 实例)。尽管我已经实现了 UITableViewDataSource 方法: tableView:moveRowAtIndexPat
我的客户报告说他的网站有一个奇怪的问题。该网站的 URL 是 your-montenegro.me 在 基于 Android 的浏览器 上加载时,页面底部会出现一个奇怪的空白区域。以下是屏幕截图: 华
我需要在拖放或复制/剪切和粘贴(复制与移动)期间获取操作类型。它是一个 Swing 应用程序,并且实现了 TransferHandle。我在操作结束时需要此信息,在 importData 方法中。 对
我编写了一个具有 add 和 get 方法的 SortedIntList 类。 我调用以下四个方法: SortedIntList mySortedIntList = new SortedIntList
我是一名优秀的程序员,十分优秀!