国际跳棋人机对战

发布时间:2020-12-03

概述

国际跳棋(英语:checkers或draughts)是一种两人棋盘游戏。玩家的棋子都是沿斜角走的。棋子可跳过敌方的棋子并吃掉它。本国际跳棋程序使用蒙特卡洛树搜索算法完成AI自动下棋的功能, 实现人机对战,根据国际跳棋的规则实现兵棋和王棋的走棋、跳棋和连跳,判断棋局的输赢或死棋,。

详细

概述

国际跳棋是一种古老的棋类游戏。远在古埃及法老时期就已存在,现代国际跳棋是在12世纪定型的。 国际跳棋是由各国的民族跳棋演变而来。其历史源远流长。据史学家研究,跳棋起源于古埃及、古罗马、古希腊等一些国家和地区。

在大多数国家国际跳棋为64格,规则有所不同,有巴西规则、俄罗斯规则等。但国际比赛采用的棋盘为100格,此外加拿大国际跳棋采用12*12144格的棋盘,棋盘越大,变化越丰富,难度也相应增大。如图所示,国际跳棋棋子是圆柱型的,黑白棋子各二十枚,棋子表面上有罗纹,这种棋子叫“兵”,把兵翻过来(或两兵叠起来)就是“王”。由于棋子只能在深色格子中行走,因此可以将这些格子依次编号,方便记录棋局。对于100格国际跳棋,开局时,黑色棋子分布在120格,白色棋子分布在3150格,和国际象棋类似,白棋先行。

1.png

在人与人对弈的国际比赛中采用的规则相对复杂,特别是对和局的判定,而计算机博弈中采用的规则做了一些简化。而且64格的规则与100格基本一致,只是棋子数目不同。另外在国内的计算机博弈赛中,国际跳棋和围棋一样也是黑方先行。

一、走法规则

所有棋子均在黑色或指定颜色格子中行走。

①、兵的走法

只能向前斜走一格,不能后退,显然靠边的兵只有一个方向可走,而居于中部的兵有两个方向可走。

②、兵的跳吃

黑白两枚棋子紧连在一条斜线上,如轮到某一方行棋时,对方棋子的前后正好有一空棋位能跳过对方的棋子,那么就可以跳过对方的棋子把被跳过的棋子吃掉,并从棋盘上取下。

兵的连跳

兵的连跳是是跳过对方的棋子以后,又遇上可以跳过的棋子,那么就可以连续跳过去,把被跳过的棋子吃掉,并且从棋盘上一次取下。兵的走法是不能后退,但是遇到跳吃或连续跳吃时,可以退跳。

兵的升变

对局开始前双方在棋盘上摆的棋子都是兵,兵在对局过程中,走到或跳到对方底线停下,即可升变为“王”刚升变的王要到下一步才能享有王的走法的权利。兵在对局过程中,走到或跳到对方底线没停下(即中途经过),不可以升变为“王”。

王的走法

王在其位于的任何一条斜线上均可进退,并且不限格数,除非遇到其它棋子。

王的跳吃

王的跳吃是王与对方棋子遇在同一斜线上,不管相距有几个空棋位,且对方棋子后也有空棋位,那么王棋就可以跳过去吃掉对方的棋子,而且跳吃时要跳到对方棋子后面的一个空位里。因此如果对方棋子有两个或两个以上相连,王棋是无法将它们直接吃掉的。

王的连跳

王的连跳与兵连跳的情况基本上相同,只是不限距离。

所有棋子均在黑色或指定颜色格子中行走。

二、吃子规定

①、有吃必吃

凡有跳吃或连跳机会时,不管对自己是否有利都必须连续跳吃或跳过,尤其是王。如果有连跳的局面,必须将对方所有的棋子跳完,直到无可再跳时才能停下。对于兵来说,遇到连续跳吃,即使吃到底也不能停下升王,而需要将所有的跳着走完,这就是“吃到底不得停”。

②、有吃多吃

如果有多条路线或2枚棋子都能吃对方的棋子,那么不管是否对自己有利,必须选择吃多的路线和棋子。例如:同时在两条路线上可以吃对方的棋子,一条路线上能吃3枚棋子,另一条路线上能吃2枚棋子,必须选择跳吃3枚棋子的路线。如果两条路线吃掉棋子的数目相等,则可以任选一种吃法。

不得重吃重跳

在跳吃过程中,被跳过的对方棋子在没有跳完之前不能拿下棋盘,这些棋子都只能被跳过一次,即已经跳过的棋子会对后面的跳吃造成屏障。在比赛中,这一规则通常被利用以形成所谓的“土耳其打击”。

三、棋局结束判断

①、所有的棋子都被对方吃掉为负棋。

②、残留在棋盘上的棋子,被对方封锁,无子可动为负棋。


详细


一、运行效果

4.png

二、人机对战算法

本程序使用了蒙特卡洛树搜索树算法来进行判断对战, 其实原理很简单:

蒙特卡洛树搜索的每个循环包括四个步骤:

  • 选择(Selection):从根节点R开始,选择连续的子节点向下至叶子节点L。后面给出了一种选择子节点的方法,让游戏树向最优的方向扩展,这是蒙特卡洛树搜索的精要所在。

  • 扩展(Expansion):除非任意一方的输赢使得游戏在L结束,否则创建一个或多个子节点并选取其中一个节点C。

  • 仿真(Simulation):在从节点C开始,用随机策略进行游戏,又称为playout或者rollout。

  • 反向传播(Backpropagation):使用随机游戏的结果,更新从C到R的路径上的节点信息。

每一个节点的内容代表胜利次数/游戏次数

MCTS_(English).svg.png


三、主要的模块

棋盘界面模块(myFrame\MainFrame.java)

package myFrame;
 
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.*;
 
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
 
import monteCarloTreeSearch.*;
import moveWays.*;
import searchTree.*;
 
/**
 *
 * @author 名字
 * @邮箱:mail@company.com
 * @修改日期:2020.11.11
 * @描述:国际跳棋主窗口
 *
 */
@SuppressWarnings("serial")
public class MainFrame extends JFrame implements Runnable {
    private int x;// 鼠标点击坐标
    private int y;
    private static int step = 0; // 记录走了几回合
    private static boolean enemyLaterIsEmpty;// 敌方棋子后有空位置
    private static boolean own = false;
 
    private static ImageIcon mainFrameIcon;// 游戏窗口背景图片
    private static JLabel back_Label;
    private static JButton startButton = new JButton();
    private static JButton firstMoveButton = new JButton("机器先走黑棋");
    private static JButton regretChessButton = new JButton("悔棋");
    Scan scan = new Scan();
 
    private JLabel chessPic; //图片,用于拖动
    private Point point = null; //坐标点
    private static boolean chessDisplay = false;
    private static boolean willDisplayChess = false;
    private static boolean willNotDisplayChess = false;
    private MainFrame that;
    private JPanel panel;
 
    static {// 加载背景图片
        mainFrameIcon = new ImageIcon("png/qipan.png");
    }
 
    public static MonteCarloPlayer player1, player2;
    public static Field game_field;
    private Image iBuffer = null;
    private Graphics gBuffer;
    private ToolTip tip = new ToolTip();
 
    //双缓冲绘图
    @Override
    public void update(Graphics g) {
        if (iBuffer == null) {
           iBuffer = createImage(this.getSize().width, this.getSize().height);
           gBuffer = iBuffer.getGraphics();
        }
        gBuffer.setColor(getBackground());
        gBuffer.fillRect(0, 0, this.getSize().width, this.getSize().height);
        paint(g);
        g.drawImage(iBuffer, 0, 0, this);
    }
 
    public MainFrame() {
        super("国际跳棋大师");
        that = this;
        setLayout(null);
        chessPic = new JLabel(new ImageIcon("png\\chess_black.png"));
        add(chessPic);
        // 写入初始信息
        ShowInformation.writeInitInformation();
        // 先建的组件,在上面
        init();// 初始化容器
        InitData.initChess();// 初始化棋盘坐标
 
        game_field = new Field();
        player1 = new MonteCarloPlayer(Field.WHITE, game_field, 30);
        player2 = new MonteCarloPlayer(Field.BLACK, game_field, 40);
        System.out.println("start of game");
        game_field.display();
 
        action();
        setVisible(true);
 
        // 创建固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(1);
        // 提交机器和人交替走棋的任务
        executor.submit(this);
        tip.setToolTip(new ImageIcon("png\\chess_black.png"),"------轮到黑方走棋------");
    }
 
    /**
     * 描述:初始化
     */
    public void init() {
        setLayout(null);
        setName("国际跳棋");
        setSize(1200, 900);
        setLocation(300, 30);
 
        startButton = new JButton("重新开始");
        startButton.setBounds(1000, 140, 120, 50);
        startButton.setEnabled(false);
        regretChessButton.setEnabled(false);
        add(startButton);
 
        firstMoveButton.setBounds(1000, 340, 120, 50);
        add(firstMoveButton);
        regretChessButton.setBounds(1000, 540, 120, 50);
        add(regretChessButton);
 
        // 加载背景图片
        back_Label = new JLabel(mainFrameIcon);
        back_Label.setBounds(0, 0, 1082, 824);
        add(back_Label);
 
        panel = new JPanel();
        panel.setLayout(null);
        panel.setBounds(0, 0, 990, 900);
        // panel.setBackground(Color.RED);
        panel.addMouseListener(new MyMouse());
        add(panel);// 面板和图片不能同时存在吗?
 
        //图标显示为棋子时的事件
        ChessMouseInputAdapter listener = new ChessMouseInputAdapter();  //鼠标事件处理
        chessPic.addMouseListener(listener);  //增加标签的鼠标事件处理
        chessPic.addMouseMotionListener(listener);
        point = new Point(199, 161);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }
 
    // 重新开始,刷新数据
    public void action() {
        startButton.addMouseListener(new MouseAdapter() {
           @Override
           public void mouseClicked(MouseEvent e) {
               chessPic.setIcon(new ImageIcon("png\\chess_black.png"));
               InitData.initChessData();
 
               game_field = new Field();
               player1 = new MonteCarloPlayer(Field.WHITE, game_field, 30);
               player2 = new MonteCarloPlayer(Field.BLACK, game_field, 40);
               System.out.println("start of game");
               game_field.display();
 
               firstMoveButton.setEnabled(true);
               if (isOwn()) {
                   setOwn(false);
               }
               repaint();// 刷新
           }
        });
        firstMoveButton.addMouseListener(new MouseAdapter() {
           @Override
           public void mouseClicked(MouseEvent e) {
               own = true;
               repaint();
               tip.setToolTip(new ImageIcon("png\\chess_black.png"), "机器执黑棋正在思考......");
               SwingUtilities.invokeLater(() -> {
                   SwingUtilities.invokeLater(() -> {
                       scan.scan();
                       scan.printWeight();
                       scan.clearWeight();
 
                       CanEvenJump.canEvenJump(); // 测试
                       CanEvenJump.bestChess();// 测试
                       try {
                           AI.ai();
                       } catch (Exception e1) {
                           // TODO Auto-generated catch block
                           e1.printStackTrace();
                       }
                       InitData.printChessData();
                       CanEvenJump.canEvenJump(); // 测试
                       CanEvenJump.bestChess();// 测试
                       //记录棋盘
                       GameRecord.backupGame();
                       repaint();
                   });
               });
               chessPic.setIcon(new ImageIcon("png\\chess_white.png"));
               regretChessButton.setEnabled(true);
               startButton.setEnabled(true);
               firstMoveButton.setEnabled(false);
           }
        });
        regretChessButton.addMouseListener(new MouseAdapter() {
           @Override
           public void mouseClicked(MouseEvent e) {
               int result = JOptionPane.showConfirmDialog(null, "是否需要悔棋?", "确认悔棋", JOptionPane.YES_NO_OPTION);
               if (result == 0) {// 确认悔棋
                   try {
                       if(GameRecord.getGameRecordList().size()>1){
                           GameRecord.renewGame();
                       }
                       else{
                           GameRecord.getGameRecordList().clear();
                           chessPic.setIcon(new ImageIcon("png\\chess_black.png"));
                           InitData.initChessData();
                           game_field = new Field();
                           player1 = new MonteCarloPlayer(Field.WHITE, game_field, 30);
                           player2 = new MonteCarloPlayer(Field.BLACK, game_field, 40);
                           System.out.println("start of game");
                           game_field.display();
                           startButton.setEnabled(false);
                           firstMoveButton.setEnabled(true);
                           regretChessButton.setEnabled(false);
                           if (isOwn()) {
                               setOwn(false);
                           }
                           repaint();// 刷新
                       }
                       InitData.printChessData();
                       repaint();
                       game_field.display();
                   } catch (Exception exception) {
                       exception.printStackTrace();
                   }
               }
           }
        });
    }
 
