JAVA 五子棋程序

一个简单的五子棋程序,实现了人机对战、人人对战、悔棋、认输功能。

一、首先是制作界面,也就是下棋界面。要画一个棋盘,添加按钮实现各种功能。
(1)创建一个ChessTable类来存放棋盘的基础数据,比如横向线的条数、纵向线的条数、单元格的大小、棋子的直径等。定义一个类是为了更改棋盘基础数据的时候更加方便。

public interface ChessTable {
    public int x0 = 50; //表格左上角起点的x值
    public int y0 = 70; //表格左上角起点的y值
    public int rows = 11; //横向线的条数
    public int columns = 11; //纵向线的条数
    public int chess_size = 30; //棋子的直径
    public int size = 40; //单元格的大小

}

(2)接下来是下棋界面的设计,考虑到后面要实现悔棋和改变界面大小,就要用到重绘。所以在创建类的时候直接继承JFrame,然后在类里面重写paint()方法来实现重绘。
JPanel是一个容器组件,可以把按钮添加到JPanel中。然后指定JPanel存放的位置。
通过ImageIcon可以在界面中添加背景图片,增加观赏性。

public class Gobang extends JFrame {

    public static void main(String[] args) {
        Gobang gb = new Gobang();
        gb.showJFrame();
    }

    //初始化窗体的方法
    public void showJFrame() {
        this.setTitle("五子棋");
        this.setSize(650, 550);
        this.setDefaultCloseOperation(3);
        this.setLocationRelativeTo(null);
        this.setResizable(false);//界面不可改变大小
        this.setLayout(new BorderLayout());
        //添加容器组件
        JPanel jl = new JPanel();
        jl.setPreferredSize(new Dimension(150,0));
        jl.setBackground(Color.LIGHT_GRAY);
        JButton start = new JButton("开始新游戏");
        start.setPreferredSize(new Dimension(100,30));
        jl.add(start);
        JButton back = new JButton("悔棋");
        back.setPreferredSize(new Dimension(80,30));
        jl.add(back);
        JButton giveup = new JButton("认输");
        giveup.setPreferredSize(new Dimension(80,30));
        jl.add(giveup);

        String[] type = {"人人对战","人机对战"};
        JComboBox<String> box = new JComboBox<>(type);
        box.setPreferredSize(new Dimension(90,30));
        jl.add(box);

        this.add(jl,BorderLayout.EAST);
        this.setVisible(true);
    }

    //重写绘制界面的方法
    public void paint(Graphics g) {
       //在界面加上图片
       ImageIcon image = new ImageIcon("C:\\Users\\某某某\\Desktop\\文档\\五子棋背景图\\1.jpg");
        g.drawImage(image.getImage(),50,70,400,400,null);
    }

    //画棋盘
    public void drawChessTable(Graphics g) {
        //画横线
        for(int i = 0;i < ChessTable.rows;i++) {
            g.drawLine(ChessTable.x0, ChessTable.y0+i*ChessTable.size, 
                    ChessTable.x0+(ChessTable.columns - 1)*ChessTable.size, ChessTable.y0+i*ChessTable.size);
        }
        //画竖线
        for(int j = 0;j < ChessTable.rows;j++) {
            g.drawLine(ChessTable.x0+j*ChessTable.size, ChessTable.y0, 
                    ChessTable.x0+j*ChessTable.size, ChessTable.y0+(ChessTable.rows - 1)*ChessTable.size);
        }
    }

}

效果图如下:
这里写图片描述
(3)添加监听器,收集按钮上的信息。
收集按钮上的信息通过addActionListener()监听方法。
要实现下棋,就要获取点击位置的坐标,需要addMouseListener()监听方法。
添加监听方法就要有事件处理类,创建GobangListener类作为事件处理类。
继承MouseAdapter鼠标适配类,MouseAdapter类里继承了MouseListener, MouseWheelListener, MouseMotionListener。继承MouseAdapter是因为MouseAdapter只需要重写用到的方法,不需要重写所有的抽象方法。
同时,还要继承ActionListener。

//实例化事件处理类的对象,并把画笔、数组传递过去
GobangListener gl = new GobangListener(this,chesses);
//添加动作监听方法
start.addActionListener(gl);
back.addActionListener(gl);
giveup.addActionListener(gl);
box.addActionListener(gl);
public class GobangListener extends MouseAdapter implements ActionListener {
         //重写抽象方法
    }

