- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我用 Javascript 制作了两种类型的井字游戏。一个是 3x3,另一个是 10x10。
我正在使用 Minimax 算法和 Alpha Beta 剪枝来解决这两个游戏。在 3x3 中,博弈树非常小,算法运行良好。
但是在 10x10 中,它需要太多时间。该代码甚至无法在 10 分钟内完成一步操作。我运行了算法,等了 10 分钟,仍然在计算,然后我就关闭了浏览器选项卡。 (如果我让代码运行,可能需要数小时、数天、数周的时间,哈哈)
我在几篇文章中读到,带 Alpha Beta 剪枝的 Minimax 可以轻松解决 10x10 或更大的井字游戏。是假的,还是我的代码不好?
这是我的代码,但我认为,很难理解它。但代码并不重要,我猜。我应用了 Minimax + Alpha Beta 剪枝。我还可以做些什么?
function makeBotMove(newBoard, availMoves, XorO, firstCall) { // newBoard stores board state in an array. availMoves stores Available moves in an array (0-99). XorO store either "X" or "O" depending on whoes turn it is. firstCall is used to find out If the call is made inside the function or not. I need it for Alpha Beta Pruning. It helps in storing the length of the total available moves when the call was made for
if (firstCall)
{
var originalAvailMovesLength = availMoves.length;
if (originalAvailMovesLength == board.length)
var maxPossibleResult = 0.5; // OriginalAvailMoves will be only 100, if it is the first move. And if it is first move, it is impossible to get reward of 1. The best the computer can do is, draw (0.5 reward).
else
var maxPossibleResult = 1;
}
availMoves = getAvailableMoves(newBoard);
var result = checkResult(newBoard, false); // It can return 4 values. 1 = Win, 0.5 = Draw, 0 = Game is on, -1 = Lose.
if (result != 0)
return [result];
var movesIndex = [];
var movesScore = [];
for (var i = 0; i < availMoves.length; i++)
{
var move = availMoves[i];
newBoard[move] = XorO;
availMoves.splice(availMoves.indexOf(Number(move)),1);
if (XorO == "O") // 1.) Yes
var reward = makeBotMove(newBoard, availMoves, "X", false);
else
var reward = makeBotMove(newBoard, availMoves, "O", false);
newBoard[move] = "-";
availMoves.push(move);
availMoves.sort();
movesIndex.push(move);
movesScore.push(reward[0]);
var bestMove = [];
if (originalAvailMovesLength == availMoves.length && Math.max(...movesScore) == maxPossibleResult)
{
bestMove[0] = Math.max(...movesScore);
bestMove[1] = movesScore.indexOf(bestMove[0]);
bestMove[1] = movesIndex[bestMove[1]];
return bestMove;
}
}
if (XorO == "O")
bestMove[0] = Math.max(...movesScore);
else
bestMove[0] = Math.min(...movesScore);
bestMove[1] = movesScore.indexOf(bestMove[0]);
bestMove[1] = movesIndex[bestMove[1]];
return bestMove;
}
如果使用极小极大算法,则无法完成这项工作。你们推荐哪种算法?它一定不是很复杂,直到现在我还不是那么好的编码员。
编辑:在 10x10 中,玩家需要连续走 5 步而不是 3 步才能获胜。
最佳答案
您的代码显示您会继续进行递归调用,直到您赢/输或棋盘已满。由于在专家之间的博弈中制作 5 行不是微不足道的,此搜索可能必须访问大部分绘图位置,我估计这将达到大约 10100 个位置10x10 板,给定 100!几乎是 10158(但我们需要从这些中减去所有的输赢)。无论如何,这样多的板子要搜索起来是不现实的,因为可见宇宙中的原子数比这个少。所以不要等待你的代码完成。它不会在你的一生中。
有两种通用方法可以减少花在计算好着法上的时间:
对于第一个操作,您可以定义递归搜索的硬编码最大深度。如果你到达那个深度并且游戏还没有结束,那么调用一个应该给当前棋盘打分的评估函数,而不需要下更多的棋子。因此,它应该查看一些简单的模式,例如连续 3 次,并让这些对最终得分有所贡献。这是一种启发式方法,意味着它是一个(希望如此)好的猜测:该值应该介于赢和输的两个极端之间。
对于第二个操作,您应该限制您将进一步调查的移动次数。未访问的候选移动是距离已经玩过的方格相对较远的移动。
此外,您可以制作一个哈希表(在每次真正下完棋后新建),用于存储您已经评估过的棋盘,这样您就不必再做这项工作,以防您通过一个玩家的棋步交换到达那里你的搜索树。确保哈希表也捕获镜像或翻转的棋盘,这将减少游戏的前几步。
还有许多其他技术,例如在搜索过程中跟踪“ killer ” Action 。如果在搜索树的一个分支中发现有一个可以带来胜利或避免损失的着法,那么也首先在其他分支中尝试这个着法。它可能导致 alpha-beta 机制的快速 trim 。更一般地说,按“质量”的降序访问您的 Action 很重要。当然,在你分析之前你不知道一个 Action 有多好,但是同样,你可以注意到一些关于 Action 的静态事情。在棋盘 Angular 落的一步肯定不如在中心的一步,等等。
搜索的某些变体首先进行 1 深度搜索,然后使用结果根据该评估结果对移动进行排序。然后进行 2 深度搜索,并再次根据该(更准确的)结果对移动进行排序,...等,直到达到最终深度。这可能看起来像很多工作,但 alpha-beta 剪枝将在移动以最佳顺序排列时提供最大的好处,这将成为整体效率的更具决定性的因素。
关于javascript - Minimax Alpha Beta Pruning Algorithm 解决 Tic Tac Toe(10x10 棋盘)需要花费太多时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51364491/
我是初学者,所以我的代码很乱。我还没有完整地评论这个游戏,所以如果你需要澄清一些变量,我可以给你。 (顺便说一句,这是一个要求制作井字游戏的c++项目) 我的主要问题是,我将如何重复我的棋盘(每次有人
我正在为C的Tic Tac Toe代码编写一个简单的游戏。我已经完成了大部分代码,但是我希望AI永不丢失。 我已经阅读了有关minimax算法的信息,但我不理解。如何使用此算法使计算机获胜或平局,但永
在MATLAB中,我想对一个别人写的函数进行计时,他们的函数内部可能使用了tic/toc。我想要我自己的 tic/toc。但如果内部函数调用 tic,则外部计时器会重置。 我怎样才能避免这种情况?我不
在MATLAB中,我想对一个别人写的函数进行计时,他们的函数内部可能使用了tic/toc。我想要我自己的 tic/toc。但如果内部函数调用 tic,则外部计时器会重置。 我怎样才能避免这种情况?我不
我现在想用我的代码做两件事。1) 检查获胜者2) 不让双方玩家在同一个位置进入eg.如果player1已经在board[0][0]='X'处输入了value,player2再次进入board[0][0
我在我的 Matlab 项目中的很多地方都使用了 tic-toc 函数。输出时间可以是331.5264 或1234.754 秒 等。我可以输出这种分钟格式吗?例如。 5 分 30.6 秒?谢谢! 最佳
我的代码(或者更确切地说,其他人的代码)有一个奇怪的问题。我正在调试并试图弄清楚为什么我们的时间显示错误。 无论如何,这是打印时间的代码:
我一直在开发一个简单的井字棋游戏,但遇到了一堵砖墙。 虽然大多数游戏功能都已到位,但我缺少适当放置计算机图 block 所需的关键算法。 我需要一种算法,可以搜索 3x3 的瓷砖网格,并在网格中搜索计
我正在用这种格式从数据文件中绘制一个 gnuplot 图表: 01 value_1_1 value_2_1 02 value_1_1 value_2_1 ... 01 value_1_n value_
在 gnuplot 中,如何在 y 轴上的每个 tic 标记处在整个图形上绘制水平条?就像一种特定点在哪里的视觉指示器。 (抱歉,如果这很简单,但谷歌搜索无果而终) 最佳答案 见 set grid命令
感谢这里人们的帮助,我成功地禁用了点击 div 并在已经使用 $(".pos").addClass('already-played'); 选择它们时覆盖它们; 以及 CSS 中的这个: .已经播放{
我正在使用 gnuplot 绘制大量绘图。由于每个图的数据范围(x 轴和 y 轴)都是可变的,因此我需要让 gnuplot 自动设置范围和控制。但是,我需要在绘图下方放置一个定义的网格,水平线各 1/
我有一个井字棋游戏,其中用户(x)玩CPU(o)。游戏开始时,CPU 将 (o) 放置在中心,并在用户之后移动到随机位置。游戏设置为循环,但一旦出现获胜者,它就会重置,并且不会显示“你赢/输的横幅”。
我是 gnuplot 新手,正在尝试为项目创建堆叠直方图。我遇到的问题是,我无法将 ticlabels 放在 x 轴上(即使可以,它们也没有以整齐的方式格式化)。我的gp文件如下: 这是我的数据文件的
我试图在没有人工智能的情况下实现井字棋游戏。不知怎的,我的点击功能会自动触发。您能帮我理解为什么点击功能会自动触发吗?这是 HTML 代码片段。 Tic Tac Toe Gam
我一直在疯狂地寻找这个问题的答案。如何设置 gnuplot 上抽动之间的距离?目前我的情节中的抽搐被挤得太紧了。我希望它们更加分散。 这是一个例子: 我有一个如下所示的图表: 100 ——
我正在制作一个井字游戏程序。我计划将 minimax 与它一起使用。我制作了一棵树,其中包含所有可能的游戏序列的空间,并且我正在寻找一种方法来填充它。我目前有这种类型: typedef struct
我在完成这项学校作业时遇到了问题。我想实现一种方法,其中代码显示 //call method to check for Winner,在每轮后检查获胜者。 我不确定该怎么做。我尝试过各种不同的方法。然
我正在编写一些计算时间很重要的代码。我使用 tic toc 函数和 profiler 来测量时间。它们之间有什么区别? 对于我的一段代码,tic toc 函数说明例如时间是 3 秒,但是我的所有代码行
我正在尝试遵循本教程: https://www.youtube.com/watch?v=Db3cC5iPrOM 2:59 我听不懂他在说什么。 我不明白为什么他在构造函数(public static
我是一名优秀的程序员,十分优秀!