    /**
     * 描述:画棋盘、棋子
     *
     * @param g
     */
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        paint0(g);
        paint1(g);
    }
 
    public void paint0(Graphics g) {
        super.paint(g);
        g.drawLine(150, 50, 950, 50);
        g.drawLine(150, 850, 950, 850);
        g.drawLine(150, 50, 150, 850);
        g.drawLine(950, 50, 950, 850);
    }
 
    /**
     * 描述:棋子
     *
     * @param
     */
    public static void paint1(Graphics g) {
        for (int i = 0; i < 10; i++) {
           for (int j = 0; j < 10; j++) {
               if (Packaging.getChessData(i, j) == Packaging.getBlackChess()) {
                   g.setColor(Color.BLACK);
                   g.fillOval(150 + 10 + j * 80, 50 + 10 + i * 80, 60, 60);
               }
               if (Packaging.getChessData(i, j) == Packaging.getWhiteChess()) {
                   g.setColor(Color.WHITE);
                   g.fillOval(150 + 10 + j * 80, 50 + 10 + i * 80, 60, 60);
               }
               if (Packaging.getChessData(i, j) == Packaging.getBlackKing()) {
                   g.setColor(Color.BLACK);
                   g.fillOval(150 + 10 + j * 80, 50 + 10 + i * 80, 60, 60);
                   g.setColor(Color.RED);
                   g.fillOval(150 + 20 + j * 80, 50 + 20 + i * 80, 40, 40);
               }
               if (Packaging.getChessData(i, j) == Packaging.getWhiteKing()) {
                   g.setColor(Color.WHITE);
                   g.fillOval(150 + 10 + j * 80, 50 + 10 + i * 80, 60, 60);
                   g.setColor(Color.RED);
                   g.fillOval(150 + 20 + j * 80, 50 + 20 + i * 80, 40, 40);
               }
               if (Packaging.getChessData(i, j) == 5) {
                   g.setColor(Color.WHITE);
                   g.fillOval(150 + 10 + j * 80, 50 + 10 + i * 80, 60, 60);
                   g.setColor(Color.GREEN);
                   g.fillOval(150 + 20 + j * 80, 50 + 20 + i * 80, 40, 40);
               }
           }
        }
    }
 
    @Override
    public void run() {
        while (true) {
           if (IsWin.isWin() == 1 || IsWin.isWin() == 2 || IsWin.isWin() == 3) {
               // 写入比赛结果信息
               ShowInformation.writeFinalResult();
               ShowResult.showWin();
               // 写入初始信息
               ShowInformation.writeInitInformation();
               repaint();
               break;
           }
           try {
               Thread.sleep(1000);
               Thread.yield();
           } catch (InterruptedException g) {
           }
        }
    }
 
    public class MyMouse implements MouseListener {
        @Override
        public void mousePressed(MouseEvent e) {
           checkJumpChess();
        }
 
        @Override
        public void mouseReleased(MouseEvent e) {
 
        }
 
        @Override
        public void mouseEntered(MouseEvent e) {
 
        }
 
        @Override
        public void mouseExited(MouseEvent e) {
 
        }
 
        @Override
        public void mouseClicked(MouseEvent e) {
           if(!startButton.isEnabled()){
               startButton.setEnabled(true);
           }
           if(!regretChessButton.isEnabled()){
               regretChessButton.setEnabled(true);
           }
           playChess(e.getX() + 8, e.getY() + 38);
        }
    }
 
    private void checkJumpChess() {
        if ((isOwn() && HaveChessCanJump.haveWriteChessCanJump())
               || (!isOwn() && HaveChessCanJump.haveBlackChessCanJump())) {
           // 在落子时,
           AI.setMustJumpChess(true);
           System.out.println("必须跳棋");
        }
    }
 
    /**
     * 描述:初步判断这一步棋是好的,才可以走,就是保证走完之后,不能被立即吃掉
     *
     * @param i:点击坐标
     * @param j
     * @return
     */
    public static boolean thisStepIsGood(int i, int j) {
        if (Packaging.getChessData(i, j) == Packaging.getBlackKing()
               || Packaging.getChessData(i, j) == Packaging.getWhiteKing()) {
           if (leftUpIsGood(i, j)) {
 
               AI.setI2(i - 1);
               AI.setJ2(j - 1);
               return true; // 如果左上角右上角或者其他也是最优的,那么优先走左上角的(第一层搜寻)
           }
           if (rightUpIsGood(i, j)) {
               AI.setI2(i - 1);
               AI.setJ2(j + 1);
               return true;
           }
           if (leftDownIsGood(i, j)) {
               AI.setI2(i + 1);
               AI.setJ2(j - 1);
               return true;
           }
           if (rightDownIsGood(i, j)) {
               AI.setI2(i + 1);
               AI.setJ2(j + 1);
               return true;
           }
        }
        if (Packaging.getChessData(i, j) == Packaging.getBlackChess()) {
           if (leftDownIsGood(i, j)) {
               AI.setI2(i + 1);
               AI.setJ2(j - 1);
               return true;
           }
           if (rightDownIsGood(i, j)) {
               AI.setI2(i + 1);
               AI.setJ2(j + 1);
               return true;
           }
        }
        if (Packaging.getChessData(i, j) == Packaging.getWhiteChess()) {
           if (leftUpIsGood(i, j)) {
               AI.setI2(i - 1);
               AI.setJ2(j - 1);
               return true; // 如果左上角右上角或者其他也是最优的,那么优先走左上角的(第一层搜寻)
           }
           if (rightUpIsGood(i, j)) {
               AI.setI2(i - 1);
               AI.setJ2(j + 1);
               return true;
           }
        }
        return false;
    }
 
    public static boolean leftUpIsGood(int i, int j) { // 左上
        if (Packaging.getChessData(i, j) == Packaging.getBlackKing()
               || Packaging.getChessData(i, j) == Packaging.getBlackChess()) { // 如果是黑方
           if ((i - 1 >= 0) && (j - 1 >= 0)) { // 左上角不越界
               if (Packaging.getChessData(i - 1, j - 1) == 0) { // 左上角为空
                   if ((i - 2 >= 0) && (j - 2 >= 0)) { // 左上上角不越界
                       // 且左上角的左上角不是敌方棋子,则可以是初步最优,因为这一步棋,不能立即被吃
                       if (Packaging.getChessData(i - 2, j - 2) != Packaging.getWhiteKing()
                               && Packaging.getChessData(i - 2, j - 2) != Packaging.getWhiteChess()) {
                           // 在左上角的左上角不是敌方棋子的情况下,需要判断上面和左面
                           // 左上角都没有越界,左面和上面也不可能越界
                           if ((Packaging.getChessData(i, j - 2) == 0 && (Packaging.getChessData(i - 2,
                                  j) == Packaging.getWhiteKing()
                                  || Packaging.getChessData(i - 2, j) == Packaging.getWhiteChess()))
                                  || (Packaging.getChessData(i - 2, j) == 0 && (Packaging
                                  .getChessData(i, j - 2) == Packaging.getWhiteKing()
                                  || Packaging.getChessData(i, j - 2) == Packaging
                                  .getWhiteChess()))) {
                               return false;
                           } else { // 如果没有上面那种也可以被吃的情况,就是初步最优
                               return true;
                           }
                       }
                   } else { // 在左上角的左上角越界的情况下,说明到达边缘,满足初步最优
                       return true;
                   }
               }
           }
        }
        if (Packaging.getChessData(i, j) == Packaging.getWhiteKing()
               || Packaging.getChessData(i, j) == Packaging.getWhiteChess()) { // 如果是白方
           if ((i - 1 >= 0) && (j - 1 >= 0)) { // 左上角不越界
               if (Packaging.getChessData(i - 1, j - 1) == 0) { // 左上角为空
                   if ((i - 2 >= 0) && (j - 2 >= 0)) { // 左上上角不越界
                       // 且左上角的左上角不是敌方棋子,则可以是初步最优,因为这一步棋,不能立即被吃
                       if (Packaging.getChessData(i - 2, j - 2) != Packaging.getBlackKing()
                               && Packaging.getChessData(i - 2, j - 2) != Packaging.getBlackChess()) {
                           if ((Packaging.getChessData(i, j - 2) == 0 && (Packaging.getChessData(i - 2,
                                  j) == Packaging.getBlackKing()
                                  || Packaging.getChessData(i - 2, j) == Packaging.getBlackChess()))
                                  || (Packaging.getChessData(i - 2, j) == 0 && (Packaging
                                  .getChessData(i, j - 2) == Packaging.getBlackKing()
                                  || Packaging.getChessData(i, j - 2) == Packaging
                                  .getBlackChess()))) {
                               return false;
                           } else { // 如果没有上面那种也可以被吃的情况,就是初步最优
                               return true;
                           }
                       }
                   } else { // 在左上角的左上角越界的情况下,说明到达边缘,满足初步最优
                       return true;
                   }
               }
           }
        }
        return false;
    }
 
    public static boolean rightUpIsGood(int i, int j) { // 右上
        if (Packaging.getChessData(i, j) == Packaging.getBlackKing()
               || Packaging.getChessData(i, j) == Packaging.getBlackChess()) { // 如果是黑方
           if ((i - 1 >= 0) && (j + 1 < 10)) {
               if (Packaging.getChessData(i - 1, j + 1) == 0) {
                   if ((i - 2 >= 0) && (j + 2 < 10)) {
                       if (Packaging.getChessData(i - 2, j + 2) != Packaging.getWhiteKing()
                               && Packaging.getChessData(i - 2, j + 2) != Packaging.getWhiteChess()) {
                           // 判断上面和右面
                           if ((Packaging.getChessData(i, j + 2) == 0 && (Packaging.getChessData(i - 2,
                                  j) == Packaging.getWhiteKing()
                                  || Packaging.getChessData(i - 2, j) == Packaging.getWhiteChess()))
                                  || (Packaging.getChessData(i - 2, j) == 0 && (Packaging
                                  .getChessData(i, j + 2) == Packaging.getWhiteKing()
                                  || Packaging.getChessData(i, j + 2) == Packaging
                                  .getWhiteChess()))) {
                               return false;
                           } else { // 如果没有上面那种也可以被吃的情况,就是初步最优
                               return true;
                           }
                       }
                   } else {
                       return true;
                   }
               }
           }
        }
        if (Packaging.getChessData(i, j) == Packaging.getWhiteKing()
               || Packaging.getChessData(i, j) == Packaging.getWhiteChess()) { // 如果是白方
           if ((i - 1 >= 0) && (j + 1 < 10)) {
               if (Packaging.getChessData(i - 1, j + 1) == 0) {
                   if ((i - 2 >= 0) && (j + 2 < 10)) {
                       if (Packaging.getChessData(i - 2, j + 2) != Packaging.getBlackKing()
                               && Packaging.getChessData(i - 2, j + 2) != Packaging.getBlackChess()) {
                           if ((Packaging.getChessData(i, j + 2) == 0 && (Packaging.getChessData(i - 2,
                                  j) == Packaging.getBlackKing()
                                  || Packaging.getChessData(i - 2, j) == Packaging.getBlackChess()))
                                  || (Packaging.getChessData(i - 2, j) == 0 && (Packaging
                                  .getChessData(i, j + 2) == Packaging.getBlackKing()
                                  || Packaging.getChessData(i, j + 2) == Packaging
                                  .getBlackChess()))) {
                               return false;
                           } else { // 如果没有上面那种也可以被吃的情况,就是初步最优
                               return true;
                           }
                       }
                   } else {
                       return true;
                   }
               }
           }
        }
        return false;
    }
 
    public static boolean leftDownIsGood(int i, int j) { // 左下
        if (Packaging.getChessData(i, j) == Packaging.getBlackKing()
               || Packaging.getChessData(i, j) == Packaging.getBlackChess()) { // 如果是黑方
           if ((i + 1 < 10) && (j - 1 >= 0)) {
               if (Packaging.getChessData(i + 1, j - 1) == 0) {
                   if ((i + 2 < 10) && (j - 2 >= 0)) {
                       if (Packaging.getChessData(i + 2, j - 2) != Packaging.getWhiteKing()
                               && Packaging.getChessData(i + 2, j - 2) != Packaging.getWhiteChess()) {
                           // 左、下
                           if ((Packaging.getChessData(i, j - 2) == 0 && (Packaging.getChessData(i + 2,
                                  j) == Packaging.getWhiteKing()
                                  || Packaging.getChessData(i + 2, j) == Packaging.getWhiteChess()))
                                  || (Packaging.getChessData(i + 2, j) == 0 && (Packaging
                                  .getChessData(i, j - 2) == Packaging.getWhiteKing()
                                  || Packaging.getChessData(i, j - 2) == Packaging
                                  .getWhiteChess()))) {
                               return false;
                           } else { // 如果没有上面那种也可以被吃的情况,就是初步最优
                               return true;
                           }
                       }
                   } else {
                       return true;
                   }
               }
           }
        }
        if (Packaging.getChessData(i, j) == Packaging.getWhiteKing()
               || Packaging.getChessData(i, j) == Packaging.getWhiteChess()) { // 如果是白方
           if ((i + 1 < 10) && (j - 1 >= 0)) {
               if (Packaging.getChessData(i + 1, j - 1) == 0) {
                   if ((i + 2 < 10) && (j - 2 >= 0)) {
                       if (Packaging.getChessData(i + 2, j - 2) != Packaging.getBlackKing()
                               && Packaging.getChessData(i + 2, j - 2) != Packaging.getBlackChess()) {
                           if ((Packaging.getChessData(i, j - 2) == 0 && (Packaging.getChessData(i + 2,
                                  j) == Packaging.getBlackKing()
                                  || Packaging.getChessData(i + 2, j) == Packaging.getBlackChess()))
                                  || (Packaging.getChessData(i + 2, j) == 0 && (Packaging
                                  .getChessData(i, j - 2) == Packaging.getBlackKing()
                                  || Packaging.getChessData(i, j - 2) == Packaging
                                  .getBlackChess()))) {
                               return false;
                           } else { // 如果没有上面那种也可以被吃的情况,就是初步最优
                               return true;
                           }
                       }
                   } else {
                       return true;
                   }
               }
           }
        }
        return false;
    }
 
    public static boolean rightDownIsGood(int i, int j) { // 右下
        if (Packaging.getChessData(i, j) == Packaging.getBlackKing()
               || Packaging.getChessData(i, j) == Packaging.getBlackChess()) { // 如果是黑方
           if ((i + 1 < 10) && (j + 1 < 10)) {
               if (Packaging.getChessData(i + 1, j + 1) == 0) {
                   if ((i + 2 < 10) && (j + 2 < 10)) {
                       if (Packaging.getChessData(i + 2, j + 2) != Packaging.getWhiteKing()
                               && Packaging.getChessData(i + 2, j + 2) != Packaging.getWhiteChess()) {
                           // 右、下
                           if ((Packaging.getChessData(i, j + 2) == 0 && (Packaging.getChessData(i + 2,
                                  j) == Packaging.getWhiteKing()
                                  || Packaging.getChessData(i + 2, j) == Packaging.getWhiteChess()))
                                  || (Packaging.getChessData(i + 2, j) == 0 && (Packaging
                                  .getChessData(i, j + 2) == Packaging.getWhiteKing()
                                  || Packaging.getChessData(i, j + 2) == Packaging
                                  .getWhiteChess()))) {
                               return false;
                           } else { // 如果没有上面那种也可以被吃的情况,就是初步最优
                               return true;
                           }
                       }
                   } else {
                       return true;
                   }
               }
           }
        }
        if (Packaging.getChessData(i, j) == Packaging.getWhiteKing()
               || Packaging.getChessData(i, j) == Packaging.getWhiteChess()) { // 如果是白方
           if ((i + 1 < 10) && (j + 1 < 10)) {
               if (Packaging.getChessData(i + 1, j + 1) == 0) {
                   if ((i + 2 < 10) && (j + 2 < 10)) {
                       if (Packaging.getChessData(i + 2, j + 2) != Packaging.getBlackKing()
                               && Packaging.getChessData(i + 2, j + 2) != Packaging.getBlackChess()) {
                           if ((Packaging.getChessData(i, j + 2) == 0 && (Packaging.getChessData(i + 2,
                                  j) == Packaging.getBlackKing()
                                  || Packaging.getChessData(i + 2, j) == Packaging.getBlackChess()))
                                  || (Packaging.getChessData(i + 2, j) == 0 && (Packaging
                                  .getChessData(i, j + 2) == Packaging.getBlackKing()
                                  || Packaging.getChessData(i, j + 2) == Packaging
                                  .getBlackChess()))) {
                               return false;
                           } else { // 如果没有上面那种也可以被吃的情况,就是初步最优
                               return true;
                           }
                       }
                   } else {
                       return true;
                   }
               }
           }
        }
        return false;
    }
 
    public static int getStep() {
        return step;
    }
 
    public static void setStep(int step) {
        MainFrame.step = step;
    }
 
    public static boolean isEnemyLaterIsEmpty() {
        return enemyLaterIsEmpty;
    }
 
    public static void setEnemyLaterIsEmpty(boolean enemyLaterIsEmpty) {
        MainFrame.enemyLaterIsEmpty = enemyLaterIsEmpty;
    }
 
    public static boolean isOwn() {
        return own;
    }
 
    public static void setOwn(boolean own) {
        MainFrame.own = own;
    }
 
    public static boolean isChessDisplay() {
        return chessDisplay;
    }
 
    public static void setChessDisplay(boolean chessDisplay) {
        MainFrame.chessDisplay = chessDisplay;
    }
 
    public static boolean isWillDisplayChess() {
        return willDisplayChess;
    }
 
    public static void setWillDisplayChess(boolean willDisplayChess) {
        MainFrame.willDisplayChess = willDisplayChess;
    }
 
    public static boolean isWillNotDisplayChess() {
        return willNotDisplayChess;
    }
 
    public static void setWillNotDisplayChess(boolean willNotDisplayChess) {
        MainFrame.willNotDisplayChess = willNotDisplayChess;
    }
 
    private boolean done;
 
    private void playChess(int x, int y) {
        this.x = x;
        this.y = y;
        done = false;
        try {
           done = AIs.ais(this.x, this.y);
        } catch (Exception e2) {
           e2.printStackTrace();
        }
        if (done) {
           SwingUtilities.invokeLater(() -> {
               scan.scan();
               scan.printWeight();
               scan.clearWeight();
 
               CanEvenJump.canEvenJump(); // 测试
               CanEvenJump.bestChess();// 测试
               try {
                   AI.ai();
               } catch (Exception e1) {
                   e1.printStackTrace();
               }
               InitData.printChessData();
               CanEvenJump.canEvenJump(); // 测试
               CanEvenJump.bestChess();// 测试
               game_field.display();
               if (game_field.gameOver()) {
                   if (game_field.whitesWin()) {
                       System.out.println("Player 1 wins");
                   } else if (game_field.blacksWin()) {
                       System.out.println("Player 2 wins");
                   } else {
                       System.out.println("Draw");
                   }
               }
               //记录棋盘
               GameRecord.backupGame();
               repaint();
           });
           if (getStep() % 2 == 1) {
               tip.setToolTip(new ImageIcon("png\\chess_black.png"),"------轮到黑方走棋------");
           } else {
               tip.setToolTip(new ImageIcon("png\\chess_white.png"),"------轮到白方走棋------");
           }
        }
        //图标显示为棋子
        else {
           if (isWillDisplayChess()) {
               setWillDisplayChess(false);
               if (!isChessDisplay()) {
                   setChessDisplay(true);
               }
           } else if (isWillNotDisplayChess()) {
               setWillNotDisplayChess(false);
               setChessDisplay(false);
           }
           if (isChessDisplay()) {
               chessPic.setLocation(x - 37, y - 62);
               chessPic.setSize(chessPic.getPreferredSize());
               point = new Point(x, y);
           }
        }
    }
 
    //鼠标控制棋子图标事件
    private class ChessMouseInputAdapter extends MouseInputAdapter {
        //棋子图标点击事件
        @Override
        public void mousePressed(MouseEvent e) {
           if (isChessDisplay()) {
               point = SwingUtilities.convertPoint(chessPic, e.getPoint(), that); //转换坐标系统
               checkJumpChess();
               playChess(point.x, point.y);
               if (done) {
                   chessDisplay = false;
                   chessPic.setLocation(-60, -60);
                   repaint();// 刷新
               }
               if (firstMoveButton.isEnabled()) {
                   firstMoveButton.setEnabled(false);
               }
           }
        }
 
        //棋子图标移动事件
        @Override
        public void mouseMoved(MouseEvent e) {
           if (isChessDisplay()) {
               Point newPoint = SwingUtilities.convertPoint(chessPic, e.getPoint(), that); //转换坐标系统
               chessPic.setLocation(chessPic.getX() + (newPoint.x - point.x), chessPic.getY() + (newPoint.y - point.y)); //设置标签图片的新位置
               point = newPoint; //更改坐标点
               repaint();// 刷新
           }
        }
    }
}