(4)定义一个数组来存放棋子信息,当你在该位置下棋后,就不能再下棋了。
将窗体传递到GobangListener类,可以在窗体中获取画笔,也可以添加MouseListener监听方法。

public class Gobang extends JFrame {
    //定义一个二维数组,用来标记棋盘上的位置
    private int[][] chesses = new int[ChessTable.rows][ChessTable.columns];
}   
public class GobangListener extends MouseAdapter implements ActionListener {

    private Gobang ct;
    private Graphics2D g;
    private int[][] chesses;

    // 构造方法
    public GobangListener(Gobang G, int[][] chesses) {
        this.ct = G;
        this.chesses = chesses;
        // 获取窗体上的画笔对象
        g = (Graphics2D) this.ct.getGraphics();
        //画笔防锯齿
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 设置画笔抗锯齿
    }
}

(5)实现下棋、悔棋、和重绘。
用count来计数,判断轮到谁下棋。
通过chesses[i][j]来判断该位置是否能下棋。
悔棋要通过数组队列来实现,定义一个数组队列ArrayList。Point是一个类,可以直接用,可以获取x,y坐标值。
重绘则根据chesses数组中的信息再画一次。
调用判断输赢方法judge(),决出胜利后,移除MouseListener()不能再下棋。

//重写绘制窗体的方法
public void paint(Graphics g) {
        super.paint(g);
        ImageIcon image = new ImageIcon("C:\\Users\\庞志贤\\Desktop\\文档\\五子棋背景图\\1.jpg");
        g.drawImage(image.getImage(),50,70,400,400,null);
        drawChessTable(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);// 设置画笔抗锯齿
        //按照数组中的信息进行重绘
        for(int j = 0;j < ChessTable.rows;j++) {
             for(int i = 0;i < ChessTable.columns;i++) {
                 int x = ChessTable.x0 + i*ChessTable.size;
                 int y = ChessTable.y0 + j*ChessTable.size;
                 if(chesses[i][j] == 1) {
                     g.setColor(Color.black);
                     g.fillOval(x - ChessTable.chess_size / 2, y - ChessTable.chess_size / 2,
                             ChessTable.chess_size, ChessTable.chess_size);
                 }else if(chesses[i][j] == -1) {
                     g.setColor(Color.WHITE);
                     g.fillOval(x - ChessTable.chess_size / 2, y - ChessTable.chess_size / 2,
                             ChessTable.chess_size, ChessTable.chess_size);
                 } 
             }
        }

    }
public class GobangListener extends MouseAdapter implements ActionListener {

    private Gobang ct;
    private Graphics2D g;
    private int[][] chesses;
    private int count;
    private ArrayList<Point> list = new ArrayList<Point>();

    public void mouseReleased(MouseEvent e) {
        // 获取鼠标事件发生时光标的位置
        int x1 = e.getX();
        int y1 = e.getY();
        for (int j = 0; j < ChessTable.rows; j++) {
            for (int i = 0; i < ChessTable.columns; i++) {
                int x = ChessTable.x0 + i * ChessTable.size;
                int y = ChessTable.y0 + j * ChessTable.size;
                if (x1 > x - ChessTable.size / 3 && x1 < x + ChessTable.size / 3 && y1 > y - ChessTable.size / 3
                        && y1 < y + ChessTable.size / 3) {
                    // 如果选择的位置没有棋子
                    if (chesses[i][j] == 0) {
                        if (count == 0) {
                            // 如果是黑子就为1
                            chesses[i][j] = 1;
                            g.setColor(Color.black);
                            count++;
                            // 调用判断输赢的方法
                            if (judge(i, j)) {
                                System.out.println("执黑子胜利");
                                // 判断输赢后移除鼠标监听方法,不能再下棋子
                                ct.removeMouseListener(this);
                            }
                        } else {
                            // 如果是白子就为-1
                            chesses[i][j] = -1;
                            g.setColor(Color.WHITE);
                            count--;
                            // 调用判断输赢的方法
                            if (judge(i, j)) {
                                System.out.println("执白子胜利");
                                // 判断输赢后移除鼠标监听方法,不能再下棋子
                                ct.removeMouseListener(this);
                            }
                        }

                        // 以最近的交叉点为圆心画圆
                        g.fillOval(x - ChessTable.chess_size / 2, y - ChessTable.chess_size / 2, ChessTable.chess_size,
                                ChessTable.chess_size);
                        Point point = new Point(x, y);
                        list.add(point);// 根据图形的数据实例化Array对象
                        return;
                    }
                }
            }
        }
    }

 }

