近几年来,随着谷歌的阿尔法狗和阿尔法元的问世,蒙特卡洛树搜索(MCTS),作为一种不需要特定领域的先验知识的搜索算法逐渐被人们重视起来。其可以在无任何已知知识,而仅需要了解模拟规则和结束状态的情况下,得到非常好的策略。但是由于其盲目的搜索,其运行时间和对内存空间的需求成为衡量其性能的主要因素之一。随着计算机的计算能力提升,对于一些特定的状态空间较少的问题,MCTS可以在其中表现优秀。
五子棋是初学者熟悉MCTS的常用用例。
图中红色代表模拟结果中下一步棋子的可能位置,红色棋子越不透明,则该位置获胜概率越高。
参数:
1.棋盘维度:7*7
2.根节点模拟次数:一百万次
3.每次运行时间:约40秒
4.赢棋赋分:1分,输棋赋分:-1分
5. Cp = 2
【目前无做任何优化,尚有很大性能优化空间,请查看后续版本】
基本呈现对称分布
下图明显白棋的落子位置能够堵住黑棋,同时与已有白棋连城一条线
黑棋落子位置为两白棋之间,同时与已有黑棋连线
白棋落子位置为黑棋三字的两端,并选择了直接杀掉这三个子的一段
这里还存在bug,白棋没有选择挡住左面即将连成四子的黑棋
黑棋也没有选择即将连成四子的黑棋,怀疑判断输赢的函数出现问题
黑棋发现已有棋面无法继续,故在四周拓展
白棋阻挡黑棋赢棋
出现了bug,所有得分均为负分。
代码尚存在一些bug,暂时开源如下,在后续的版本中修改。
代码如下
1.MCTSwuziqi.java 主程序,负责调用生成棋盘
2.DrawChessBoard.java 负责画出棋盘,时间监听,调用MCTS
3.MCTS_01.java 负责进行MCTS模拟
MCTSwuziqi.java
package bwjiang;
public class MCTSwuziqi {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("main init");
DrawChessBoard chessBoard = new DrawChessBoard();
//chessBoard.boardFrame.setVisible(true);
//System.out.println(chessBoard.boardFrame.getChessmans()[0][0].getColor());
}
}
DrawChessBoard.java
package bwjiang;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.io.*;
public class DrawChessBoard {
public static final int BLACKWIN = 1;
public static final int WHITEWIN = 2;
public static final int NOTWIN = 0;
public static final int ALLFILLED = -1;
public static final int BLACK = 1;
public static final int NOCHESS = 0;
public static final int WHITE = -1;
public static final int WINLENGTH = 5;
public BoardFrame boardFrame;
public int rows = 9;
JTextField rowsText;
JLabel nowChessColor;
public DrawChessBoard() {
//棋盘窗体
this.boardFrame = new BoardFrame();
boardFrame.setVisible(true);
}
//棋盘内容
class BoardPanel extends JPanel implements MouseListener{
public Image boardImage;//棋盘边框
public int lastChessColor = WHITE;
//记录全部落子的棋子类,第一项为行数,第二项为列数
public int[][] chessmans = new int[rows][rows];
public int[][] predictChessmans = new int[rows][rows];
public int maxReward = 0;
public int nextChessColor = BLACK;//控制交换棋权
int FrameWidth;//窗体
int FrameHeight;
int chessBoardX;//棋盘边框左上角
int chessBoardY;
int realChessBoardX;//真正落子的左上角
int realChessBoardY;
int deltaX;//间距
int deltaY;
public int[][] getChessmans(){
return this.chessmans;
}
//棋盘边框
public BoardPanel() {
try {
boardImage = ImageIO.read(new File("res/boar