玩家走棋模块(myFrame\AIs.java

package myFrame;
 
import java.util.Arrays;
 
import monteCarloTreeSearch.*;
import moveWays.KingChess;
 
import javax.swing.*;
 
/**
 *
 * @author 名字
 * @邮箱:mail@company.com
 * @修改日期:2020.11.11
 * @描述:点击时的事件,点击走棋,接收点击坐标
 *
 */
public class AIs {
    private static String movePath = "";
    private static MonteCarloPlayer player;
    //机器下棋期间锁定棋盘的变量
    private static boolean isFinished = true;
 
    /**
     * 描述:点击时的事件(主动走棋)
     *
     * @param x:点击的xy坐标
     * @param y
     * @throws Exception
     */
    public static boolean ais(int x, int y) throws Exception {
        //增加机器下棋期间对棋盘的锁定,避免重复点击棋盘导致问题
        boolean foundChess = false;
        if (isFinished) {
           isFinished = false;
           ToolTip tip = new ToolTip();
           for (int i = 0; i < 10; i++) {
               for (int j = 0; j < 10; j++) {
                   if ((x - myFrame.InitData.getXQ(i, j) > -58) && (x - myFrame.InitData.getXQ(i, j) < 58)
                           && (y - myFrame.InitData.getYQ(i, j) > -58) && (y - myFrame.InitData.getYQ(i, j) < 58)) {
                       // 1、3是黑棋走,2、4是白棋走
                       if (AI.isZT() == false) { // 拿起棋子
                           moveWays.SearchFourAngleEmpty.rightDownSearchEmpty(i, j);
                           myFrame.AI.setI0(i);// 将拿起棋子的ij索引临时保存
                           myFrame.AI.setJ0(j);
                           if ((MainFrame.getStep() % 2) + 1 == 1) {
                               System.out.println("------轮到黑方走棋------");
                               tip.setIcon(new ImageIcon("png\\chess_black.png"));
                               player = MainFrame.player2;
                           } else {
                               System.out.println("------轮到白方走棋------");
                               tip.setIcon(new ImageIcon("png\\chess_white.png"));
                               player = MainFrame.player1;
                           }
                           if (AI.isMustEvenJump()) { // 判断是不是必须连跳
                               if (i == AI.getI1() && j == AI.getJ1()) { // i1,j1
                                  // 为上次落子时保存的索引,连跳时必须点击上次的棋子
                                  AI.setZT(true);
                                  tip.setToolTip("连跳");
                               } else {
                                  tip.setToolTip("必须点击上次落下的棋子,请从新点击");
                               }
                           } else { // 不用连跳,所以正常拿起棋子
                               if (myFrame.Packaging.getChessData(i, j) == myFrame.Packaging.getFlag()
                                      || myFrame.Packaging.getChessData(i, j) == myFrame.Packaging.getKingFlag()) {// 判断轮到哪个棋子走
                                  // flag = Chess_Data[i][j];
                                  // 如果此次必须跳棋,则必须点击可以跳的那颗棋子
                                  if (AI.isMustJumpChess()) {
                                      if (moveWays.ThisChessCanJump.thisChessCanJump(i, j)) {// 判断点击的这颗棋子能不能跳
                                          tip.setToolTip("拿起 棋子,可以跳");
                                          AI.setCanJump(true);
                                          AI.setZT(true);
                                          //显示棋子图标
                                          MainFrame.setWillDisplayChess(true);
                                      } else {
                                          tip.setToolTip("不可拿起,从新点击");
                                      }
                                  } else { // 在没有跳棋的情况下,才可以移动
                                      if (moveWays.ThisChessCanMove.thisChessCanMove(i, j)) { // 判断点击的棋子能不能移动
                                          tip.setToolTip("拿起 棋子,可以走");
                                          // canMove = true;
                                          AI.setZT(true);
                                          //显示棋子图标
                                          MainFrame.setWillDisplayChess(true);
                                      } else {
                                          tip.setToolTip("不可拿起,从新点击");
                                      }
                                  }
 
                               }
                           }
                       } else if (AI.isZT() && !AI.isMustEvenJump()
                               && (myFrame.Packaging.getChessData(i, j) == myFrame.Packaging.getFlag()
                               || myFrame.Packaging.getChessData(i, j) == myFrame.Packaging.getKingFlag())
                               && !AI.isMustJumpChess() && moveWays.ThisChessCanMove.thisChessCanMove(i, j)) {// 判断点击的棋子能不能移动
                           tip.setToolTip("拿起 棋子,可以走");
                          myFrame.AI.setI0(i);// 改变选择移动的棋子,将拿起棋子的ij索引临时保存
                           myFrame.AI.setJ0(j);
                           // canMove = true;
                           // AI.setZT(true);
                           //显示棋子图标
                           MainFrame.setWillDisplayChess(true);
                       } else if (AI.isZT() && !AI.isMustEvenJump()
                               && moveWays.ThisChessCanJump.thisChessCanJump(i, j)) {
                           tip.setToolTip("拿起 棋子,可以跳");
                           myFrame.AI.setI0(i);// 改变选择跳棋的棋子,将拿起棋子的ij索引临时保存
                           myFrame.AI.setJ0(j);
                           //显示棋子图标
                           MainFrame.setWillDisplayChess(true);
                       } else {
                           /**
                            * 如果能连跳,必须连跳 如何可以不连跳,规则? 跳棋结束后需要修改的数据:mustJumpChess、canJump、
                            * 移动结束后需要修改的数据:canMove 最后需要修改的数据:ZT
                            */
                           if (AI.isZT() == true) {// 下棋状态
                               AI.setI1(i); // i1j1为临时保存的落下棋子的索引
                               AI.setJ1(j);
 
                               // 只有必须跳,和不能跳,两种情况
                               if (AI.isMustJumpChess()) { // 如果能吃,必须吃
                                  // 此时必须进行跳棋,再判断点击的那颗棋子,能不能跳,拿起的时候已经判断
                                  if (AI.isCanJump()) {
                                      // 判断落子的位置满不满足规定
                                      if (moveWays.CanJumpToHere.canJumpToHere(AI.getI0(), AI.getJ0(), i, j)) { // 这个棋子能跳棋,且还需满足点击的位置没有棋子,才能跳,移动同此
                                          tip.setToolTip("完成跳棋,判断能不能连跳");
                                          moveWays.ChessJump.chessJump(AI.getI0(), AI.getJ0(), i, j); // 此时,被吃棋子的数据没有清零,等结束跳棋后再进行清零
                                          Movement movement = new Movement(Arrays.asList(9 - AI.getI0(), AI.getJ0()));
                                          movement.steps.add(Arrays.asList(9 - i, j));
                                          player.move(movement);
                                          AI.setZT(false);
                                          if (AI.isMustEvenJump()) {
                                              AI.setMovePath(AI.getMovePath() + "x"
                                                     + (myFrame.Packaging.getChessLocation(i, j) < 10 ? "0" : "")
                                                     + myFrame.Packaging.getChessLocation(i, j));
                                          } else {
                                              AI.setMovePath(AI.getMovePath() + " "
                                                     + (myFrame.Packaging.getChessLocation(AI.getI0(),
                                                     AI.getJ0()) < 10 ? "0" : "")
                                                     + myFrame.Packaging.getChessLocation(AI.getI0(), AI.getJ0())
                                                     + "x"
                                                     + (myFrame.Packaging.getChessLocation(i, j) < 10 ? "0" : "")
                                                     + myFrame.Packaging.getChessLocation(i, j));
                                          }
                                          setMovePath(getMovePath() + " " + myFrame.Packaging.getChessLocation(AI.getI0(), AI.getJ0())
                                                  + "x" + myFrame.Packaging.getChessLocation(i, j));
                                          // 跳棋之后,落子之后的判断
                                          // 判断能不能连跳,就是落下的那颗棋子还能不能跳
                                          // 如果能跳,则下次必须拿起这颗棋子,而且再落下时,必须跳
                                          if (moveWays.ThisChessCanJump.thisChessCanJump(i, j)) { // 如果能连跳
                                              if (myFrame.Packaging.getFlag() == myFrame.Packaging.getBlackChess()
                                                     || myFrame.Packaging.getFlag() == myFrame.Packaging
                                                      .getBlackKing()) {
                                               myFrame.Packaging.setFlag(myFrame.Packaging.getWhiteChess());
                                              } else {
                                               myFrame.Packaging.setFlag(myFrame.Packaging.getBlackChess());
                                              }
                                              myFrame.Packaging.setCount(myFrame.Packaging.getCount() + 1);
                                              AI.setMustEvenJump(true); // 拿起棋子时的判断
                                              AI.setMustJumpChess(true); // 落下棋子时的判断
                                              tip.setToolTip("能连跳,下次必须还要拿起这颗棋子");
                                          } else { // 如果不能连跳,此次跳棋结束,修改数据,进行刷新
                                              player.display();
                                              System.out.println("跳棋结束");
                                              for (int s = 0; s <= myFrame.Packaging.getCount(); s++) {
                                                  System.out
                                                         .println("打印被吃棋:" + moveWays.WillBeEatChess.getWillBeEatX(s)
                                                                 + "," + moveWays.WillBeEatChess.getWillBeEatY(s));
                                                  myFrame.Packaging.setChessData(0,
                                                         moveWays.WillBeEatChess.getWillBeEatX(s),
                                                         moveWays.WillBeEatChess.getWillBeEatY(s));
                                              }
                                              myFrame.Packaging.setCount(0); // 临时被吃棋的个数清零
                                              AI.setMustEvenJump(false);
                                              AI.setMustJumpChess(false);
                                              AI.setCanJump(false);
                                              // 跳棋结束后,棋子所在位置判断是否为王棋
                                              KingChess.becomeKingChess(i, j);// 如果满足条件,则变为王棋
                                              MainFrame.setStep(MainFrame.getStep() + 1);
                                              myFrame.ShowInformation.writeResult();
                                              AI.setMovePath("");
                                              if (!foundChess) {
                                                  foundChess = true;
                                              }
                                              //鼠标的棋子图标还原
                                              MainFrame.setWillNotDisplayChess(true);
                                              if ((MainFrame.getStep() % 2) == 0) {
                                                  tip.setToolTip(new ImageIcon("png\\chess_black.png"), "机器执黑棋正在思考......");
                                              } else {
                                                  tip.setToolTip(new ImageIcon("png\\chess_white.png"), "机器执白棋正在思考......");
                                              }
                                          }
                                      } else {
                                          tip.setToolTip("错误,请从新点击");
                                      }
                                  }
                               } else { // 不能跳棋的情况下才能移动
                                  if (moveWays.CanMoveToHere.canMoveToHere(AI.getI0(), AI.getJ0(), i, j)) {
                                      System.out.println("完成移动");
                                      moveWays.ChessMove.chessMove(AI.getI0(), AI.getJ0(), i, j); // 移动
                                      Movement movement = new Movement(Arrays.asList(9 - AI.getI0(), AI.getJ0()));
                                      movement.steps.add(Arrays.asList(9 - i, j));
                                      player.move(movement);
                                      KingChess.becomeKingChess(i, j);// 如果满足条件,则变为王棋
                                      AI.setZT(false);
                                      AI.setMovePath(AI.getMovePath() + " "
                                              + (myFrame.Packaging.getChessLocation(AI.getI0(), AI.getJ0()) < 10 ? "0"
                                              : "")
                                              + myFrame.Packaging.getChessLocation(AI.getI0(), AI.getJ0()) + "-"
                                              + (myFrame.Packaging.getChessLocation(i, j) < 10 ? "0" : "")
                                              + myFrame.Packaging.getChessLocation(i, j));
                                      MainFrame.setStep(MainFrame.getStep() + 1);
                                      myFrame.ShowInformation.writeResult();
                                      AI.setMovePath("");
                                      if (!foundChess) {
                                          foundChess = true;
                                      }
                                      //鼠标棋子图标还原
                                      MainFrame.setWillNotDisplayChess(true);
                                      if ((MainFrame.getStep() % 2)  == 1) {
                                          tip.setToolTip(new ImageIcon("png\\chess_black.png"), "机器执黑棋正在思考......");
                                      } else {
                                          tip.setToolTip(new ImageIcon("png\\chess_white.png"), "机器执白棋正在思考......");
                                      }
                                  }
                               }
                           }
                       }
                   }
               }
           }
           isFinished = true;
        }
        return foundChess;
    }
 
    public static String getMovePath() {
        return movePath;
    }
 
    public static void setMovePath(String movePath) {
        AIs.movePath = movePath;
    }
}

机器AI走棋模块(myFrame\AI.java

package myFrame;
 
import moveWays.CanEvenJump2.*;
import moveWays.KingChess;
import java.util.*;
import monteCarloTreeSearch.*;
 
import javax.swing.*;
 
/**
 * 
 * @author 名字
 * @邮箱:mail@company.com
 * @修改日期:2020.11.11
 * @描述:机器自动走棋程序
 *
 */
public class AI {
    public static boolean haveMoveData = false;
    private static boolean isFind = true; // 没有找到跳棋最多的棋子,所以最开始跳棋时,先进行测试。
    private static boolean mustJumpChess;
    private static boolean mustEvenJump;
    private static boolean ZT;
    private static int adv = 0;// 有没有最优的
    /**
     * 拿起棋子的索引
     */
    private static int i0;
    private static int j0;
    /**
     * 落下棋子的ij索引
     */
    private static int i1;
    private static int j1;
    private static boolean canJump;
    private static boolean canMove = true;
    private static boolean goodStep;
    private static String movePath = "";
 
    /**
     * 下次即将要走的位置
     */
    private static int i2;
    private static int j2;
 
    private static int ix;
    private static int iy;
 
    public static boolean isMustJumpChess() {
        return mustJumpChess;
    }
 
    public static void setMustJumpChess(boolean mustJumpChess) {
        AI.mustJumpChess = mustJumpChess;
    }
 
    public static boolean isMustEvenJump() {
        return mustEvenJump;
    }
 
    public static void setMustEvenJump(boolean mustEvenJump) {
        AI.mustEvenJump = mustEvenJump;
    }
 
    public static boolean isZT() {
        return ZT;
    }
 
    public static void setZT(boolean zT) {
        ZT = zT;
    }
 
    public static int getI1() {
        return i1;
    }
 
    public static void setI1(int i1) {
        AI.i1 = i1;
    }
 
    public static int getI0() {
        return i0;
    }
 
    public static void setI0(int i0) {
        AI.i0 = i0;
    }
 
    public static int getJ0() {
        return j0;
    }
 
    public static void setJ0(int j0) {
        AI.j0 = j0;
    }
 
    public static int getJ1() {
        return j1;
    }
 
    public static void setJ1(int j1) {
        AI.j1 = j1;
    }
 
    public static boolean isCanJump() {
        return canJump;
    }
 
    public static void setCanJump(boolean canJump) {
        AI.canJump = canJump;
    }
 
    public static boolean isGoodStep() {
        return goodStep;
    }
 
    public static void setGoodStep(boolean goodStep) {
        AI.goodStep = goodStep;
    }
 
    public static String getMovePath() {
        return movePath;
    }
 
    public static void setMovePath(String movePath) {
        AI.movePath = movePath;
    }
 
    public static int getI2() {
        return i2;
    }
 
    public static void setI2(int i2) {
        AI.i2 = i2;
    }
 
    public static int getJ2() {
        return j2;
    }
 
    public static void setJ2(int j2) {
        AI.j2 = j2;
    }
 
    private static MonteCarloPlayer player;
 
    /**
     * 自动生成满足规则的ij 描述:
     * 
     * @throws Exception
     */
    public static void ai() throws Exception {
        if (moveWays.IsWin.isWin() == 1 || moveWays.IsWin.isWin() == 2 || moveWays.IsWin.isWin() == 3) {
           // 写入比赛结果信息
           myFrame.ShowInformation.writeFinalResult();
           myFrame.ShowResult.showWin();
           // 写入初始信息
           myFrame.ShowInformation.writeInitInformation();
        }
        if ((MainFrame.getStep() % 2) + 1 == 1) {
           System.out.println("------轮到黑方走棋------");
           player = MainFrame.player2;
        } else {
           System.out.println("------轮到白方走棋------");
           player = MainFrame.player1;
        }
 
        // 先判断是不是必须跳棋
        if (((myFrame.Packaging.getFlag() == myFrame.Packaging.getWhiteChess()
               || myFrame.Packaging.getFlag() == myFrame.Packaging.getWhiteKing())
               && moveWays.HaveChessCanJump.haveWriteChessCanJump())
               || (((myFrame.Packaging.getFlag() == myFrame.Packaging.getBlackChess()
               || myFrame.Packaging.getFlag() == myFrame.Packaging.getBlackKing())
               && moveWays.HaveChessCanJump.haveBlackChessCanJump()))) {
           if (mustEvenJump) {
 
           } else {
               mustJumpChess = true;
               haveMoveData = true;
               // 直接拿起棋子
               i0 = moveWays.CanEvenJump.getBestJumpChessI();
               j0 = moveWays.CanEvenJump.getBestJumpChessJ();
               canJump = true;
               ZT = true;
           }
        }
        ToolTip tip = new ToolTip();
 
        if (!ZT) { // 拿起棋子
           outer: for (int i = 0; i < 10; i++) {
               for (int j = 0; j < 10; j++) {
                   i0 = i;// 将拿起棋子的ij索引临时保存
                   j0 = j;
                   if (mustEvenJump) { // 判断是不是必须连跳
                       if (i == i1 && j == j1) { // i1,j1为上次落子时保存的索引,连跳时必须点击上次的棋子
                           ZT = true;
                           System.out.println("连跳");
                           break outer;
                       } else {
                           continue;
                       }
                   } else { // 不用连跳,所以正常拿起棋子
                       if (myFrame.Packaging.getChessData(i, j) == myFrame.Packaging.getFlag()
                               || myFrame.Packaging.getChessData(i, j) == myFrame.Packaging.getKingFlag()) {// 判断轮到哪个棋子走
                           if (mustJumpChess) {
                               if (moveWays.ThisChessCanEvenJump.thisChessCanEvenJump(i, j)) {
                                  System.out.println("拿起 棋子,可以跳");
                                  canJump = true;
                                  ZT = true;
                                  break outer;
                               } else {
                                  continue;
                               }
                           } else { // 在没有跳棋的情况下,才可以移动
                               // 先看看有没有己方能被吃的棋子,有的话先搜寻那颗棋子
                               out: for (int ws = 0; ws < 10; ws++) {
                                  for (int qs = 0; qs < 10; qs++) {
                                      if (myFrame.Packaging.getChessData(ws, qs) == myFrame.Packaging.getFlag()
                                              || myFrame.Packaging.getChessData(ws, qs) == myFrame.Packaging
                                                      .getKingFlag()) {// 判断轮到哪个棋子走
                                          if (MainFrame.thisStepIsGood(ws, qs)) {
                                              // 如果搜寻之前有能被吃掉的棋子,则默认最优
                                              if (moveWays.SimulateMove.simulateMove(ws, qs)) {
                                                  adv++;
                                                  break out;
                                              } else {
                                                  continue;
 
                                              }
                                          }
                                      }
                                  }
                               }
 
                               if (moveWays.ThisChessCanMove.thisChessCanMove(i0, j0)) { // 判断点击的棋子能不能移动
                                  if (adv > 0) {
                                      adv = 0;
                                      if (MainFrame.thisStepIsGood(i, j)) {
                                          // 在最优的情况下,再全局判断有没有能被吃的棋子
                                          // 如果有,说明移动之后导致己方有棋子能被吃,不算最优,重新搜寻
                                          if (moveWays.SimulateMove.simulateMove(i0, j0)) {
                                              System.out.println("拿起 棋子,可以走");
                                              canMove = true;
                                              goodStep = true;
                                              ZT = true;
                                              break outer;
                                          }
                                      } else {
 
                                      }
                                  } else {
                                      // 当棋子全都没有最优的情况下,才可以选择随机的
                                      System.out.println("拿起棋子");
                                      ZT = true;
                                      break outer;
                                  }
 
                               } else {
                                  continue;
                               }
                           }
                       }
                   }
               }
           }
        } // 放下棋子
        if (ZT) {// 下棋状态
           outer: for (int i = 0; i < 10; i++) {
               for (int j = 0; j < 10; j++) {
                   i1 = i; // i1j1为临时保存的落下棋子的索引
                   j1 = j;
                   if (haveMoveData) {
                       i1 = moveWays.CanEvenJump.getBestJumpChessI1();
                       j1 = moveWays.CanEvenJump.getBestJumpChessJ1();
                       haveMoveData = false;
                   }
                   // 只有必须跳,和不能跳,两种情况
                   if (mustJumpChess) { // 如果能吃,必须吃
                       // 此时必须进行跳棋,再判断点击的那颗棋子,能不能跳,拿起的时候已经判断
                       // 判断落子的位置满不满足规定
                       if (moveWays.CanJumpToHere.canJumpToHere(i0, j0, i1, j1)) { // 这个棋子能跳棋,且还需满足点击的位置没有棋子,才能跳,移动同此
                           String simulateMoveColor = MainFrame.isOwn() ? "BLACK" : "WHITE";
                           List<NodeStep> wayEat = moveWays.CanEvenJump2.canEvenJump(simulateMoveColor); // 测试
                           int lastX = 0, lastY = 0;
                           boolean isFirstJumpPath = true;
                           for (NodeStep ns : wayEat) {
                               moveWays.ChessJump.chessJump(ns.ndstt.x, ns.ndstt.y, ns.ndend.x, ns.ndend.y);
                               Movement movement = new Movement(Arrays.asList(9 - ns.ndstt.x, ns.ndstt.y));
                               movement.steps.add(Arrays.asList(9 - ns.ndend.x, ns.ndend.y));
 
                               player.move(movement);
                               if (isFirstJumpPath) {
                                   AI.setMovePath(AI.getMovePath() + " "
                                          + (myFrame.Packaging.getChessLocation(ns.ndstt.x, ns.ndstt.y) < 10 ? "0"
                                          : "")
                                          + myFrame.Packaging.getChessLocation(ns.ndstt.x, ns.ndstt.y) + "x"
                                          + (myFrame.Packaging.getChessLocation(ns.ndend.x, ns.ndend.y) < 10 ? "0"
                                          : "")
                                          + myFrame.Packaging.getChessLocation(ns.ndend.x, ns.ndend.y));
                                  isFirstJumpPath = false;
                               } else {
                                   AI.setMovePath(AI.getMovePath() + "x"
                                          + (myFrame.Packaging.getChessLocation(ns.ndend.x, ns.ndend.y) < 10 ? "0"
                                          : "")
                                          + myFrame.Packaging.getChessLocation(ns.ndend.x, ns.ndend.y));
                               }
                               System.out.println("能连跳,下次必须还要拿起这颗棋子");
                               myFrame.Packaging.setCount(myFrame.Packaging.getCount() + 1);
                               moveWays.WillBeEatChess.setWillBeEatX(ns.ndeat.x, myFrame.Packaging.getCount());
                               moveWays.WillBeEatChess.setWillBeEatY(ns.ndeat.y, myFrame.Packaging.getCount());
                               lastX = ns.ndend.x;
                               lastY = ns.ndend.y;
                           }
 
                           // 跳棋结束后,棋子所在位置判断是否为王棋
                           KingChess.becomeKingChess(lastX, lastY);// 如果满足条件,则变为王棋
                           ZT = false;
                           player.display();
                           System.out.println("连跳结束");
                           ArrayList<List<Integer>> eaten = new ArrayList<>();
                           for (int s = 0; s <= myFrame.Packaging.getCount(); s++) {
                               myFrame.Packaging.setChessData(0, moveWays.WillBeEatChess.getWillBeEatX(s),
                                      moveWays.WillBeEatChess.getWillBeEatY(s));
                               eaten.add(Arrays.asList(9 - moveWays.WillBeEatChess.getWillBeEatX(s),
                                      moveWays.WillBeEatChess.getWillBeEatY(s)));
                           }
                           myFrame.Packaging.setCount(0); // 临时被吃棋的个数清零
                           mustEvenJump = false;
                           mustJumpChess = false;
                           canJump = false;
 
                           // 此次跳棋全部结束,修改变量
                           if (isFind) {
                               moveWays.ThisChessCanJump.setCanJumpChessIndex(0);
                               moveWays.ThisChessCanJump.setCanJumpChessNum(0);
                               moveWays.ThisChessCanJump.setCanJumpChessTest(0);
                               moveWays.ThisChessCanJump.setEvenJumpCountIndex(0);
                               moveWays.ThisChessCanJump.setEvenJumpCountMax(0);
                               for (int w = 0; w < 20; w++) {
                                   moveWays.ThisChessCanJump.setCanJumpChessX(0, w);
                                   moveWays.ThisChessCanJump.setCanJumpChessY(0, w);
                                   moveWays.ThisChessCanJump.setEvenJumpCount(0, w);
                               }
                               MainFrame.setStep(MainFrame.getStep() + 1);
 
                               // 写入到文件中
                               myFrame.ShowInformation.writeResult();
                               movePath = "";
                               break outer;
                           }
                           if (MainFrame.getStep() % 2 == 0) {
                               tip.setToolTip(new ImageIcon("png\\chess_black.png"),"------轮到黑方走棋------");
                           } else {
                               tip.setToolTip(new ImageIcon("png\\chess_white.png"),"------轮到白方走棋------");
                           }
                       } else {
                           continue;
                       }
                   } else { // 不能跳棋的情况下才能移动
                       try {
                           Movement move = player.move();
                           int i3 = 9 - move.steps.get(0).get(0);
                           int j3 = move.steps.get(0).get(1);
                           int i4 = 9 - move.steps.get(1).get(0);
                           int j4 = move.steps.get(1).get(1);
                           setCanMove(true);// 先将修改为true可以走,然后判断,如果可以走,则不修改默认走,如果不能走,则修改
                           moveWays.ChessMove.chessMove(i3, j3, i4, j4); // 移动
                           KingChess.becomeKingChess(i4, i4);// 如果满足条件,则变为王棋
                           canMove = false;
                           goodStep = false;
                           ZT = false;
                           AI.setMovePath(AI.getMovePath() + " "
                                  + (myFrame.Packaging.getChessLocation(i3, j3) < 10 ? "0" : "")
                                  + myFrame.Packaging.getChessLocation(i3, j3) + "-"
                                  + (myFrame.Packaging.getChessLocation(i4, j4) < 10 ? "0" : "")
                                  + myFrame.Packaging.getChessLocation(i4, j4));
                       } catch (Exception ex) {
                           // 将走的状态添加到数组
                           if (goodStep) { // 如果应该走最优
                               adv = 0;
                               Movement movement = new Movement(Arrays.asList(9 - i0, j0));
                               movement.steps.add(Arrays.asList(9 - i2, j2));
                               player.move(movement);
                               moveWays.ChessMove.chessMove(i0, j0, i2, j2); // 移动
                               KingChess.becomeKingChess(i2, j2);// 如果满足条件,则变为王棋
                               canMove = false;
                               goodStep = false;
                               ZT = false;
                               AI.setMovePath(AI.getMovePath() + " "
                                      + (myFrame.Packaging.getChessLocation(AI.getI0(), AI.getJ0()) < 10 ? "0" : "")
                                      + myFrame.Packaging.getChessLocation(AI.getI0(), AI.getJ0()) + "-"
                                      + (myFrame.Packaging.getChessLocation(i2, j2) < 10 ? "0" : "")
                                      + myFrame.Packaging.getChessLocation(i2, j2));
                           } else { // 如果不能走最优的
                               adv = 0;
                               if (moveWays.CanMoveToHere.canMoveToHere(i0, j0, i, j)) {
                                  setCanMove(true);// 先将修改为true可以走,然后判断,如果可以走,则不修改默认走,如果不能走,则修改
                                  Movement movement = new Movement(Arrays.asList(9 - i0, j0));
                                   movement.steps.add(Arrays.asList(9 - i, j));
                                  player.move(movement);
                                   moveWays.ChessMove.chessMove(i0, j0, i, j); // 移动
                                   KingChess.becomeKingChess(i, j);// 如果满足条件,则变为王棋
                                  ZT = false;
                                   AI.setMovePath(AI.getMovePath() + " "
                                          + (myFrame.Packaging.getChessLocation(AI.getI0(), AI.getJ0()) < 10 ? "0"
                                          : "")
                                          + myFrame.Packaging.getChessLocation(AI.getI0(), AI.getJ0()) + "-"
                                          + (myFrame.Packaging.getChessLocation(i, j) < 10 ? "0" : "")
                                          + myFrame.Packaging.getChessLocation(i, j));
                               }
                           }
                       }
                       MainFrame.setStep(MainFrame.getStep() + 1);
                       myFrame.ShowInformation.writeResult();
                       movePath = "";
                       if (MainFrame.getStep() % 2 == 0) {
                           tip.setToolTip(new ImageIcon("png\\chess_black.png"),"------轮到黑方走棋------");
                       } else {
                           tip.setToolTip(new ImageIcon("png\\chess_white.png"),"------轮到白方走棋------");
                       }
                       break outer;
                   }
               }
           }
        }
    }
 
    public static int getIx() {
        return ix;
    }
 
    public static void setIx(int ix) {
        AI.ix = ix;
    }
 
    public static int getIy() {
        return iy;
    }
 
    public static void setIy(int iy) {
        AI.iy = iy;
    }
 
    public static boolean isCanMove() {
        return canMove;
    }
 
    public static void setCanMove(boolean canMove) {
        AI.canMove = canMove;
    }
}

棋子移动模块(moveWays\ChessMove.java

package moveWays;
 
/**
 * 
 * @author 名字
 * @邮箱:mail@company.com
 * @修改日期:2020.11.11
 * @描述:用于棋子的移动后,修改数据
 *
 */
public class ChessMove {
    /**
     * 
     * 描述:用于棋子的移动后,修改数据
     * 
     * @param i0 拿起棋子时的索引
     * @param j0
     * @param i  放下棋子时的索引
     * @param j
     */
    public static void chessMove(int i0, int j0, int i, int j) {
        if (myFrame.Packaging.getChessData(i0, j0) == myFrame.Packaging.getBlackKing()) {
 
           myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
         myFrame.Packaging.setChessData(myFrame.Packaging.getBlackKing(), i, j); // 将落下的那颗棋子的值变
                                                                                // 拿起时的值
         myFrame.Packaging.setKingFlag(myFrame.Packaging.getWhiteKing()); // 修改棋子标志
         myFrame.Packaging.setFlag(myFrame.Packaging.getWhiteChess());
        }
        if (myFrame.Packaging.getChessData(i0, j0) == myFrame.Packaging.getWhiteKing()) {
 
           myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
         myFrame.Packaging.setChessData(myFrame.Packaging.getWhiteKing(), i, j); // 将落下的那颗棋子的值变
                                                                                // 拿起时的值
         myFrame.Packaging.setKingFlag(myFrame.Packaging.getBlackKing()); // 修改棋子标志
         myFrame.Packaging.setFlag(myFrame.Packaging.getBlackChess());
        }
        // 如果是黑棋
        if (myFrame.Packaging.getChessData(i0, j0) == myFrame.Packaging.getBlackChess()) {
           if (moveWays.JudgeFourAngleCanMove.leftDownCanMove(i0, j0)) { // 左下
               if (i == (i0 + 1) && j == (j0 - 1)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
                myFrame.Packaging.setChessData(myFrame.Packaging.getBlackChess(), i, j); // 将落下的那颗棋子的值变
                                                                                            // 拿起时的值
               }
 
           }
           if (moveWays.JudgeFourAngleCanMove.rightDownCanMove(i0, j0)) { // 右下
               if (i == (i0 + 1) && j == (j0 + 1)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
                myFrame.Packaging.setChessData(myFrame.Packaging.getBlackChess(), i, j); // 将落下的那颗棋子的值变
                                                                                            // 拿起时的值
               }
           }
         myFrame.Packaging.setKingFlag(myFrame.Packaging.getWhiteKing()); // 修改棋子标志
         myFrame.Packaging.setFlag(myFrame.Packaging.getWhiteChess());
        }
        // 如果是白棋
        if (myFrame.Packaging.getChessData(i0, j0) == myFrame.Packaging.getWhiteChess()) {
           if (moveWays.JudgeFourAngleCanMove.leftUpCanMove(i0, j0)) { // 左上
               if (i == (i0 - 1) && j == (j0 - 1)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
                myFrame.Packaging.setChessData(myFrame.Packaging.getWhiteChess(), i, j);
                   ; // 将落下的那颗棋子的值变 拿起时的值
               }
           }
           if (moveWays.JudgeFourAngleCanMove.rightUpCanMove(i0, j0)) { // 右上
               if (i == (i0 - 1) && j == (j0 + 1)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
                myFrame.Packaging.setChessData(myFrame.Packaging.getWhiteChess(), i, j); // 将落下的那颗棋子的值变
                                                                                            // 拿起时的值
               }
           }
         myFrame.Packaging.setKingFlag(myFrame.Packaging.getBlackKing()); // 修改棋子标志
         myFrame.Packaging.setFlag(myFrame.Packaging.getBlackChess());
        }
    }
}

棋子跳吃模块(moveWays\ChessJump.java)

package moveWays;
 
/**
 *
 * @author 名字
 * @邮箱:mail@company.com
 * @修改日期:2020.11.11
 * @描述:执行跳棋,修改数据。
 *
 */
public class ChessJump {
 
    /**
     *
     * 描述: 跳棋时,拿起的那颗棋子的数据变为0,落下位置的数据变为拿起的那颗棋子的数据,
     * 但是,被吃掉的那颗棋子的数据暂时变为5,就是变成障碍,将他的索引存到数组中, 待跳棋结束后,再修改被吃掉的棋子,变为0
     *
     * @param i0:拿起棋子的位置
     * @param j0
     * @param i:落下棋子的位置
     * @param j
     */
    public static void chessJump(int i0, int j0, int i, int j) {
        // 如果是黑王
        if (myFrame.Packaging.getChessData(i0, j0) == myFrame.Packaging.getBlackKing()) {
           myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
 
         myFrame.Packaging.setChessData(myFrame.Packaging.getBlackKing(), i, j); // 将落下的那颗棋子的值变 拿起时的值
           // 将被吃的棋子添加到数组中
         moveWays.WillBeEatChess.setWillBeEatX(myFrame.Packaging.getI3(), myFrame.Packaging.getCount());
         moveWays.WillBeEatChess.setWillBeEatY(myFrame.Packaging.getJ3(), myFrame.Packaging.getCount());
         myFrame.Packaging.setKingFlag(myFrame.Packaging.getWhiteKing()); // 修改棋子标志
         myFrame.Packaging.setFlag(myFrame.Packaging.getWhiteChess());
          searchTree.InitialSearch.setEatChessColor1(myFrame.Packaging
                           .getChessData(moveWays.WillBeEatChess.getWillBeEatX(0), moveWays.WillBeEatChess.getWillBeEatY(0)),
                   searchTree.InitialSearch.getCountStep());
          searchTree.InitialSearch.setEatChessColor2(myFrame.Packaging
                           .getChessData(moveWays.WillBeEatChess.getWillBeEatX(1), moveWays.WillBeEatChess.getWillBeEatY(1)),
                   searchTree.InitialSearch.getCountStep());
           myFrame.Packaging.setChessData(5, myFrame.Packaging.getI3(), myFrame.Packaging.getJ3()); // 将中间的被吃掉的那颗棋子值变5
        }
        // 如果是白王
        if (myFrame.Packaging.getChessData(i0, j0) == myFrame.Packaging.getWhiteKing()) {
           myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
 
         myFrame.Packaging.setChessData(myFrame.Packaging.getWhiteKing(), i, j); // 将落下的那颗棋子的值变 拿起时的值
           // 将被吃的棋子添加到数组中
         moveWays.WillBeEatChess.setWillBeEatX(myFrame.Packaging.getI3(), myFrame.Packaging.getCount());
         moveWays.WillBeEatChess.setWillBeEatY(myFrame.Packaging.getJ3(), myFrame.Packaging.getCount());
         myFrame.Packaging.setKingFlag(myFrame.Packaging.getBlackKing()); // 修改棋子标志
         myFrame.Packaging.setFlag(myFrame.Packaging.getBlackChess());
          searchTree.InitialSearch.setEatChessColor1(myFrame.Packaging
                           .getChessData(moveWays.WillBeEatChess.getWillBeEatX(0), moveWays.WillBeEatChess.getWillBeEatY(0)),
                   searchTree.InitialSearch.getCountStep());
          searchTree.InitialSearch.setEatChessColor2(myFrame.Packaging
                           .getChessData(moveWays.WillBeEatChess.getWillBeEatX(1), moveWays.WillBeEatChess.getWillBeEatY(1)),
                   searchTree.InitialSearch.getCountStep());
           myFrame.Packaging.setChessData(5, myFrame.Packaging.getI3(), myFrame.Packaging.getJ3()); // 将中间的被吃掉的那颗棋子值变5
        }
        // 如果是黑棋
        if (myFrame.Packaging.getChessData(i0, j0) == myFrame.Packaging.getBlackChess()) {
           if (moveWays.JudgeFourAngleCanJump.leftUpCanJump(i0, j0)) { // 左上能跳
               if (i == (i0 - 2) && j == (j0 - 2)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
 
                myFrame.Packaging.setChessData(myFrame.Packaging.getBlackChess(), i, j); // 将落下的那颗棋子的值变 拿起时的值
                   // 将被吃的棋子添加到数组中
                   moveWays.WillBeEatChess.setWillBeEatX(i0 - 1, myFrame.Packaging.getCount());
                   moveWays.WillBeEatChess.setWillBeEatY(j0 - 1, myFrame.Packaging.getCount());
                   searchTree.InitialSearch
                           .setEatChessColor1(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(0),
                                          moveWays.WillBeEatChess.getWillBeEatY(0)),
                                   searchTree.InitialSearch.getCountStep());
                   searchTree.InitialSearch
                           .setEatChessColor2(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(1),
                                          moveWays.WillBeEatChess.getWillBeEatY(1)),
                                   searchTree.InitialSearch.getCountStep());
                   myFrame.Packaging.setChessData(5, i0 - 1, j0 - 1); // 将中间的被吃掉的那颗棋子值变5
               }
           }
           if (moveWays.JudgeFourAngleCanJump.rightUpCanJump(i0, j0)) { // 右上
               if (i == (i0 - 2) && j == (j0 + 2)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
 
                myFrame.Packaging.setChessData(myFrame.Packaging.getBlackChess(), i, j); // 将落下的那颗棋子的值变 拿起时的值
                   // 将被吃的棋子添加到数组中
                   moveWays.WillBeEatChess.setWillBeEatX(i0 - 1, myFrame.Packaging.getCount());
                   moveWays.WillBeEatChess.setWillBeEatY(j0 + 1, myFrame.Packaging.getCount());
                   searchTree.InitialSearch
                           .setEatChessColor1(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(0),
                                          moveWays.WillBeEatChess.getWillBeEatY(0)),
                                   searchTree.InitialSearch.getCountStep());
                   searchTree.InitialSearch
                           .setEatChessColor2(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(1),
                                          moveWays.WillBeEatChess.getWillBeEatY(1)),
                                   searchTree.InitialSearch.getCountStep());
                   myFrame.Packaging.setChessData(5, i0 - 1, j0 + 1); // 将中间的被吃掉的那颗棋子值变5
               }
           }
           if (moveWays.JudgeFourAngleCanJump.leftDownCanJump(i0, j0)) { // 左下
               if (i == (i0 + 2) && j == (j0 - 2)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
 
                myFrame.Packaging.setChessData(myFrame.Packaging.getBlackChess(), i, j); // 将落下的那颗棋子的值变 拿起时的值
                   // 将被吃的棋子添加到数组中
                   moveWays.WillBeEatChess.setWillBeEatX(i0 + 1, myFrame.Packaging.getCount());
                   moveWays.WillBeEatChess.setWillBeEatY(j0 - 1, myFrame.Packaging.getCount());
                   searchTree.InitialSearch
                           .setEatChessColor1(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(0),
                                          moveWays.WillBeEatChess.getWillBeEatY(0)),
                                   searchTree.InitialSearch.getCountStep());
                   searchTree.InitialSearch
                           .setEatChessColor2(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(1),
                                          moveWays.WillBeEatChess.getWillBeEatY(1)),
                                   searchTree.InitialSearch.getCountStep());
                   myFrame.Packaging.setChessData(5, i0 + 1, j0 - 1); // 将中间的被吃掉的那颗棋子值变5
               }
           }
           if (moveWays.JudgeFourAngleCanJump.rightDownCanJump(i0, j0)) { // 右下
               if (i == (i0 + 2) && j == (j0 + 2)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
 
                myFrame.Packaging.setChessData(myFrame.Packaging.getBlackChess(), i, j); // 将落下的那颗棋子的值变 拿起时的值
                   // 将被吃的棋子添加到数组中
                   moveWays.WillBeEatChess.setWillBeEatX(i0 + 1, myFrame.Packaging.getCount());
                   moveWays.WillBeEatChess.setWillBeEatY(j0 + 1, myFrame.Packaging.getCount());
                   searchTree.InitialSearch
                           .setEatChessColor1(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(0),
                                          moveWays.WillBeEatChess.getWillBeEatY(0)),
                                   searchTree.InitialSearch.getCountStep());
                   searchTree.InitialSearch
                           .setEatChessColor2(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(1),
                                          moveWays.WillBeEatChess.getWillBeEatY(1)),
                                   searchTree.InitialSearch.getCountStep());
                   myFrame.Packaging.setChessData(5, i0 + 1, j0 + 1); // 将中间的被吃掉的那颗棋子值变5
               }
           }
 
         myFrame.Packaging.setKingFlag(myFrame.Packaging.getWhiteKing()); // 修改棋子标志
         myFrame.Packaging.setFlag(myFrame.Packaging.getWhiteChess());
        }
        // 如果是白棋
        if (myFrame.Packaging.getChessData(i0, j0) == myFrame.Packaging.getWhiteChess()) {
           if (moveWays.JudgeFourAngleCanJump.leftUpCanJump(i0, j0)) { // 左上能跳
               if (i == (i0 - 2) && j == (j0 - 2)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
 
                myFrame.Packaging.setChessData(myFrame.Packaging.getWhiteChess(), i, j); // 将落下的那颗棋子的值变 拿起时的值
                   // 将被吃的棋子添加到数组中
                   moveWays.WillBeEatChess.setWillBeEatX(i0 - 1, myFrame.Packaging.getCount());
                   moveWays.WillBeEatChess.setWillBeEatY(j0 - 1, myFrame.Packaging.getCount());
                   searchTree.InitialSearch
                           .setEatChessColor1(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(0),
                                          moveWays.WillBeEatChess.getWillBeEatY(0)),
                                   searchTree.InitialSearch.getCountStep());
                   searchTree.InitialSearch
                           .setEatChessColor2(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(1),
                                          moveWays.WillBeEatChess.getWillBeEatY(1)),
                                   searchTree.InitialSearch.getCountStep());
                   myFrame.Packaging.setChessData(5, i0 - 1, j0 - 1); // 将中间的被吃掉的那颗棋子值变5
               }
           }
           if (moveWays.JudgeFourAngleCanJump.rightUpCanJump(i0, j0)) { // 右上
               if (i == (i0 - 2) && j == (j0 + 2)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
 
                myFrame.Packaging.setChessData(myFrame.Packaging.getWhiteChess(), i, j); // 将落下的那颗棋子的值变 拿起时的值
                   // 将被吃的棋子添加到数组中
                   moveWays.WillBeEatChess.setWillBeEatX(i0 - 1, myFrame.Packaging.getCount());
                   moveWays.WillBeEatChess.setWillBeEatY(j0 + 1, myFrame.Packaging.getCount());
                   searchTree.InitialSearch
                           .setEatChessColor1(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(0),
                                          moveWays.WillBeEatChess.getWillBeEatY(0)),
                                   searchTree.InitialSearch.getCountStep());
                   searchTree.InitialSearch
                           .setEatChessColor2(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(1),
                                          moveWays.WillBeEatChess.getWillBeEatY(1)),
                                   searchTree.InitialSearch.getCountStep());
                   myFrame.Packaging.setChessData(5, i0 - 1, j0 + 1); // 将中间的被吃掉的那颗棋子值变5
               }
           }
           if (moveWays.JudgeFourAngleCanJump.leftDownCanJump(i0, j0)) { // 左下
               if (i == (i0 + 2) && j == (j0 - 2)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
 
                myFrame.Packaging.setChessData(myFrame.Packaging.getWhiteChess(), i, j); // 将落下的那颗棋子的值变 拿起时的值
                   // 将被吃的棋子添加到数组中
                   moveWays.WillBeEatChess.setWillBeEatX(i0 + 1, myFrame.Packaging.getCount());
                   moveWays.WillBeEatChess.setWillBeEatY(j0 - 1, myFrame.Packaging.getCount());
                   searchTree.InitialSearch
                           .setEatChessColor1(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(0),
                                          moveWays.WillBeEatChess.getWillBeEatY(0)),
                                   searchTree.InitialSearch.getCountStep());
                   searchTree.InitialSearch
                           .setEatChessColor2(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(1),
                                          moveWays.WillBeEatChess.getWillBeEatY(1)),
                                   searchTree.InitialSearch.getCountStep());
                   myFrame.Packaging.setChessData(5, i0 + 1, j0 - 1); // 将中间的被吃掉的那颗棋子值变5
               }
           }
           if (moveWays.JudgeFourAngleCanJump.rightDownCanJump(i0, j0)) { // 右下
               if (i == (i0 + 2) && j == (j0 + 2)) {
                   myFrame.Packaging.setChessData(0, i0, j0); // 将拿起的那颗棋子值变0
 
                myFrame.Packaging.setChessData(myFrame.Packaging.getWhiteChess(), i, j); // 将落下的那颗棋子的值变 拿起时的值
                   // 将被吃的棋子添加到数组中
                   moveWays.WillBeEatChess.setWillBeEatX(i0 + 1, myFrame.Packaging.getCount());
                   moveWays.WillBeEatChess.setWillBeEatY(j0 + 1, myFrame.Packaging.getCount());
                   searchTree.InitialSearch
                           .setEatChessColor1(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(0),
                                          moveWays.WillBeEatChess.getWillBeEatY(0)),
                                   searchTree.InitialSearch.getCountStep());
                   searchTree.InitialSearch
                           .setEatChessColor2(
                                myFrame.Packaging.getChessData(moveWays.WillBeEatChess.getWillBeEatX(1),
                                          moveWays.WillBeEatChess.getWillBeEatY(1)),
                                   searchTree.InitialSearch.getCountStep());
                   myFrame.Packaging.setChessData(5, i0 + 1, j0 + 1); // 将中间的被吃掉的那颗棋子值变5
               }
           }
         myFrame.Packaging.setKingFlag(myFrame.Packaging.getBlackKing()); // 修改棋子标志
         myFrame.Packaging.setFlag(myFrame.Packaging.getBlackChess());
        }
    }
}