(6)判断输赢。
下完一颗棋子后就要判断一次。一颗棋子的周围是否有五颗连续的同色棋子。分四个方向,水平、竖直、左斜、右斜。

     public boolean judge(int x, int y) {
        int count = 1;
        // 向右
        for (int i = x + 1; i < chesses.length; i++) {
            if (chesses[i][y] == chesses[x][y]) {
                count++;
            } else
                break;
        }
        // 向左
        for (int i = x - 1; i >= 0; i--) {
            if (chesses[i][y] == chesses[x][y]) {
                count++;
            } else
                break;
        }
        if (count >= 5) {
            return true;
        } else {
            count = 1;
        }
        // 向上
        for (int j = y + 1; j < chesses.length; j++) {
            if (chesses[x][j] == chesses[x][y]) {
                count++;
            } else
                break;
        }
        // 向下
        for (int j = y - 1; j >= 0; j--) {
            if (chesses[x][j] == chesses[x][y]) {
                count++;
            } else
                break;
        }
        if (count >= 5) {
            return true;
        } else {
            count = 1;
        }
        // 右下
        for (int i = x + 1, j = y + 1; i < chesses.length && j < chesses.length; i++, j++) {
            if (chesses[i][j] == chesses[x][y]) {
                count++;
            } else
                break;
        }
        // 左上
        for (int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--) {
            if (chesses[i][j] == chesses[x][y]) {
                count++;
            } else
                break;
        }
        if (count >= 5) {
            return true;
        } else {
            count = 1;
        }
        // 右上
        for (int i = x + 1, j = y - 1; i < chesses.length && j >= 0; i++, j--) {
            if (chesses[i][j] == chesses[x][y]) {
                count++;
            } else
                break;
        }
        // 左下
        for (int i = x - 1, j = y + 1; i >= 0 && j < chesses.length; i--, j++) {
            if (chesses[i][j] == chesses[x][y]) {
                count++;
            } else
                break;
        }
        if (count >= 5) {
            return true;
        } else {
            count = 1;
        }
        return false;
    }

二、五子棋的AI算法
AI算法:通过计算的方法选择最优的位置自动下棋。
(1)考虑棋盘上可能出现出现的各种情况。选择一个空位来计算权值,最后选择权值最大的位置来下棋。空位周围棋子的存在情况,可以分为活连、眠连。

    // 定义HashMap的集合对象,用来存储棋子相连的情况
    private static HashMap<String, Integer> map = new HashMap<String, Integer>();
// 活连、眠连,可能出现的各种情况
    static {
        map.put("010", 10);// 活一连(黑)
        map.put("0-10", 10);// 活一连(白)
        map.put("01010", 70);// 活二连(黑)
        map.put("0110", 70);// 活二连(黑)
        map.put("0-10-10", 70);// 活二连(白)
        map.put("0-1-10", 70);// 活二连(白)
        map.put("01110", 120);// 活三连(黑)
        map.put("0-1-1-10", 120);// 活三连(白)
        map.put("011110", 5000);// 活四连(黑)
        map.put("0-1-1-1-10", 5000);// 活四连(白)
        map.put("1-1", 1);// 眠一连(黑)
        map.put("-11", 1);// 眠一连(白)
        map.put("011-1", 50);// 眠二连(黑)
        map.put("-1110", 50);// 眠二连(黑)
        map.put("0-1-11", 50);// 眠二连(白)
        map.put("1-1-10", 50);// 眠二连(白)
        map.put("0111-1", 100);// 眠三连(黑)
        map.put("-11110", 100);// 眠三连(黑)
        map.put("0-1-1-11", 100);// 眠三连(白)
        map.put("1-1-1-10", 100);// 眠三连(白)
        map.put("01111-1", 2500);// 眠四连(黑)
        map.put("-111110", 2500);// 眠四连(黑)
        map.put("1-1-1-1-10", 2500);// 眠四连(白)
        map.put("0-1-1-1-11", 2500);// 眠四连(白)
    }

