1.概述

本文将探讨蒙特卡洛树搜索(MCTS)算法及其应用。

我们将通过在Java中实现井字棋来详细分析。 我们将设计一个通用解决方案,只需很少的更改可用于许多其他实际应用中。

2. 介绍

简而言之,蒙特卡洛树搜索是一种概率搜索算法。它是作出最优决策的方法,因为它在有着巨大可能性的开放式环境中高效。

是否您已经熟悉像Minimax这样的游戏算法,它需要一个评估当前状态的函数,并且必须计算游戏树中的许多级别才能找到最优解。

不幸的是,在像围棋这样的游戏中这样做是不可行的,因为在游戏中存在高分支率(随着树的高度增加而导致数百万的可能性),并且很难编写好的评估函数来计算 当前状态。

蒙特卡洛树搜索将蒙特卡洛方法应用于游戏树搜索。 由于它基于对游戏状态的随机抽样,因此不需要蛮横地排除每种可能性。 此外,它并不一定要求我们编写评估或良好的启发式功能。

3.算法

最初,我们将用一个根节点构建一个前瞻树(游戏树),然后我们随机展开它。 在这个过程中,我们将记录每个节点的访问次数和获胜次数。

最后,我们将选择最有希望的节点。

该算法由四个阶段组成; 让我们来详细探索它们。

3.1选择

在初始阶段,算法从一个根节点开始,并以最高胜率挑选一个子节点。 我们也想确保每个节点都有一个公平的机会。

这个思想是保持选择最佳的子节点,直到我们到达树的叶节点。 选择这样的子节点的一个好方法是使用UCT公式:

其中:wi =第i次移动后的获胜数

ni =第i次移动后的模拟次数

c =探索参数(理论上等于√2)

t =父节点的模拟总数。

该公式确保没有哪个状态会成为饥饿的受害者,并且它比对手更频繁地发挥有前途的分支。

3.2扩展

当它不能再应用UCT来寻找后继节点时,它通过从叶节点追加所有可能的状态来展开游戏树。

3.3模拟

在扩展张之后,该算法任意选取一个子节点,并且模拟从选定节点开始的随机游戏,直到它达到游戏的最终状态。 如果节点在播放期间被随机或半随机选取,则称为轻播放。 你也可以通过编写优质启发式或评估函数来选择重播放。

3.4反向传播

这也被称为更新阶段。 一旦算法达到游戏结束,它就会评估状态确定哪个玩家获胜。 它向上遍历根,并增加所有访问节点的访问分数。 如果该位置的玩家赢得了播放,它还会更新每个节点的胜利分数。

MCTS不断重复这四个阶段,直到一些固定的迭代次数或一些固定的时间量。

在这种方法中,我们根据随机移动估计每个节点的胜利分数。 迭代次数越多,估计就越可靠。 算法估计在搜索开始时将不太准确,并在足够的时间后持续改进。 它仅仅取决于问题的类型。

4.实现

现在,让我们使用蒙特卡洛树搜索算法来实现井字游戏。

我们将为MCTS设计一个通用解决方案,并可用于其他许多棋盘游戏。 我们将看看文章中的大部分代码。

尽管为了使解释清晰起见,我们可能不得不跳过一些小的细节(与MCTS没有特别的关系),但总是可以在这里找到完整的实现。

首先,我们需要树和节点类的基本实现来实现树搜索功能:

public class Node {

State state;

Node parent;

List childArray;

// setters and getters}

public class Tree {

Node root;

}

由于每个节点都有一个特定的问题状态,我们还需要实现一个State类:

public class State {

Board board;

int playerNo;

int visitCount;

double winScore;

// copy constructor, getters, and setters

public List getAllPossibleStates() {

// constructs a list of all possible states from current state }

public void randomPlay() {

/* get a list of all possible positions on the board andplay a random move */

}

}

现在,我们来实现类MonteCarloTreeSearch,它将负责从给定的游戏位置中找出下一个最好的移动:

public class MonteCarloTreeSearch {

static final int WIN_SCORE = 10;

int level;

int opponent;

public Board findNextMove(Board board, int playerNo) {

// define an end time which will act as a terminating condition

opponent = 3 - playerNo;

Tree tree = new Tree();

Node rootNode = tree.getRoot();

rootNode.getState().setBoard(board);

rootNode.getState().setPlayerNo(oponent);

while (System.currentTimeMillis() < end) {

// Phase 1 - Selection Node promisingNode = selectPromisingNode(rootNode);

// Phase 2 - Expansion if (promisingNode.getState().getBoard().checkStatus()

== Board.IN_PROGRESS) {

expandNode(promisingNode);

}

// Phase 3 - Simulation Node nodeToExplore = promisingNode;

if (promisingNode.getChildArray().size() > 0) {

nodeToExplore = promisingNode.getRandomChildNode();

}

int playoutResult = simulateRandomPlayout(nodeToExplore);

// Phase 4 - Update backPropogation(nodeToExplore, playoutResult);

}

Node winnerNode = rootNode.getChildWithMaxScore();

tree.setRoot(winnerNode);

return winnerNode.getState().getBoard();

}

}

在这里,我们不断迭代这四个阶段,直到预定义的时间,最后,我们得到一个具有可靠统计数据的树来作出明智的决定。

现在,我们来实现所有阶段的方法。

我们将从选择阶段开始,这也需要UCT的实施:

private Node selectPromisingNode(Node rootNode) {

Node node = rootNode;

while (node.getChildArray().size() != 0) {

node = UCT.findBestNodeWithUCT(node);

}

return node;

}

public class UCT {

public static double uctValue(

int totalVisit, double nodeWinScore, int nodeVisit) {

if (nodeVisit == 0) {

return Integer.MAX_VALUE;

}

return ((double) nodeWinScore / (double) nodeVisit)

+ 1.41 * Math.sqrt(Math.log(totalVisit) / (double) nodeVisit);

}

public static Node findBestNodeWithUCT(Node node) {

int parentVisit = node.getState().getVisitCount();

return Collections.max(

node.getChildArray(),

Comparator.comparing(c -> uctValue(parentVisit,

c.getState().getWinScore(), c.getState().getVisitCount())));

}

}

在扩展阶段进一步扩展叶节点:

private void expandNode(Node node) {

List possibleStates = node.getState().getAllPossibleStates();

possibleStates.forEach(state -> {

Node newNode = new Node(state);

newNode.setParent(node);

newNode.getState().setPlayerNo(node.getState().getOpponent());

node.getChildArray().add(newNode);

});

}

接下来,我们编写代码来选择一个随机节点并模拟随机播放。此外,我们将有一个更新函数来传播从叶到根的分数和访问计数:

private void backPropogation(Node nodeToExplore, int playerNo) {

Node tempNode = nodeToExplore;

while (tempNode != null) {

tempNode.getState().incrementVisit();

if (tempNode.getState().getPlayerNo() == playerNo) {

tempNode.getState().addScore(WIN_SCORE);

}

tempNode = tempNode.getParent();

}

}

private int simulateRandomPlayout(Node node) {

Node tempNode = new Node(node);

State tempState = tempNode.getState();

int boardStatus = tempState.getBoard().checkStatus();

if (boardStatus == opponent) {

tempNode.getParent().getState().setWinScore(Integer.MIN_VALUE);

return boardStatus;

}

while (boardStatus == Board.IN_PROGRESS) {

tempState.togglePlayer();

tempState.randomPlay();

boardStatus = tempState.getBoard().checkStatus();

}

return boardStatus;

}

现在我们已经完成了MCTS算法实现。 我们需要的是一个井字棋实现。 请注意,在我们的实现中玩其他游戏; 我们只需要更改类Board。

public class Board {

int[][] boardValues;

public static final int DEFAULT_BOARD_SIZE = 3;

public static final int IN_PROGRESS = -1;

public static final int DRAW = 0;

public static final int P1 = 1;

public static final int P2 = 2;

// getters and setters public void performMove(int player, Position p) {

this.totalMoves++;

boardValues[p.getX()][p.getY()] = player;

}

public int checkStatus() {

/* Evaluate whether the game is won and return winner.If it is draw return 0 else return -1 */

}

public List getEmptyPositions() {

int size = this.boardValues.length;

List emptyPositions = new ArrayList<>();

for (int i = 0; i < size; i++) {

for (int j = 0; j < size; j++) {

if (boardValues[i][j] == 0)

emptyPositions.add(new Position(i, j));

}

}

return emptyPositions;

}

}

我们刚刚实施了一个AI,它不能在井字游戏中被打败。 我们来写一个测试用例,它证明人工智能与人工智能总是会产生平局:

@Test

public void givenEmptyBoard_whenSimulateInterAIPlay_thenGameDraw() {

Board board = new Board();

int player = Board.P1;

int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;

for (int i = 0; i < totalMoves; i++) {

board = mcts.findNextMove(board, player);

if (board.checkStatus() != -1) {

break;

}

player = 3 - player;

}

int winStatus = board.checkStatus();

assertEquals(winStatus, Board.DRAW);

}

5.优势不需要有关游戏的战术知识。

一般的MCTS实现可以在很少修改的情况下重用于任意的游戏。

专注于获胜的可能性更大的节点。

适用于高分支率的问题,因为它不会浪费所有可能分支上的计算。

执行可以在任何给定的时间停止,它仍然会建议到目前为止计算的下一个最佳状态。

6.缺点

如果MCTS的基本形式没有任何改进,它可能无法给出合理的动作。 如果没有充分访问节点会导致估算不准确,则可能会发生这种情况。

但是,使用一些技术可以改进MCTS。 它涉及特定领域以及领域独立技术。

在特定领域的技术中,模拟阶段产生更真实的播出而不是随机模拟。 虽然它需要游戏特定技术和规则的知识。

7.总结

乍看之下,很难相信依靠随机选择的算法会带来AI。 然而,MCTS的深思熟虑的实施确实可以为我们提供一种可用于许多游戏以及决策问题的解决方案。