蒙特卡洛树搜索模块(monteCarloTreeSearch\Field.java

package monteCarloTreeSearch;
 
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import org.apache.commons.lang3.SerializationUtils;
 
 
/**
 * 
 * @author 名字
 * @邮箱:mail@company.com
 * @修改日期:2020.11.11
 * @描述:国际跳棋
 *
 */
public class Field implements Serializable {
    private static final long serialVersionUID = 1L;
    public final static int WHITE = 1;
    public final static int BLACK = 2;
    public final static int EMPTY = 0;
    public final static int BLOCK = 3;
 
    public final static int SIZE = 10;
    public final static double FIGURES = (3.0 * SIZE) / 2.0;
    private Vector<Vector<Integer>> desk = new Vector<>();
    public HashMap<Integer, Integer> score;
 
    private HashMap<Integer, Integer> kingrows;
    private HashMap<Integer, Integer> hashDict;
 
    @SuppressWarnings("serial")
    public Field() {
        for (int i = 0; i < SIZE; ++i) {
           Vector<Integer> temp = new Vector<Integer>();
           for (int j = 0; j < SIZE; ++j) {
               temp.add(-1);
           }
           getDesk().add(temp);
        }
        score = new HashMap<Integer, Integer>() {
           {
               put(WHITE, 0);
               put(BLACK, 0);
               put(-1, -1);
           }
        };
        setKingrows(new HashMap<Integer, Integer>() {
           {
               put(WHITE, SIZE - 1);
               put(BLACK, 0);
           }
        });
        setHashDict(new HashMap<>());
        // fill whites
        for (int i = 0; i < SIZE / 2 - 1; ++i) {
           for (int j = 0; j < SIZE; ++j) {
               if ((i + j) % 2 == 0) {
                   getDesk().get(i).set(j, 1);
               } else {
                   getDesk().get(i).set(j, 3);
               }
           }
        }
        // fill space
        for (int i = SIZE / 2 - 1; i < SIZE / 2 + 1; ++i) {
           for (int j = 0; j < SIZE; ++j) {
               if ((i + j) % 2 == 0) {
                   getDesk().get(i).set(j, 0);
               } else {
                   getDesk().get(i).set(j, 3);
               }
           }
        }
        // fill blacks
        for (int i = SIZE / 2 + 1; i < SIZE; ++i) {
           for (int j = 0; j < SIZE; ++j) {
               if ((i + j) % 2 == 0) {
                   getDesk().get(i).set(j, 2);
               } else {
                   getDesk().get(i).set(j, 3);
               }
           }
        }
    }
 
    public int invcolor(int color) {
        if (color == WHITE) {
           return BLACK;
        } else if (color == BLACK) {
           return WHITE;
        }
        return color;
    }
 
    private List<Integer> move(Vector<Vector<Integer>> desk, Map<Integer, Integer> hashDict,
           Map<Integer, Integer> score, Movement movement, int color) throws Exception {
        ArrayList<List<Integer>> steps = SerializationUtils.clone(movement.steps);
        if (steps.size() < 2) {
           throw new Exception("empty move");
        }
        int x0 = steps.get(0).get(0);
        int y0 = steps.get(0).get(1);
        steps.remove(0);
        if (desk.get(x0).get(y0) % 10.0 != color) {
           display();
           throw new Exception("illegal move x0=" + x0 + " y0=" + y0 + " desk.get(x0).get(y0) % 10.0="
                   + (desk.get(x0).get(y0) % 10.0) + " color=" + color);
        }
        int x = x0;
        int y = y0;
        ArrayList<List<Integer>> eaten = new ArrayList<>();
        while (steps.size() != 0) {
           int x1 = steps.get(0).get(0);
           int y1 = steps.get(0).get(1);
           steps.remove(0);
           if (x1 < 0 || x1 > SIZE || y1 < 0 || y1 > SIZE) {
               throw new Exception("illegal move");
            }
           if (desk.get(x1).get(y1) % 10.0 == BLOCK) {
               throw new Exception("illegal move");
           }
           if (desk.get(x1).get(y1) % 10.0 == color && x1 != x0 && y1 != y0) {
               throw new Exception("illegal move x0=" + x0 + " y0=" + y0 + " x1=" + x1 + " y1=" + y1
                       + " desk.get(x1).get(y1) % 10.0=" + (desk.get(x1).get(y1) % 10.0) + " color=" + color);
           }
           if (desk.get(x1).get(y1) % 10.0 == invcolor(color) && steps.size() == 0) {
               throw new Exception("illegal move x1=" + x1 + " y1=" + y1 + " desk.get(x1).get(y1) % 10.0="
                       + (desk.get(x0).get(y0) % 10.0) + " invcolor(color)=" + invcolor(color)
                       + " movement.steps.size()=" + movement.steps.size());
           }
           if (Math.abs(x - x1) != 1 || Math.abs(y - y1) != 1) {
               int startX = x > x1 ? x1 : x;
               int endX = x > x1 ? x : x1;
               int startY = y > y1 ? y1 : y;
               int endY = y > y1 ? y : y1;
               for (int xx = startX + 1; xx < endX; ++xx) {
                   for (int yy = startY + 1; yy < endY; ++yy) {
                       if (desk.get(xx).get(yy) % 10.0 == invcolor(color)) {
                           eaten.add(Arrays.asList(xx, yy));
                       }
                   }
               }
           }
           if (desk.get(x1).get(y1) % 10.0 == invcolor(color)) {
               eaten.add(Arrays.asList(x1, y1));
           }
           x = x1;
           y = y1;
        }
//        // the moving was correct, apply changes
        eaten.forEach(li -> {
           int xe = li.get(0);
           int ye = li.get(1);
           desk.get(xe).set(ye, EMPTY);
        });
        score.put(color, score.get(color) + eaten.size());
        // set target position
        desk.get(x).set(y, desk.get(x0).get(y0));
        // clean initial position
        desk.get(x0).set(y0, EMPTY);
        // check for kings
        if (x == getKingrows().get(color) && desk.get(x).get(y) / 10.0 < 1) {
           desk.get(x).set(y, desk.get(x).get(y) + 10);
        }
        int deskHash = desk.hashCode();
        if (hashDict.containsKey(deskHash)) {
           if (hashDict.get(deskHash) == 2) {
               score.put(-1, 0);
           } else {
               hashDict.put(deskHash, hashDict.get(deskHash) + 1);
           }
        } else {
           hashDict.put(deskHash, 1);
        }
        return Arrays.asList(x, y);
    }
 
    public List<Integer> move(Movement movement, int color) throws Exception {
        return move(getDesk(), getHashDict(), score, movement, color);
    }
 
    public Vector<Vector<Integer>> getDesk() {
        return desk;
    }
 
    public void setDesk(Vector<Vector<Integer>> desk) {
        this.desk = desk;
    }
 
    public HashMap<Integer, Integer> getKingrows() {
        return kingrows;
    }
 
    public void setKingrows(HashMap<Integer, Integer> kingrows) {
        this.kingrows = kingrows;
    }
 
    public HashMap<Integer, Integer> getHashDict() {
        return hashDict;
    }
 
    public void setHashDict(HashMap<Integer, Integer> hashDict) {
        this.hashDict = hashDict;
    }
 
    @FunctionalInterface
    private interface neighbourKingMoveFunction<One, Two, Three> extends Serializable {
        ArrayList<Movement> neighbourKingMove(One one, Two two, Three three);
    }
 
    //从根节点R开始,选择连续的子节点向下至叶子节点L。后面给出了一种选择子节点的方法,让游戏树向最优的方向扩展
    private ArrayList<Movement> complexOptions(Vector<Vector<Integer>> rootDesk, HashMap<Integer, Integer> rootHashDict,
           HashMap<Integer, Integer> score, List<Integer> position,
           neighbourKingMoveFunction<Vector<Vector<Integer>>, List<Integer>, Integer> nextMoves, int color)
           throws Exception {
        ArrayList<Movement> neighbourMoves = nextMoves.neighbourKingMove(rootDesk, position, color);
        ArrayList<Movement> endMoves = new ArrayList<>();
        endMoves.addAll(neighbourMoves.stream().filter(nMove -> nMove.score == 0).collect(Collectors.toList()));
        ArrayList<List> neighbourMoves2 = new ArrayList<>();
        ArrayList<List> finalNeighbourMoves = neighbourMoves2;
        neighbourMoves.stream().filter(nMove -> nMove.score > 0).forEach(nMove -> {
           finalNeighbourMoves.add(Arrays.asList(nMove, SerializationUtils.clone(rootDesk),
                   SerializationUtils.clone(rootHashDict), SerializationUtils.clone(score)));
        });
        while (neighbourMoves2.size() > 0) {
           ArrayList<List> nextNMoves = new ArrayList<>();
           for (List list : neighbourMoves2) {
               Movement nMove2 = (Movement) list.get(0);
               Vector<Vector<Integer>> desk2 = (Vector<Vector<Integer>>) list.get(1);
               HashMap<Integer, Integer> hashDict2 = (HashMap<Integer, Integer>) list.get(2);
               HashMap<Integer, Integer> score2 = (HashMap<Integer, Integer>) list.get(3);
               Vector<Vector<Integer>> newDesk = SerializationUtils.clone(desk2);
               Map<Integer, Integer> newHashDict = SerializationUtils.clone(hashDict2);
               Map<Integer, Integer> newScore = SerializationUtils.clone(score2);
               move(newDesk, newHashDict, newScore, nMove2, color);
               List<Integer> target = nMove2.steps.get(nMove2.steps.size() - 1);
               ArrayList<Movement> childNeighbourMoves = nextMoves.neighbourKingMove(newDesk, target, color);
               List<Movement> scoreMoves = childNeighbourMoves.stream().filter(cnMove -> cnMove.score > 0)
                       .collect(Collectors.toList());
               if (scoreMoves.size() == 0) {
                   endMoves.add(nMove2);
               } else {
                   for (Movement scoreMove : scoreMoves) {
                       Movement nextNMove = SerializationUtils.clone(nMove2);
                       nextNMove.add(scoreMove);
                       nextNMoves.add(Arrays.asList(nextNMove, desk2, hashDict2, SerializationUtils.clone(score2)));
                   }
               }
           }
           neighbourMoves2 = nextNMoves;
        }
        return endMoves;
    }
 
    public List<Movement> options(int color) throws Exception {
        ArrayList<List> myCheckers = new ArrayList<>();
        ArrayList<Integer> rows = new ArrayList<>();
        if (color == BLACK) {
           for (int i = SIZE - 1; i > -1; --i) {
               rows.add(i);
            }
        } else {
           for (int i = 0; i < SIZE; ++i) {
               rows.add(i);
           }
        }
        for (int i : rows) {
           for (int j = 0; j < SIZE; ++j) {
               if (getDesk().get(i).get(j) % 10 == color) {
                   myCheckers.add(Arrays.asList(i, j));
               }
           }
        }
        ArrayList<Movement> moves = new ArrayList<Movement>();
        for (List<?> list : myCheckers) {
           int x = (int) list.get(0);
           int y = (int) list.get(1);
           ArrayList<Movement> endMoves = new ArrayList<Movement>();
           if ((int) (getDesk().get(x).get(y) / 10.0) == 1) {
               endMoves = complexOptions(this.getDesk(), this.getHashDict(), this.score, Arrays.asList(x, y),
                       neighbourKingMovesFunc, color);
           } else {
               endMoves = complexOptions(this.getDesk(), this.getHashDict(), this.score, Arrays.asList(x, y), neighbourMovesFunc,
                       color);
           }
           moves.addAll(endMoves);
        }
        List<Movement> filterMoves = moves.stream().filter(m -> m.score > 0).collect(Collectors.toList());
        if (filterMoves.size() > 0) {
           return filterMoves;
        }
        return moves;
    }
 
    private void diagMoves(Vector<Vector<Integer>> desk, List<Movement> moves, List<Integer> direction, int r,
           List<Integer> cell, int color) {
        int x = cell.get(0);
        int y = cell.get(1);
        int dx = direction.get(0);
        int dy = direction.get(1);
        Movement movement = new Movement(cell);
        for (int i = 1; i <= r; ++i) {
           int x0 = x + dx * i;
           int y0 = y + dy * i;
           if (desk.get(x0).get(y0) % 10 == EMPTY) {
               if (color == WHITE && x0 == x - 1) {
                   break;
               } else if (color == BLACK && x0 == x + 1) {
                   break;
               }
               movement.steps.add(Arrays.asList(x0, y0));
               moves.add(SerializationUtils.clone(movement));
               break;
           } else if (desk.get(x0).get(y0) % 10 == invcolor(color)) {
               movement.steps.add(Arrays.asList(x0, y0));
               movement.score++;
               continue;
           } else {
               break;
           }
        }
    }
 
    public ArrayList<Movement> neighbourMoves(Vector<Vector<Integer>> desk, List<Integer> position, int color) {
        int x = position.get(0);
        int y = position.get(1);
        ArrayList<Movement> movements = new ArrayList<>();
        int lowerX = x - 2 > 0 ? x - 2 : 0;
        int upperX = x + 2 < SIZE - 1 ? x + 2 : SIZE - 1;
        int lowerY = y - 2 > 0 ? y - 2 : 0;
        int upperY = y + 2 < SIZE - 1 ? y + 2 : SIZE - 1;
 
        int rMax = y - lowerY < x - lowerX ? y - lowerY : x - lowerX;
        List<Integer> dir = Arrays.asList(-1, -1);
        diagMoves(desk, movements, dir, rMax, position, color);
 
        rMax = upperY - y < upperX - x ? upperY - y : upperX - x;
        dir = Arrays.asList(1, 1);
        diagMoves(desk, movements, dir, rMax, position, color);
 
        rMax = y - lowerY < upperX - x ? y - lowerY : upperX - x;
        dir = Arrays.asList(1, -1);
        diagMoves(desk, movements, dir, rMax, position, color);
 
        rMax = upperY - y < x - lowerX ? upperY - y : x - lowerX;
        dir = Arrays.asList(-1, 1);
        diagMoves(desk, movements, dir, rMax, position, color);
        return movements;
    }
 
    private void diagKingMoves(Vector<Vector<Integer>> desk, List<Movement> moves, List<Integer> direction, int r,
           List<Integer> cell, int color) {
        ArrayList<Movement> tmpMoves = new ArrayList<>();
        int x = cell.get(0);
        int y = cell.get(1);
        int dx = direction.get(0);
        int dy = direction.get(1);
        Movement movement = new Movement(cell);
        int px = x;
        int py = y;
        for (int i = 1; i <= r; ++i) {
           int x0 = x + dx * i;
           int y0 = y + dy * i;
           if (desk.get(x0).get(y0) % 10 == EMPTY) {
               movement.steps.add(Arrays.asList(x0, y0));
               tmpMoves.add(SerializationUtils.clone(movement));
           } else if (desk.get(x0).get(y0) % 10 == invcolor(color)) {
               if (desk.get(px).get(py) == EMPTY) {
                   movement.steps.add(Arrays.asList(x0, y0));
                   movement.score++;
               } else if (px == x && py == y) {
                   movement.steps.add(Arrays.asList(x0, y0));
                   movement.score++;
               } else {
                   break;
               }
           } else {
               break;
           }
           px = x0;
           py = y0;
        }
        if (tmpMoves.size() > 0) {
           moves.add(tmpMoves.get(tmpMoves.size() - 1));
        }
    }
 
    private neighbourKingMoveFunction neighbourKingMovesFunc = new neighbourKingMoveFunction() {
        @Override
        public ArrayList<Movement> neighbourKingMove(Object desk, Object position, Object color) {
           return neighbourKingMoves((Vector<Vector<Integer>>) desk, (List<Integer>) position, (int) color);
        }
    };
 
    private neighbourKingMoveFunction neighbourMovesFunc = (desk, position,
           color) -> neighbourMoves((Vector<Vector<Integer>>) desk, (List<Integer>) position, (int) color);
 
    public ArrayList<Movement> neighbourKingMoves(Vector<Vector<Integer>> desk, List<Integer> position, int color) {
        int x = position.get(0);
        int y = position.get(1);
        ArrayList<Movement> moves = new ArrayList<>();
        int lowerX = x - (SIZE - 1) > 0 ? x - (SIZE - 1) : 0;
        int upperX = x + (SIZE - 1) < SIZE - 1 ? x + (SIZE - 1) : SIZE - 1;
        int lowerY = y - (SIZE - 1) > 0 ? y - (SIZE - 1) : 0;
        int upperY = y + (SIZE - 1) < SIZE - 1 ? y + (SIZE - 1) : SIZE - 1;
 
        int rMax = y - lowerY < x - lowerX ? y - lowerY : x - lowerX;
        List<Integer> dir = Arrays.asList(-1, -1);
        diagMoves(desk, moves, dir, rMax, position, color);
 
        rMax = upperY - y < upperX - x ? upperY - y : upperX - x;
        dir = Arrays.asList(1, 1);
        diagMoves(desk, moves, dir, rMax, position, color);
 
        rMax = y - lowerY < upperX - x ? y - lowerY : upperX - x;
        dir = Arrays.asList(1, -1);
        diagMoves(desk, moves, dir, rMax, position, color);
 
        rMax = upperY - y < x - lowerX ? upperY - y : x - lowerX;
        dir = Arrays.asList(-1, 1);
        diagMoves(desk, moves, dir, rMax, position, color);
 
        return moves;
    }
 
    public Boolean gameOver() {
        return score.get(BLACK) == FIGURES || score.get(WHITE) == FIGURES || score.get(score.size() - 1) == -1;
    }
 
    public Boolean blacksWin() {
        return score.get(BLACK) == FIGURES;
    }
 
    public Boolean whitesWin() {
        return score.get(WHITE) == FIGURES;
    }
 
    public Boolean win(int color) {
        return score.get(color) == FIGURES;
    }
 
    public void display() {
        for (int i = SIZE - 1; i > -1; --i) {
           for (int j = 0; j < SIZE; ++j) {
               int bc = getDesk().get(i).get(j) % 10;
               char c = bc == 0 ? ' ' : (bc == 3 ? '*' : (bc == 1 ? 'w' : 'b'));
               System.out.print(c);
               System.out.print(" ");
           }
           System.out.println();
        }
        for (int k : score.keySet()) {
           int bc = k;
           char c2 = bc == 0 ? ' ' : (bc == 3 ? '*' : (bc == 1 ? 'w' : 'b'));
           System.out.print(c2);
           System.out.print(":");
           System.out.print(score.get(k));
           System.out.print(" ");
        }
        System.out.println();
    }
}

消息提示框模块(myFrame\ToolTip.java

package myFrame;
 
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EtchedBorder;
 
/**
 *
 * @author 名字
 * @邮箱:mail@company.com
 * @修改日期:2020.11.11
 * @描述:悬浮消息框
 *
 */
public class ToolTip {
 
    // 气泡提示宽
    private int _width = 300;
 
    // 气泡提示高
    private int _height = 100;
 
    // 设定循环的步长
    private int _step = 30;
 
    // 每步时间
    private int _stepTime = 30;
 
    // 显示时间
    private int _displayTime = 6000;
 
    // 目前申请的气泡提示数量
    private int _countOfToolTip = 0;
 
    // 当前最大气泡数
    private int _maxToolTip = 0;
 
    // 在屏幕上显示的最大气泡提示数量
    private int _maxToolTipSceen;
 
    // 字体
    private Font _font;
 
    // 边框颜色
    private Color _bgColor;
 
    // 背景颜色
    private Color _border;
 
    // 消息颜色
    private Color _messageColor;
 
    //设置默认显示图片
    private Icon _icon = null;
 
    // 差值设定
    int _gap;
 
    // 是否要求至顶(jre1.5以上版本方可执行)
    boolean _useTop = true;
 
    /**
     * 构造函数,初始化默认气泡提示设置
     *
     */
    public ToolTip() {
        // 设定字体
        _font = new Font("宋体", 0, 12);
        // 设定边框颜色
        _bgColor = new Color(255, 255, 225);
        _border = Color.BLACK;
        _messageColor = Color.BLACK;
        _useTop = true;
        // 通过调用方法,强制获知是否支持自动窗体置顶
        try {
            JWindow.class.getMethod("setAlwaysOnTop",
                    new Class[] { Boolean.class });
        } catch (Exception e) {
            _useTop = false;
        }
 
    }
 
    /**
     * 重构JWindow用于显示单一气泡提示框
     *
     */
    class ToolTipSingle extends JWindow {
        private static final long serialVersionUID = 1L;
 
        private JLabel _iconLabel = new JLabel();
 
        private JTextArea _message = new JTextArea();
 
        public ToolTipSingle() {
            initComponents();
        }
 
        private void initComponents() {
            setSize(_width, _height);
            _message.setFont(getMessageFont());
            JPanel externalPanel = new JPanel(new BorderLayout(1, 1));
            externalPanel.setBackground(_bgColor);
            // 通过设定水平与垂直差值获得内部面板
            JPanel innerPanel = new JPanel(new BorderLayout(getGap(), getGap()));
            innerPanel.setBackground(_bgColor);
            _message.setBackground(_bgColor);
            _message.setMargin(new Insets(4, 4, 4, 4));
            _message.setLineWrap(true);
            _message.setWrapStyleWord(true);
            // 创建具有指定高亮和阴影颜色的阴刻浮雕化边框
            EtchedBorder etchedBorder = (EtchedBorder) BorderFactory
                    .createEtchedBorder();
            // 设定外部面板内容边框为风化效果
            externalPanel.setBorder(etchedBorder);
            // 加载内部面板
            externalPanel.add(innerPanel);
            _message.setForeground(getMessageColor());
            innerPanel.add(_iconLabel, BorderLayout.WEST);
            innerPanel.add(_message, BorderLayout.CENTER);
            getContentPane().add(externalPanel);
        }
 
        /**
         * 动画开始
         *
         */
        public void animate() {
            new Animation(this).start();
        }
 
    }
 
    /**
     * 此类处则动画处理
     *
     */
    class Animation extends Thread {
 
        ToolTipSingle _single;
 
        public Animation(ToolTipSingle single) {
            this._single = single;
        }
 
        /**
         * 调用动画效果,移动窗体坐标
         *
         * @param posx
         * @param startY
         * @param endY
         * @throws InterruptedException
         */
        private void animateVertically(int posx, int startY, int endY)
                throws InterruptedException {
            _single.setLocation(posx, startY);
            if (endY < startY) {
                for (int i = startY; i > endY; i -= _step) {
                    _single.setLocation(posx, i);
                    Thread.sleep(_stepTime);
                }
            } else {
                for (int i = startY; i < endY; i += _step) {
                    _single.setLocation(posx, i);
                    Thread.sleep(_stepTime);
                }
            }
            _single.setLocation(posx, endY);
        }
 
        /**
         * 开始动画处理
         */
        public void run() {
            try {
                boolean animate = true;
                GraphicsEnvironment ge = GraphicsEnvironment
                        .getLocalGraphicsEnvironment();
                Rectangle screenRect = ge.getMaximumWindowBounds();
                int screenHeight = (int) screenRect.height;
                int startYPosition;
                int stopYPosition;
                if (screenRect.y > 0) {
                    animate = false;
                }
                _maxToolTipSceen = screenHeight / _height;
                int posx = (int) screenRect.width - _width - 1;
                _single.setLocation(posx, screenHeight);
                _single.setVisible(true);
                if (_useTop) {
                    _single.setAlwaysOnTop(true);
                }
                if (animate) {
                    startYPosition = screenHeight;
                    stopYPosition = startYPosition - _height - 1;
                    if (_countOfToolTip > 0) {
                        stopYPosition = stopYPosition
                                - (_maxToolTip % _maxToolTipSceen * _height);
                    } else {
                        _maxToolTip = 0;
                    }
                } else {
                    startYPosition = screenRect.y - _height;
                    stopYPosition = screenRect.y;
 
                    if (_countOfToolTip > 0) {
                        stopYPosition = stopYPosition
                                + (_maxToolTip % _maxToolTipSceen * _height);
                    } else {
                        _maxToolTip = 0;
                    }
                }
 
                _countOfToolTip++;
                _maxToolTip++;
 
                animateVertically(posx, startYPosition, stopYPosition);
                Thread.sleep(_displayTime);
                animateVertically(posx, stopYPosition, startYPosition);
 
                _countOfToolTip--;
                _single.setVisible(false);
                _single.dispose();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
 
    /**
     * 设定显示的图片及信息
     *
     * @param icon
     * @param msg
     */
    public void setToolTip(Icon icon, String msg) {
        ToolTipSingle single = new ToolTipSingle();
        if (icon != null) {
            single._iconLabel.setIcon(icon);
        }
        single._message.setText(msg);
        single.animate();
    }
 
    /**
     * 设定显示的信息
     *
     * @param msg
     */
    public void setToolTip(String msg) {
        setToolTip(_icon, msg);
    }
 
    /**
     * 获得当前消息字体
     *
     * @return
     */
    public Font getMessageFont() {
        return _font;
    }
 
    /**
     * 设置当前消息字体
     *
     * @param font
     */
    public void setMessageFont(Font font) {
        _font = font;
    }
 
    /**
     * 获得边框颜色
     *
     * @return
     */
    public Color getBorderColor() {
        return _border;
    }
 
    /**
     * 设置边框颜色
     *
     * @param borderColor
     */
    public void setBorderColor(Color borderColor) {
        this._border = borderColor;
    }
 
    /**
     * 获得显示时间
     *
     * @return
     */
    public int getDisplayTime() {
        return _displayTime;
    }
 
    /**
     * 设置显示时间
     *
     * @param displayTime
     */
    public void setDisplayTime(int displayTime) {
        this._displayTime = displayTime;
    }
 
    /**
     * 获得差值
     *
     * @return
     */
    public int getGap() {
        return _gap;
    }
 
    /**
     * 设定差值
     *
     * @param gap
     */
    public void setGap(int gap) {
        this._gap = gap;
    }
 
    /**
     * 获得信息颜色
     *
     * @return
     */
    public Color getMessageColor() {
        return _messageColor;
    }
 
    /**
     * 设定信息颜色
     *
     * @param messageColor
     */
    public void setMessageColor(Color messageColor) {
        this._messageColor = messageColor;
    }
 
 
    /**
     * 获得默认显示图片
     *
     * @return
     */
    public Icon getIcon() {
        return _icon;
    }
 
    /**
     * 设定默认显示图片
     *
     * @param icon
     */
    public void setIcon(Icon icon) {
        this._icon = icon;
    }
 
    /**
     * 获得循环步长
     *
     * @return
     */
    public int getStep() {
        return _step;
    }
 
    /**
     * 设定循环步长
     *
     * @param _step
     */
    public void setStep(int _step) {
        this._step = _step;
    }
 
    public int getStepTime() {
        return _stepTime;
    }
 
    public void setStepTime(int _stepTime) {
        this._stepTime = _stepTime;
    }
 
    public Color getBackgroundColor() {
        return _bgColor;
    }
 
    public void setBackgroundColor(Color bgColor) {
        this._bgColor = bgColor;
    }
 
    public int getHeight() {
        return _height;
    }
 
    public void setHeight(int height) {
        this._height = height;
    }
 
    public int getWidth() {
        return _width;
    }
 
    public void setWidth(int width) {
        this._width = width;
    }
 
    public static void main(String[] args) {
 
        ToolTip tip = new ToolTip();
        tip.setToolTip("“程序员”就是特指越写程序身材越“圆”那群人 -- cping1982");
 
    }
 
}

棋盘状态管理模块(searchTree\GameRecord.java

package searchTree;
 
import java.util.ArrayList;
 
/**
 *
 * @author 名字
 * @邮箱:mail@company.com
 * @修改日期:2020.11.11
 * @描述:棋盘状态管理类
 *
 */
public class GameRecord {
    private static ArrayList<GameRecordStorage> gameRecordList = new ArrayList<GameRecordStorage>();
    private static int index = -1;
 
    public static ArrayList<GameRecordStorage> getGameRecordList() {
        return gameRecordList;
    }
 
    public static void setGameRecordList(ArrayList<GameRecordStorage> gameRecordList) {
        GameRecord.gameRecordList = gameRecordList;
    }
 
    public static void backupGame() {
        GameRecordStorage gameRecordStorage = new GameRecordStorage();
        gameRecordStorage.backups();
        gameRecordList.add(gameRecordStorage);
        index++;
    }
 
    public static void renewGame() throws Exception {
        if (index > 0) {
            GameRecordStorage gameRecordStorage = gameRecordList.get(index - 1);
            gameRecordStorage.renew();
            gameRecordList.remove(index);
            index--;
        } else {
            throw new Exception("国际跳棋棋谱为空!");
        }
    }
}

棋盘状态记录模块(searchTree\GameRecordStorage.java

package searchTree;
 
import myFrame.MainFrame;
 
import java.util.*;
import org.apache.commons.lang3.SerializationUtils;
 
/**
 *
 * @author 名字
 * @邮箱:mail@company.com @修改日期:2020.11.11
 * @描述:棋盘状态记录类
 *
 */
public class GameRecordStorage {
    private int i0s = myFrame.AI.getI0();
    private int j0s = myFrame.AI.getJ0();
    private int i1s = myFrame.AI.getI1();
    private int j1s = myFrame.AI.getJ1();
    private int i2s = myFrame.AI.getI2();
    private int j2s = myFrame.AI.getJ2();
    private int i4s = myFrame.Packaging.getI4();
    private int j4s = myFrame.Packaging.getJ4();
    private int i3s = myFrame.Packaging.getI3();
    private int j3s = myFrame.Packaging.getJ3();
    private boolean mustJumpChesss = myFrame.AI.isMustJumpChess();
    private boolean mustEvenJumps = myFrame.AI.isMustEvenJump();
    private boolean ZTs = myFrame.AI.isZT();
    private boolean canJumps = myFrame.AI.isCanJump();
    private boolean goodSteps = myFrame.AI.isGoodStep();
    private int steps = MainFrame.getStep(); // 记录走了几回合
    private boolean enemyLaterIsEmptys = MainFrame.isEnemyLaterIsEmpty();// 敌方棋子后有空位置
    private int[][] ChessDatas = new int[10][10];
    private int flags;
    private int kingFlags;
    private Vector<Vector<Integer>> desk;
    private HashMap<Integer, Integer> score;
    private HashMap<Integer, Integer> kingrows, hashDict;
    private int color1;
    private int invColor1;
    private int rounds1;
    private int color2;
    private int invColor2;
    private int rounds2;
 
    public int getI0s() {
        return i0s;
    }
 
    public void setI0s(int i0s) {
        this.i0s = i0s;
    }
 
    public int getJ0s() {
        return j0s;
    }
 
    public void setJ0s(int j0s) {
        this.j0s = j0s;
    }
 
    public int getI1s() {
        return i1s;
    }
 
    public void setI1s(int i1s) {
        this.i1s = i1s;
    }
 
    public int getJ1s() {
        return j1s;
    }
 
    public void setJ1s(int j1s) {
        this.j1s = j1s;
    }
 
    public int getI2s() {
        return i2s;
    }
 
    public void setI2s(int i2s) {
        this.i2s = i2s;
    }
 
    public int getJ2s() {
        return j2s;
    }
 
    public void setJ2s(int j2s) {
        this.j2s = j2s;
    }
 
    public int getI4s() {
        return i4s;
    }
 
    public void setI4s(int i4s) {
        this.i4s = i4s;
    }
 
    public int getJ4s() {
        return j4s;
    }
 
    public void setJ4s(int j4s) {
        this.j4s = j4s;
    }
 
    public int getI3s() {
        return i3s;
    }
 
    public void setI3s(int i3s) {
        this.i3s = i3s;
    }
 
    public int getJ3s() {
        return j3s;
    }
 
    public void setJ3s(int j3s) {
        this.j3s = j3s;
    }
 
    public boolean isMustJumpChesss() {
        return mustJumpChesss;
    }
 
    public void setMustJumpChesss(boolean mustJumpChesss) {
        this.mustJumpChesss = mustJumpChesss;
    }
 
    public boolean isMustEvenJumps() {
        return mustEvenJumps;
    }
 
    public void setMustEvenJumps(boolean mustEvenJumps) {
        this.mustEvenJumps = mustEvenJumps;
    }
 
    public boolean isZTs() {
        return ZTs;
    }
 
    public void setZTs(boolean zTs) {
        ZTs = zTs;
    }
 
    public boolean isCanJumps() {
        return canJumps;
    }
 
    public void setCanJumps(boolean canJumps) {
        this.canJumps = canJumps;
    }
 
    public boolean isGoodSteps() {
        return goodSteps;
    }
 
    public void setGoodSteps(boolean goodSteps) {
        this.goodSteps = goodSteps;
    }
 
    public int getSteps() {
        return steps;
    }
 
    public void setSteps(int steps) {
        this.steps = steps;
    }
 
    public boolean isEnemyLaterIsEmptys() {
        return enemyLaterIsEmptys;
    }
 
    public void setEnemyLaterIsEmptys(boolean enemyLaterIsEmptys) {
        this.enemyLaterIsEmptys = enemyLaterIsEmptys;
    }
 
    public int getChessDatas(int i, int j) {
        return ChessDatas[i][j];
    }
 
    public void setChessDatas(int chessDatas, int i, int j) {
        ChessDatas[i][j] = chessDatas;
    }
 
    /**
     * 
     * 描述:数据备份,保护现场
     */
    public void backups() {
        setI0s(myFrame.AI.getI0());
        setJ0s(myFrame.AI.getJ0());
        setI1s(myFrame.AI.getI1());
        setJ1s(myFrame.AI.getJ1());
        setI2s(myFrame.AI.getI2());
        setJ2s(myFrame.AI.getJ2());
        setI3s(myFrame.Packaging.getI3());
        setJ3s(myFrame.Packaging.getJ3());
        setI4s(myFrame.Packaging.getI4());
        setJ4s(myFrame.Packaging.getJ4());
        setMustJumpChesss(myFrame.AI.isMustJumpChess());
        setMustEvenJumps(myFrame.AI.isMustEvenJump());
        setZTs(myFrame.AI.isZT());
        setCanJumps(myFrame.AI.isCanJump());
        setGoodSteps(myFrame.AI.isGoodStep());
        setSteps(MainFrame.getStep());
        setEnemyLaterIsEmptys(MainFrame.isEnemyLaterIsEmpty());
        for (int i = 0; i < 10; i++) {
           for (int j = 0; j < 10; j++) {
               setChessDatas(myFrame.Packaging.getChessData(i, j), i, j);
           }
        }
        flags = myFrame.Packaging.getFlag();
        kingFlags = myFrame.Packaging.getKingFlag();
        desk = SerializationUtils.clone(MainFrame.game_field.getDesk());
        score = SerializationUtils.clone(MainFrame.game_field.score);
        kingrows = SerializationUtils.clone(MainFrame.game_field.getKingrows());
        hashDict = SerializationUtils.clone(MainFrame.game_field.getHashDict());
        color1 = MainFrame.player1.getColor();
        invColor1 = MainFrame.player1.getInvColor();
        rounds1 = MainFrame.player1.getRounds();
        color2 = MainFrame.player2.getColor();
        invColor2 = MainFrame.player2.getInvColor();
        rounds2 = MainFrame.player2.getRounds();
    }
 
    /**
     * 
     * 描述:恢复数据
     */
    public void renew() {
        myFrame.AI.setI0(getI0s());
        myFrame.AI.setJ0(getJ0s());
        myFrame.AI.setI1(getI1s());
        myFrame.AI.setJ1(getJ1s());
        myFrame.AI.setI2(getI2s());
        myFrame.AI.setJ2(getJ2s());
        myFrame.Packaging.setI3(getI3s());
        myFrame.Packaging.setJ3(getJ3s());
        myFrame.Packaging.setI4(getI4s());
        myFrame.Packaging.setJ4(getJ4s());
        myFrame.AI.setMustJumpChess(isMustJumpChesss());
        myFrame.AI.setMustEvenJump(isMustEvenJumps());
        myFrame.AI.setZT(isZTs());
        myFrame.AI.setCanJump(isCanJumps());
        myFrame.AI.setGoodStep(isGoodSteps());
        MainFrame.setStep(getSteps());
        MainFrame.setEnemyLaterIsEmpty(isEnemyLaterIsEmptys());
        for (int i = 0; i < 10; i++) {
           for (int j = 0; j < 10; j++) {
               myFrame.Packaging.setChessData(getChessDatas(i, j), i, j);
           }
        }
        myFrame.Packaging.setFlag(flags);
        myFrame.Packaging.setKingFlag(kingFlags);
     MainFrame.game_field.setDesk(SerializationUtils.clone(desk));
        MainFrame.game_field.score = SerializationUtils.clone(score);
     MainFrame.game_field.setKingrows(SerializationUtils.clone(kingrows));
     MainFrame.game_field.setHashDict(SerializationUtils.clone(hashDict));
        MainFrame.player1.setColor(color1);
        MainFrame.player1.setInvColor(invColor1);
        MainFrame.player1.setRounds(rounds1);
        MainFrame.player2.setColor(color2);
        MainFrame.player2.setInvColor(invColor2);
        MainFrame.player2.setRounds(rounds2);
    }
}


四、总结

本软件使用蒙特卡洛树搜索算法实现人工智能走棋。Java swing图形界面使用绘制棋谱,并加入鼠标点击和移动事件和棋子移动动画实现增加用户交互性,还加入了消息提示窗口和悔棋功能。人工智能走棋方面,由于要处理很多棋谱数据,程序的运行比较占用内存和CPU资源比高,程序思考走棋的时间较长,可以优化代码逻辑和压缩棋谱数据以缩短运行时间。


本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码