(2)计算权值就要先判断各个方向的活连、眠连情况,然后根据权重来计算权值。

// 定义权值数组,用来存储权值
    private int[][] weightArray = new int[ChessTable.rows][ChessTable.columns];
// 权值计算方法
    public void weight() {
        // 统计存储棋子的chesses数组,根据棋子数组中相连的情况来计算权值存入到weightArray数组中
        // 统计四个方向,水平(向左、向右)、竖直(向上、向下)、左斜(左下、右上)、右斜(左上、右下)
        for (int r = 0; r < chesses.length; r++) {
            for (int c = 0; c < chesses.length; c++) {
                if (chesses[r][c] == 0) {// 判断当前点是否为空位(没有棋子)
                    String code = "0"; // 记录棋子相连的情况
                    int chess = 0; // 记录棋子出现的次数
                    int number = 0; // 记录空位出现的次数
                    // 向左
                    for (int c1 = c - 1; c1 >= 0; c1--) {
                        if (chesses[r][c1] == 0) {// 判断当前交叉点的左边是否为空位
                            if (c == c1 + 1) {// 判断是否为两个连续的空位,如果是则停止
                                break;
                            } else if (number == 0) {// 表示第一次出现空位
                                code = code + chesses[r][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 1) {// 表示第二次出现空位
                                if (chesses[r][c1] == chesses[r][c1 + 1]) {// 检测两个位置是否都为空位
                                    break;
                                }
                                code = code + chesses[r][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 2) { // 表示第三次出现空位
                                if (chesses[r][c1] == chesses[r][c1 + 1]) { // 检测两个位置是否都为空位
                                    break;
                                }
                            }
                        } else {// 当前交叉点的左边是棋子
                            if (chess == 0) { // 表示第一次出现棋子
                                chess = chesses[r][c1]; // 存储第一次出现的棋子
                                code = code + chesses[r][c1]; // 记录棋子相连的情况
                            } else if (chess == chesses[r][c1]) { // 判断是否和第一次出现的棋子颜色相同
                                code = code + chesses[r][c1]; // 记录棋子相连的情况
                            } else { // 表示此处的棋子和第一次出现的颜色不一样
                                code = code + chesses[r][c1]; // 记录棋子相连的情况
                                break;
                            }
                        }
                    }
                    // 根据code的数据,作为map的key,从map中获取对应的value
                    Integer value = map.get(code);
                    if (value != null) {// 判断value是否不为null
                        weightArray[r][c] += value;
                    }

                    // 向右
                    for (int c1 = c + 1; c1 < chesses.length - 1; c1++) {
                        if (chesses[r][c1] == 0) {// 判断当前交叉点的右边是否为空位
                            if (c == c1 - 1) {// 判断是否为两个连续的空位,如果是则停止
                                break;
                            } else if (number == 0) {// 表示第一次出现空位
                                code = code + chesses[r][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 1) {// 表示第二次出现空位
                                if (chesses[r][c1] == chesses[r][c1 - 1]) {// 检测两个位置是否都为空位
                                    break;
                                }
                                code = code + chesses[r][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 2) { // 表示第三次出现空位
                                if (chesses[r][c1] == chesses[r][c1 - 1]) { // 检测两个位置是否都为空位
                                    break;
                                }
                            }
                        } else {// 当前交叉点的右边是棋子
                            if (chess == 0) { // 表示第一次出现棋子
                                chess = chesses[r][c1]; // 存储第一次出现的棋子
                                code = code + chesses[r][c1]; // 记录棋子相连的情况
                            } else if (chess == chesses[r][c1]) { // 判断是否和第一次出现的棋子颜色相同
                                code = code + chesses[r][c1]; // 记录棋子相连的情况
                            } else { // 表示此处的棋子和第一次出现的颜色不一样
                                code = code + chesses[r][c1]; // 记录棋子相连的情况
                                break;
                            }
                        }
                    }
                    System.out.println(code);
                    // 根据code的数据,作为map的key,从map中获取对应的value
                    value = map.get(code);
                    if (value != null) {// 判断value是否不为null
                        weightArray[r][c] += value;
                    }

                    // 向上
                    for (int r1 = r - 1; r1 >= 0; r1--) {
                        if (chesses[r1][c] == 0) {// 判断当前交叉点的上边是否为空位
                            if (r == r1 + 1) {// 判断是否为两个连续的空位,如果是则停止
                                break;
                            } else if (number == 0) {// 表示第一次出现空位
                                code = code + chesses[r1][c]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 1) {// 表示第二次出现空位
                                if (chesses[r1][c] == chesses[r1 + 1][c]) {// 检测两个位置是否都为空位
                                    break;
                                }
                                code = code + chesses[r1][c]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 2) { // 表示第三次出现空位
                                if (chesses[r1][c] == chesses[r1 + 1][c]) { // 检测两个位置是否都为空位
                                    break;
                                }
                            }
                        } else {// 当前交叉点的上边是棋子
                            if (chess == 0) { // 表示第一次出现棋子
                                chess = chesses[r1][c]; // 存储第一次出现的棋子
                                code = code + chesses[r1][c]; // 记录棋子相连的情况
                            } else if (chess == chesses[r1][c]) { // 判断是否和第一次出现的棋子颜色相同
                                code = code + chesses[r1][c]; // 记录棋子相连的情况
                            } else { // 表示此处的棋子和第一次出现的颜色不一样
                                code = code + chesses[r1][c]; // 记录棋子相连的情况
                                break;
                            }
                        }
                    }
                    System.out.println(code);
                    // 根据code的数据,作为map的key,从map中获取对应的value
                    value = map.get(code);
                    if (value != null) {// 判断value是否不为null
                        weightArray[r][c] += value;
                    }

                    // 向下
                    for (int r1 = r + 1; r1 < chesses.length - 1; r1++) {
                        if (chesses[r1][c] == 0) {// 判断当前交叉点的下边是否为空位
                            if (r == r1 - 1) {// 判断是否为两个连续的空位,如果是则停止
                                break;
                            } else if (number == 0) {// 表示第一次出现空位
                                code = code + chesses[r1][c]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 1) {// 表示第二次出现空位
                                if (chesses[r1][c] == chesses[r1 - 1][c]) {// 检测两个位置是否都为空位
                                    break;
                                }
                                code = code + chesses[r1][c]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 2) { // 表示第三次出现空位
                                if (chesses[r1][c] == chesses[r1 - 1][c]) { // 检测两个位置是否都为空位
                                    break;
                                }
                            }
                        } else {// 当前交叉点的下边是棋子
                            if (chess == 0) { // 表示第一次出现棋子
                                chess = chesses[r1][c]; // 存储第一次出现的棋子
                                code = code + chesses[r1][c]; // 记录棋子相连的情况
                            } else if (chess == chesses[r1][c]) { // 判断是否和第一次出现的棋子颜色相同
                                code = code + chesses[r1][c]; // 记录棋子相连的情况
                            } else { // 表示此处的棋子和第一次出现的颜色不一样
                                code = code + chesses[r1][c]; // 记录棋子相连的情况
                                break;
                            }
                        }
                    }
                    System.out.println(code);
                    // 根据code的数据,作为map的key,从map中获取对应的value
                    value = map.get(code);
                    if (value != null) {// 判断value是否不为null
                        weightArray[r][c] += value;
                    }

                    // 左下
                    for (int r1 = r - 1, c1 = c + 1; r1 >= 0 && c1 < chesses.length - 1; r1--, c1++) {
                        if (chesses[r1][c1] == 0) {// 判断当前交叉点的左下边是否为空位
                            if (r == r1 + 1 && c == c1 - 1) {// 判断是否为两个连续的空位,如果是则停止
                                break;
                            } else if (number == 0) {// 表示第一次出现空位
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 1) {// 表示第二次出现空位
                                if (chesses[r1][c1] == chesses[r1 + 1][c1 - 1]) {// 检测两个位置是否都为空位
                                    break;
                                }
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 2) { // 表示第三次出现空位
                                if (chesses[r1][c1] == chesses[r1 + 1][c1 - 1]) { // 检测两个位置是否都为空位
                                    break;
                                }
                            }
                        } else {// 当前交叉点的左下边是棋子
                            if (chess == 0) { // 表示第一次出现棋子
                                chess = chesses[r1][c1]; // 存储第一次出现的棋子
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                            } else if (chess == chesses[r1][c1]) { // 判断是否和第一次出现的棋子颜色相同
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                            } else { // 表示此处的棋子和第一次出现的颜色不一样
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                break;
                            }
                        }
                    }
                    System.out.println(code);
                    // 根据code的数据,作为map的key,从map中获取对应的value
                    value = map.get(code);
                    if (value != null) {// 判断value是否不为null
                        weightArray[r][c] += value;
                    }

                    // 右上
                    for (int r1 = r + 1, c1 = c - 1; r1 < chesses.length - 1 && c1 >= 0; r1++, c1--) {
                        if (chesses[r1][c1] == 0) {// 判断当前交叉点的右上边是否为空位
                            if (r == r1 - 1 && c == c1 + 1) {// 判断是否为两个连续的空位,如果是则停止
                                break;
                            } else if (number == 0) {// 表示第一次出现空位
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 1) {// 表示第二次出现空位
                                if (chesses[r1][c1] == chesses[r1 - 1][c1 + 1]) {// 检测两个位置是否都为空位
                                    break;
                                }
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 2) { // 表示第三次出现空位
                                if (chesses[r1][c1] == chesses[r1 - 1][c1 + 1]) { // 检测两个位置是否都为空位
                                    break;
                                }
                            }
                        } else {// 当前交叉点的右上边是棋子
                            if (chess == 0) { // 表示第一次出现棋子
                                chess = chesses[r1][c1]; // 存储第一次出现的棋子
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                            } else if (chess == chesses[r1][c1]) { // 判断是否和第一次出现的棋子颜色相同
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                            } else { // 表示此处的棋子和第一次出现的颜色不一样
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                break;
                            }
                        }
                    }
                    System.out.println(code);
                    // 根据code的数据,作为map的key,从map中获取对应的value
                    value = map.get(code);
                    if (value != null) {// 判断value是否不为null
                        weightArray[r][c] += value;
                    }

                    // 左上
                    for (int r1 = r - 1, c1 = c - 1; r1 >= 0 && c1 >= 0; r1--, c1--) {
                        if (chesses[r1][c1] == 0) {// 判断当前交叉点的左上边是否为空位
                            if (r == r1 + 1 && c == c1 + 1) {// 判断是否为两个连续的空位,如果是则停止
                                break;
                            } else if (number == 0) {// 表示第一次出现空位
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 1) {// 表示第二次出现空位
                                if (chesses[r1][c1] == chesses[r1 + 1][c1 + 1]) {// 检测两个位置是否都为空位
                                    break;
                                }
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 2) { // 表示第三次出现空位
                                if (chesses[r1][c1] == chesses[r1 + 1][c1 + 1]) { // 检测两个位置是否都为空位
                                    break;
                                }
                            }
                        } else {// 当前交叉点的左上边是棋子
                            if (chess == 0) { // 表示第一次出现棋子
                                chess = chesses[r1][c1]; // 存储第一次出现的棋子
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                            } else if (chess == chesses[r1][c1]) { // 判断是否和第一次出现的棋子颜色相同
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                            } else { // 表示此处的棋子和第一次出现的颜色不一样
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                break;
                            }
                        }
                    }
                    System.out.println(code);
                    // 根据code的数据,作为map的key,从map中获取对应的value
                    value = map.get(code);
                    if (value != null) {// 判断value是否不为null
                        weightArray[r][c] += value;
                    }

                    // 右下
                    for (int r1 = r + 1, c1 = c + 1; r1 < chesses.length - 1 && c1 < chesses.length - 1; r1++, c1++) {
                        if (chesses[r1][c1] == 0) {// 判断当前交叉点的右下边是否为空位
                            if (r == r1 - 1 && c == c1 - 1) {// 判断是否为两个连续的空位,如果是则停止
                                break;
                            } else if (number == 0) {// 表示第一次出现空位
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 1) {// 表示第二次出现空位
                                if (chesses[r1][c1] == chesses[r1 - 1][c1 - 1]) {// 检测两个位置是否都为空位
                                    break;
                                }
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                number++; // 空位出现次数增加1
                            } else if (number == 2) { // 表示第三次出现空位
                                if (chesses[r1][c1] == chesses[r1 - 1][c1 - 1]) { // 检测两个位置是否都为空位
                                    break;
                                }
                            }
                        } else {// 当前交叉点的右下边是棋子
                            if (chess == 0) { // 表示第一次出现棋子
                                chess = chesses[r1][c1]; // 存储第一次出现的棋子
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                            } else if (chess == chesses[r1][c1]) { // 判断是否和第一次出现的棋子颜色相同
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                            } else { // 表示此处的棋子和第一次出现的颜色不一样
                                code = code + chesses[r1][c1]; // 记录棋子相连的情况
                                break;
                            }
                        }
                    }
                    System.out.println(code);
                    // 根据code的数据,作为map的key,从map中获取对应的value
                    value = map.get(code);
                    if (value != null) {// 判断value是否不为null
                        weightArray[r][c] += value;
                    }

                } // 第一个if循环
            } // 第二个for循环
        } // 第一个for循环
    }// 方法

(3)点击开始新游戏,添加鼠标监听方法。然后选择对战模式。

public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("开始新游戏")) {
            // 添加鼠标监听方法
            ct.addMouseListener(this);
            // 开始新游戏需要把棋盘数组重置
            for (int j = 0; j < ChessTable.rows; j++) {
                for (int i = 0; i < ChessTable.columns; i++) {
                    chesses[i][j] = 0;
                }
            }
            ct.repaint();// 重绘棋盘
            // 黑棋先下
            count = 0;
        } else if (e.getActionCommand().equals("悔棋")) {
            if (list.size() > 0) {
                Point point = list.remove(list.size() - 1);
                int i = (point.x - ChessTable.x0) / ChessTable.size;
                int j = (point.y - ChessTable.y0) / ChessTable.size;
                chesses[i][j] = 0;
            }
            if (count == 1) {
                count--;
            } else {
                count++;
            }
            // 重绘
            ct.repaint();
        } else if (e.getActionCommand().equals("认输")) {
            if (list.size() > 0) {
                if (count == 0) {
                    System.out.println("执白子获胜,执黑子认输");
                } else {
                    System.out.println("执黑子获胜,执白子认输");
                }
                ct.removeMouseListener(this);
            }
        } else if (e.getSource() instanceof JComboBox) {
            // instanceof关键字主要功能是判断这个事件源是不是JComboBox的
            // 取到对象
            JComboBox<String> comboBox = (JComboBox) e.getSource();
            // 取到下拉菜单被选择的内容
            name = comboBox.getSelectedItem().toString();
            System.out.println("选择了对战模式" + "  " + name);
        }

    }

(4)如果是人机对战。要实现电脑自动画棋子的方法。判断出哪个位置为最大的权值,然后画棋子。

public void pve_draw() {
        this.weight();
        int max = 0;
        int xIndex = 0, yIndex = 0;
        int p = 0, q = 0;
        for (int i = 0; i < weightArray.length - 1; i++) {
            for (int j = 0; j < weightArray.length - 1; j++) {
                if (weightArray[i][j] > max) { // 找到第一个最大的权值
                    max = weightArray[i][j];
                    p = i;
                    q = j;
                    yIndex = i + 1;
                    xIndex = j + 1;
                }
            }
        }
        System.out.println(max + " " + "row:" + yIndex + " " + "column:" + xIndex + " " + p + " " + q);

        // 找出与权值最大值相等的数据
        int r = 0, c = 0;
        for (int i = 0; i < weightArray.length - 1; i++) {
            for (int j = 0; j < weightArray.length - 1; j++) {
                if (weightArray[i][j] == max) { // 找到第一个最大的
                    max = weightArray[i][j];
                    r = i;
                    c = j;

                    yIndex = i + 1;
                    xIndex = j + 1;
                }
            }
        }
        if (r != p && c != q) {
            System.out.println(max + " " + "row:" + yIndex + " " + "column:" + xIndex + " " + r + " " + c);
        }

        // 画棋子
        if (chesses[p][q] == 0) {
            int x = ChessTable.x0 + p * ChessTable.size;
            int y = ChessTable.y0 + q * ChessTable.size;
            g.setColor(Color.WHITE);
            g.fillOval(x - ChessTable.chess_size / 2, y - ChessTable.chess_size / 2, ChessTable.chess_size,
                    ChessTable.chess_size);
            Point point = new Point(x, y);
            list.add(point);
            chesses[p][q] = -1;
            weightArray[p][q] = 0; // 用完这个点要清空
            // 判断输赢
            if (judge(p, q)) {
                System.out.println("电脑执白子胜利");
                // 判断输赢后移除鼠标监听方法,不能再下棋子
                ct.removeMouseListener(this);
            }
        }

    }

(5)如果是人人对战模式,则是轮流下棋。

public void pvp(int x1, int y1) {
        for (int j = 0; j < ChessTable.rows; j++) {
            for (int i = 0; i < ChessTable.columns; i++) {
                int x = ChessTable.x0 + i * ChessTable.size;
                int y = ChessTable.y0 + j * ChessTable.size;
                if (x1 > x - ChessTable.size / 3 && x1 < x + ChessTable.size / 3 && y1 > y - ChessTable.size / 3
                        && y1 < y + ChessTable.size / 3) {
                    // 如果选择的位置没有棋子
                    if (chesses[i][j] == 0) {
                        if (count == 0) {
                            // 如果是黑子就为1
                            chesses[i][j] = 1;
                            g.setColor(Color.black);
                            count++;
                            // 调用判断输赢的方法
                            if (judge(i, j)) {
                                System.out.println("执黑子胜利");
                                // 判断输赢后移除鼠标监听方法,不能再下棋子
                                ct.removeMouseListener(this);
                            }
                        } else {
                            // 如果是白子就为-1
                            chesses[i][j] = -1;
                            g.setColor(Color.WHITE);
                            count--;
                            // 调用判断输赢的方法
                            if (judge(i, j)) {
                                System.out.println("执白子胜利");
                                // 判断输赢后移除鼠标监听方法,不能再下棋子
                                ct.removeMouseListener(this);
                            }
                        }

                        // 以最近的交叉点为圆心画圆
                        g.fillOval(x - ChessTable.chess_size / 2, y - ChessTable.chess_size / 2, ChessTable.chess_size,
                                ChessTable.chess_size);
                        Point point = new Point(x, y);
                        list.add(point);// 根据图形的数据实例化Array对象
                        return;
                    }
                }
            }
        }
    }

(6)最后则是判断选择了哪种游戏方式。

public void mouseReleased(MouseEvent e) {
        // 获取鼠标事件发生时光标的位置
        int x1 = e.getX();
        int y1 = e.getY();

        // 人机大战
        if (name.equals("人机对战")) {
            for (int j = 0; j < ChessTable.rows; j++) {
                for (int i = 0; i < ChessTable.columns; i++) {
                    int x = ChessTable.x0 + i * ChessTable.size;
                    int y = ChessTable.y0 + j * ChessTable.size;
                    if (x1 > x - ChessTable.size / 3 && x1 < x + ChessTable.size / 3 && y1 > y - ChessTable.size / 3
                            && y1 < y + ChessTable.size / 3) {
                        if (chesses[i][j] == 0) {
                            chesses[i][j] = 1;
                            g.setColor(Color.black);
                            // 以最近的交叉点为圆心画圆
                            g.fillOval(x - ChessTable.chess_size / 2, y - ChessTable.chess_size / 2,
                                    ChessTable.chess_size, ChessTable.chess_size);
                            // 调用判断输赢的方法
                            if (judge(i, j)) {
                                System.out.println("执黑子胜利");
                                // 判断输赢后移除鼠标监听方法,不能再下棋子
                                ct.removeMouseListener(this);
                                //判断输赢后,弹出一个窗口
                            //  JOptionPane.showMessageDialog(null, "黑棋赢");
                                return;
                            }
                            Point point = new Point(x, y);
                            list.add(point);// 根据图形的数据实例化Array对象
                            this.pve_draw();
                            System.out.println(x1 + " " + y1);
                            return;
                        }
                    }
                }
            }
        } else if (name.equals("人人对战")) {
            System.out.println(x1 + " " + y1);
            this.pvp(x1, y1);
        }

    }

猜你喜欢

转载自blog.csdn.net/qq1925346284/article/details/82588541