国际跳棋人机对战
概述
详细
概述
国际跳棋是一种古老的棋类游戏。远在古埃及法老时期就已存在,现代国际跳棋是在12世纪定型的。 国际跳棋是由各国的民族跳棋演变而来。其历史源远流长。据史学家研究,跳棋起源于古埃及、古罗马、古希腊等一些国家和地区。
在大多数国家国际跳棋为64格,规则有所不同,有巴西规则、俄罗斯规则等。但国际比赛采用的棋盘为100格,此外加拿大国际跳棋采用12*12即144格的棋盘,棋盘越大,变化越丰富,难度也相应增大。如图所示,国际跳棋棋子是圆柱型的,黑白棋子各二十枚,棋子表面上有罗纹,这种棋子叫“兵”,把兵翻过来(或两兵叠起来)就是“王”。由于棋子只能在深色格子中行走,因此可以将这些格子依次编号,方便记录棋局。对于100格国际跳棋,开局时,黑色棋子分布在1至20格,白色棋子分布在31至50格,和国际象棋类似,白棋先行。
在人与人对弈的国际比赛中采用的规则相对复杂,特别是对和局的判定,而计算机博弈中采用的规则做了一些简化。而且64格的规则与100格基本一致,只是棋子数目不同。另外在国内的计算机博弈赛中,国际跳棋和围棋一样也是黑方先行。
一、走法规则
所有棋子均在黑色或指定颜色格子中行走。
①、兵的走法
只能向前斜走一格,不能后退,显然靠边的兵只有一个方向可走,而居于中部的兵有两个方向可走。
②、兵的跳吃
黑白两枚棋子紧连在一条斜线上,如轮到某一方行棋时,对方棋子的前后正好有一空棋位能跳过对方的棋子,那么就可以跳过对方的棋子把被跳过的棋子吃掉,并从棋盘上取下。
③、兵的连跳
兵的连跳是是跳过对方的棋子以后,又遇上可以跳过的棋子,那么就可以连续跳过去,把被跳过的棋子吃掉,并且从棋盘上一次取下。兵的走法是不能后退,但是遇到跳吃或连续跳吃时,可以退跳。
④、兵的升变
对局开始前双方在棋盘上摆的棋子都是兵,兵在对局过程中,走到或跳到对方底线停下,即可升变为“王”刚升变的王要到下一步才能享有王的走法的权利。兵在对局过程中,走到或跳到对方底线没停下(即中途经过),不可以升变为“王”。
⑤、王的走法
王在其位于的任何一条斜线上均可进退,并且不限格数,除非遇到其它棋子。
⑥、王的跳吃
王的跳吃是王与对方棋子遇在同一斜线上,不管相距有几个空棋位,且对方棋子后也有空棋位,那么王棋就可以跳过去吃掉对方的棋子,而且跳吃时要跳到对方棋子后面的一个空位里。因此如果对方棋子有两个或两个以上相连,王棋是无法将它们直接吃掉的。
⑦、王的连跳
王的连跳与兵连跳的情况基本上相同,只是不限距离。
所有棋子均在黑色或指定颜色格子中行走。
二、吃子规定
①、有吃必吃
凡有跳吃或连跳机会时,不管对自己是否有利都必须连续跳吃或跳过,尤其是王。如果有连跳的局面,必须将对方所有的棋子跳完,直到无可再跳时才能停下。对于兵来说,遇到连续跳吃,即使吃到底也不能停下升王,而需要将所有的跳着走完,这就是“吃到底不得停”。
②、有吃多吃
如果有多条路线或2枚棋子都能吃对方的棋子,那么不管是否对自己有利,必须选择吃多的路线和棋子。例如:同时在两条路线上可以吃对方的棋子,一条路线上能吃3枚棋子,另一条路线上能吃2枚棋子,必须选择跳吃3枚棋子的路线。如果两条路线吃掉棋子的数目相等,则可以任选一种吃法。
③、不得重吃重跳
在跳吃过程中,被跳过的对方棋子在没有跳完之前不能拿下棋盘,这些棋子都只能被跳过一次,即已经跳过的棋子会对后面的跳吃造成屏障。在比赛中,这一规则通常被利用以形成所谓的“土耳其打击”。
三、棋局结束判断
①、所有的棋子都被对方吃掉为负棋。
②、残留在棋盘上的棋子,被对方封锁,无子可动为负棋。
详细
一、运行效果
二、人机对战算法
本程序使用了蒙特卡洛树搜索树算法来进行判断对战, 其实原理很简单:
蒙特卡洛树搜索的每个循环包括四个步骤:
选择(Selection):从根节点R开始,选择连续的子节点向下至叶子节点L。后面给出了一种选择子节点的方法,让游戏树向最优的方向扩展,这是蒙特卡洛树搜索的精要所在。
扩展(Expansion):除非任意一方的输赢使得游戏在L结束,否则创建一个或多个子节点并选取其中一个节点C。
仿真(Simulation):在从节点C开始,用随机策略进行游戏,又称为playout或者rollout。
反向传播(Backpropagation):使用随机游戏的结果,更新从C到R的路径上的节点信息。
每一个节点的内容代表胜利次数/游戏次数
三、主要的模块
棋盘界面模块(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资源比高,程序思考走棋的时间较长,可以优化代码逻辑和压缩棋谱数据以缩短运行时间。