蒙特卡洛树搜索的主要流程有哪些_蒙特卡洛树搜索简介与实现相关推荐

  1. 蒙特卡洛树搜索的主要流程有哪些_蒙特卡洛树搜索简介

    什么是 MCTS? 全称 Monte Carlo Tree Search,是一种人工智能问题中做出最优决策的方法,一般是在组合博弈中的行动(move)规划形式.它结合了随机模拟的一般性和树搜索的准确性 ...

  2. 蒙特卡洛树搜索的主要流程有哪些_笔记:蒙特卡洛树搜索

    Model-free: 类似monte carlo control, sarsa, q-learning, ac算法都是model-free算法.样本完全从经验中获得.从来不利用对于下一个状态,下一个 ...

  3. 智慧树考试复制粘贴会检测吗_智慧树考试可以分屏吗?切屏会被发现吗

    智慧树可以在线考试,有不少朋友想知道智慧树考试切屏有记录吗?智慧树考试分屏会被发现吗?下面小编就为大家带来相关介绍,感兴趣的朋友们快来一起了解下吧! -->>智慧树下载< 智慧树考试 ...

  4. 手机桌面百度搜索框不显示热词_移动端搜索和PC端搜索的区别

    随着智能手机的普及,移动端搜索量是越来越大了,在去年从未有人通过移动搜索我的博客,而到了今年,从通过统计工具的数据分析来看,已经有越来越多的用户通过手机搜索到我的博客. 有一段时间移动搜索来路很大的时 ...

  5. 蒙特卡洛树搜索的主要流程有哪些_「详细原理」蒙特卡洛树搜索入门教程

    本文是对 Monte Carlo Tree Search – beginners guide 这篇文章的文章大体翻译,以及对其代码的解释. 1 引言 蒙特卡洛树搜索在2006年被Rémi Coulom ...

  6. 蒙特卡洛树搜索的主要流程有哪些_海运拼箱操作流程主要有哪些

    海运拼箱操作流程与海运出口流程差别不大,只是多了一个拼装入箱的步骤罢了.下面我们来看一张图(海运出口操作流程). 首先,无论是出口方还是进口方,他们都需要通过信息流.商流和物流来了解行情,选择并决定某 ...

  7. 智慧树怎么导入教务系统的课_智慧树——后疫情时代异地直播课堂解决方案

    0 1 后疫情时代教学 随着各行各业的陆续复工,高校也迎来了全面恢复新学期的教学运行工作.来自五湖四海的学生即将回归校园,开始新学期的学习和生活. 为降低疫情风险,保障学生学习安全,基于高校异地同步教 ...

  8. 二叉搜索树中第k大元素_二叉搜索树中第K个最小元素

    二叉搜索树中第k大元素 Problem statement: 问题陈述: Find the k-th smallest element in a given binary search tree (B ...

  9. 智慧树期末考试可以切换页面吗_智慧树考试可以切换界面吗?中途可以退出吗...

    智慧树是一个在线教育平台,也是可以用来在线考试的,不少朋友想知道智慧树考试可以切换界面吗?智慧树考试中途退出有记录吗?下面小编就为大家带来相关介绍,感兴趣的朋友们快来一起了解下吧! -->> ...

最新文章

  1. ie与firefox 关于js 的差别(转载)
  2. IdentityServer4 配置负载均衡
  3. Linux装ntfs后内存不够,Linux_安装Ubuntu后无法使用NTFS硬盘或移动硬盘,  在安装Ubuntu系统后,存在 - phpStudy...
  4. 131. Palindrome Partitioning
  5. Java并发包中Semaphore的工作原理、源码分析及使用示例
  6. 导航栏-滚动渐变 - 封装版
  7. iOS UISlider
  8. DataTable的Select方法
  9. 软件工程-----个人总结
  10. 珍大户《认知世界的经济学》学习笔记 -- 第21课 利率的计算 更新时间2021年07月27日22:14:34
  11. “打开文件所在位置”提示“找不到应用程序”的解决方案
  12. DOS命令窗口(黑窗口)
  13. 第十一章 文件操作_C语言实现文件复制功能(包括文本文件和二进制文件)
  14. mysql主从配置duxi_MySQL 8.0主从(Master-Slave)配置
  15. 去掉input text边框
  16. 刘强东终于向自己的兄弟下手了!
  17. pyqt5 tablewidget 隐藏表头,设置表头
  18. mysql子查询效率高_mysql利用子查询效率怎么样
  19. MS SQL 分类汇总参数 grouping(**)=1 rollup cubt
  20. 我的世界java三叉戟怎么得_《我的世界》1.13最新快照,“水鬼”的三叉戟究竟如何获得?...

热门文章

  1. Java实现超级简易的银行ATM机项目(详细注释版)
  2. ABIDE(自闭症)数据集(nii格式)下载
  3. LVGL v8学习笔记 | 01 - LVGL PC模拟器初体验
  4. EasyNLP 中文文图生成模型带你秒变艺术家
  5. EasyExcel实现导入excel
  6. Idea下载后打不开
  7. Kolin解决数学旅游座车
  8. 云原生之使用Docker部署h5ai文件展示页
  9. Simulink仿真入门到精通(四) Simulink子系统
  10. iOS开发通过微信学习WCDB(二)