五子棋小游戏 java版(代码+详细注释)

news2024/11/27 4:26:44
游戏展示

        这周闲来无事,再来写个五子棋小游戏。基本功能都实现了,包括人人对战、人机对战。界面布局和功能都写的还行,没做到很优秀,但也不算差。如有需要,做个java初学者的课程设计或者自己写着玩玩也都是不错的(非常简单,小白照着就能写出来)。完整代码在最后,可直接到最后粘贴,代码里面也附有详细的注释,我也会在前面对设计思路和程序的一些地方进行讲解,希望对各位有用。(如果有什么讲的不好的地方,也欢迎大家批评指正...)


目录

游戏展示​编辑

讲解

界面布局

创建窗口

 创建容器面板MPanel继承JPanel

 重写paint方法

放置按钮和JLabel组件

基本功能

画棋子和画选择框

 判断输赢

按钮功能 

五元组算法

代码


游戏展示

共有两种模式,一种人与人下棋,一种为人机对战,人机又分人持黑或持白。在游戏中也有悔棋和重新游戏的功能。大家也都玩过五子棋,这里也没什么特别好讲的。


讲解

这里分三个方面讲,包括界面的布局实现、基本功能的实现,和五元法实现的人机对战。

界面布局

创建窗口

创建一个游戏窗口MFrame,new一个JFrame(也可以直接继承),然后在给它添加一系列属性。

public class MFrame {
    public static void main(String[] args) {
        JFrame jf = new JFrame("五子棋小游戏");
        
        jf.add(new TablePanel());

        jf.pack();  //自动适配大小
        jf.setLocationRelativeTo(null);     //界面居中
        jf.setResizable(false); //不可调整大小
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //按×关闭
        jf.setVisible(true);    //是否可见
    }
}

 创建容器面板TablePanel继承JPanel

设置它的长宽、背景图片和布局方式,布局方式的应用后面会详细讲一下。

public class TablePanel extends JPanel {
    //Panel的长宽
    final int TABLE_WIDTH = 700;
    final int TABLE_HEIGHT = 580;
    SpringLayout springLayout = new SpringLayout(); //设置springLayout布局,方便按钮位置的部署

    public TablePanel() {
        setLayout(springLayout);    //设置弹性布局方式
        setPreferredSize(new Dimension(TABLE_WIDTH, TABLE_HEIGHT)); //设置组件的首选大小
        setBackground(Color.green); //设置背景颜色
    }
}

运行一下,就能得到一个绿色的面板。

 重写paint方法

重写paint方法,后面还有三个方法,分别来画棋盘、棋子和右上角的提示区域。

@Override
    public void paint(Graphics g) {
        //定义一个Graphics2D
        Graphics2D gg = (Graphics2D) g;
        gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        gg.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);

        //画棋盘
        initPaint(g, gg);
        //画棋子
        ovalPaint(gg);
        //画提示框
        sidePaint(gg);
    }

这个定义了个Graphics2D,并设置了一些属性,主要是为了消除棋子的锯齿。

效果可以看下面的图,左边是没有消除锯齿的,右边是消除的,可以看到效果还是有点明显的。

 画棋盘

简单的画几条线,稍微的再装饰一下,来画出一个棋盘。

这里面用Graphics2D是为了改变一些线的宽度。

    final int NUM = 15;             //棋盘线的条数
    final int OFFSET_X = 30;  //棋盘左上角相对于panel左上角的偏移量(棋盘的起始位置)
    final int OFFSET_Y = 80;
    final int SP = 33; //棋盘每条线的间隔
    final int RECT_SIZE = 6;    //棋盘上五个提示点的位置
    BasicStroke bs; //定义画笔宽度(因为不止一个方法用,就定义在外面)

    private void initPaint(Graphics g, Graphics2D gg) {
        super.paint(g);
        //画棋盘的线
        g.setColor(Color.BLACK);
        for (int i = 0; i < NUM; i++) {
            g.drawLine(OFFSET_X + SP * i, OFFSET_Y, OFFSET_X + SP * i, OFFSET_Y + SP * (NUM - 1));
        }
        for (int i = 0; i < NUM; i++) {
            g.drawLine(OFFSET_X, OFFSET_Y + SP * i, OFFSET_X + SP * (NUM - 1), OFFSET_Y + SP * i);
        }

        //加点点缀
        //五个定位的小方块
        g.fillRect(OFFSET_X + SP * 3 - RECT_SIZE / 2, OFFSET_Y + SP * 3 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);
        g.fillRect(OFFSET_X + SP * 11 - RECT_SIZE / 2, OFFSET_Y + SP * 3 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);
        g.fillRect(OFFSET_X + SP * 3 - RECT_SIZE / 2, OFFSET_Y + SP * 11 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);
        g.fillRect(OFFSET_X + SP * 11 - RECT_SIZE / 2, OFFSET_Y + SP * 11 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);
        g.fillRect(OFFSET_X + SP * 7 - RECT_SIZE / 2, OFFSET_Y + SP * 7 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);
        //再加几条粗一点的线
        bs = new BasicStroke(3);       // 画笔宽度为5
        gg.setStroke(bs);
        gg.drawRect(OFFSET_X - 7, OFFSET_Y - 7, (NUM - 1) * SP + 14, (NUM - 1) * SP + 14);
        bs = new BasicStroke(2);
        gg.setStroke(bs);
        for (int i = 1; i < NUM; i = i + 4) {
            gg.drawLine(OFFSET_X + SP * i, OFFSET_Y, OFFSET_X + SP * i, OFFSET_Y + SP * (NUM - 1));
        }
        for (int i = 1; i < NUM; i = i + 4) {
            gg.drawLine(OFFSET_X, OFFSET_Y + SP * i, OFFSET_X + SP * (NUM - 1), OFFSET_Y + SP * i);
        }
    }

效果如下

 画棋子

主要的实现思路是:定义了一个table二维数组,刷新整个二维数组,里面数值为2的,则在相对应的地方画出黑色棋子;为1则画白色;0则不用管。

    int[][] table = new int[NUM][NUM];  //二维数字记录棋盘上每个位置上的棋子 (0无棋子  1白子  2黑子)
    final int OVAL_SIZE = 32;   //棋子的大小
    
    private void ovalPaint(Graphics2D gg) {
        //画棋子
        //每次点击后,会刷新一下棋盘,根据table的值画黑或白字

        //画实体棋子
        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM; j++) {
                int x = OFFSET_X + SP * i - OVAL_SIZE / 2;
                int y = OFFSET_Y + SP * j - OVAL_SIZE / 2;
                if (table[i][j] == 2) {
                    gg.setColor(Color.BLACK);
                    gg.fillOval(x, y, OVAL_SIZE, OVAL_SIZE);
                } else if (table[i][j] == 1) {
                    gg.setColor(Color.WHITE);
                    gg.fillOval(x, y, OVAL_SIZE, OVAL_SIZE);
                } else if (table[i][j] == 3) {
                    gg.setColor(Color.RED);
                    gg.drawOval(x, y, OVAL_SIZE, OVAL_SIZE);
                }
            }
        }
    }

 画提示框

就是画右上角的一些东西,我也不知道叫啥好,就叫提示区域吧。

根据游戏的进行,来显示出不同的文字。

这里的文字是用drawString()方法写出来的,但是屏幕中另外的字是用JLabel组件实现的。效果差不多,怎么方便怎么来吧!

    int isStart;
    boolean isWin;
    int oval_type = 2; //所要下的棋子的颜色 1白 2黑
    int step;

    private void sidePaint(Graphics2D gg) {
        if (isStart != 0) {
            //开始游戏时
            if (isWin) {
                //赢了后
                gg.setColor((oval_type == 1 ? Color.black : Color.white));
                gg.setFont(font3);
                gg.drawString((oval_type == 1 ? "黑方赢" : "白方赢"), 520, 170);
            } else {
                //没赢之前
                gg.setColor(Color.red);
                gg.setFont(font4);
                gg.drawString("轮到:", 520, 105);

                if (oval_type == 2) {
                    gg.setColor(Color.black);
                } else if (oval_type == 1) {
                    gg.setColor(Color.white);
                }
                gg.drawString((oval_type == 2 ? "黑方" : "白方"), 530, 150);
                gg.fillOval(610, 125, 40, 40);

                gg.setColor(Color.red);
                gg.drawString("步数:", 520, 200);
                gg.setColor(Color.black);
                gg.drawString(step + "", 620, 200);
            }
        } else {
            gg.setColor(Color.RED);
            gg.setFont(font4);
            gg.drawString("请选择游", 525, 150);
            gg.drawString("戏类型", 525, 190);
        }
    }

放置按钮和JLabel组件

创建一些Font 

    Dimension buttonSize = new Dimension(130, 30);    //设置按钮大小
    //设置字体的形状
    Font font1 = new Font("华文行楷", Font.PLAIN, 30);
    Font font2 = new Font("楷体", Font.PLAIN, 20);
    Font font3 = new Font("华文行楷", Font.PLAIN, 50);
    Font font4 = new Font("华文行楷", Font.PLAIN, 35);

创建按钮和JLabel组件

    JLabel titleLabel = new JLabel("逗呵呵五子棋");
    JLabel selectLabel = new JLabel("游戏选择:");
    JButton rrBtn = new JButton("人人对战");
    JButton rjbBtn = new JButton("人机.持黑");
    JButton rjwBtn = new JButton("人机.持白");
    JLabel elseLabel = new JLabel("其他设置:");
    JButton regretBtn = new JButton("悔棋");
    JButton restartBtn = new JButton("重新游戏");
    JButton endBtn = new JButton("结束游戏");

放置这些组件 

        private void initBtn() {
        //将button和label设置各自的属性
        selectLabel.setFont(font1);
        rrBtn.setPreferredSize(buttonSize);
        rrBtn.setFont(font2);
        rjbBtn.setPreferredSize(buttonSize);
        rjbBtn.setFont(font2);
        rjwBtn.setPreferredSize(buttonSize);
        rjwBtn.setFont(font2);
        elseLabel.setFont(font1);
        regretBtn.setPreferredSize(buttonSize);
        regretBtn.setFont(font2);
        restartBtn.setPreferredSize(buttonSize);
        restartBtn.setFont(font2);
        endBtn.setPreferredSize(buttonSize);
        endBtn.setFont(font2);
        titleLabel.setFont(font3); // 标题

        //将其放入
        add(selectLabel);
        add(rrBtn);
        add(rjbBtn);
        add(rjwBtn);
        add(elseLabel);
        add(regretBtn);
        add(restartBtn);
        add(endBtn);
        add(titleLabel);

        //设置各自的位置,使用弹性布局

        //将标题放置到中建位置
        int offsetX = Spring.width(titleLabel).getValue() / 2;
        springLayout.putConstraint(SpringLayout.WEST, titleLabel, -offsetX,
                SpringLayout.HORIZONTAL_CENTER, this);
        springLayout.putConstraint(SpringLayout.NORTH, titleLabel, 10, SpringLayout.NORTH, this);


        springLayout.putConstraint(SpringLayout.WEST, selectLabel, 525,
                SpringLayout.WEST, this);
        springLayout.putConstraint(SpringLayout.NORTH, selectLabel, 260, SpringLayout.NORTH, this);

        springLayout.putConstraint(SpringLayout.WEST, rrBtn, 5,
                SpringLayout.WEST, selectLabel);
        springLayout.putConstraint(SpringLayout.NORTH, rrBtn, 5, SpringLayout.SOUTH, selectLabel);

        springLayout.putConstraint(SpringLayout.WEST, rjbBtn, 0,
                SpringLayout.WEST, rrBtn);
        springLayout.putConstraint(SpringLayout.NORTH, rjbBtn, 5, SpringLayout.SOUTH, rrBtn);

        springLayout.putConstraint(SpringLayout.WEST, rjwBtn, 0,
                SpringLayout.WEST, rjbBtn);
        springLayout.putConstraint(SpringLayout.NORTH, rjwBtn, 5, SpringLayout.SOUTH, rjbBtn);

        springLayout.putConstraint(SpringLayout.WEST, elseLabel, 0,
                SpringLayout.WEST, selectLabel);
        springLayout.putConstraint(SpringLayout.NORTH, elseLabel, 10, SpringLayout.SOUTH, rjwBtn);

        springLayout.putConstraint(SpringLayout.WEST, regretBtn, 5,
                SpringLayout.WEST, elseLabel);
        springLayout.putConstraint(SpringLayout.NORTH, regretBtn, 5, SpringLayout.SOUTH, elseLabel);

        springLayout.putConstraint(SpringLayout.WEST, restartBtn, 0,
                SpringLayout.WEST, regretBtn);
        springLayout.putConstraint(SpringLayout.NORTH, restartBtn, 5, SpringLayout.SOUTH, regretBtn);

        springLayout.putConstraint(SpringLayout.WEST, endBtn, 0,
                SpringLayout.WEST, restartBtn);
        springLayout.putConstraint(SpringLayout.NORTH, endBtn, 5, SpringLayout.SOUTH, restartBtn);
    }

 写完后效果如下

 这里用的是SpringLayout(弹性布局),个人感觉这个布局还是挺好用的,虽然看起来复杂,用起来还是挺简单的。

拿一个例子来讲一下

        springLayout.putConstraint(SpringLayout.WEST, rrBtn, 5,
                SpringLayout.WEST, selectLabel);
        springLayout.putConstraint(SpringLayout.NORTH, rrBtn, 5, SpringLayout.SOUTH, selectLabel);

 这代码是设置rrBtn的位置,即rrBtn组件的西边距离selectLabel组件的西边正5个像素,rrBtn组件的北边距离selectLabel的南边正5个像素。(还是比较简单的吧,只是看着比较多)

布局到这就完成了,要是觉得不好看,自己也可以改,我个人感觉还是能看的。

基本功能

也没啥什么复杂的功能,也就包括画出棋子,画选择框,判断输赢,还有按钮的一些功能。

画棋子和画选择框

创建鼠标事件

MouseAdapter mouseAdapter = new MouseAdapter() {

};

 重写mouseClicked()方法

基本思路是,获得鼠标的xy值,在棋盘区域内,则讲鼠标的xy转换为二维数组的行和列,当点击时,将二维数组该处的值设置为2或者1,然后重绘画布。下完后改变棋子类型(oval_type)以便改变颜色。随着棋子的下出,改变提示框响应的内容。根据选择类型的不同,来确定下棋的方法,大体上是相同的,看看代码应该也能明白,这里写的有点乱,各位可以自己优化一下。(能用就好)

        @Override
        public void mouseClicked(MouseEvent e) {
            //赢的时候不能用
            if (!isWin) {
                if (isStart == 1) {
                    //来判断是否在棋盘内
                    if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2
                            && e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {

                        //将坐标转换为二维数组的i和j
                        mouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;
                        mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;
                        if (table[mouse_X][mouse_Y] == 0) {
                            table[mouse_X][mouse_Y] = oval_type;
                            if (oval_type == 2) {
                                oval_type = 1;
                                step++; //根据黑棋下的次数来增加总步数
                            } else if (oval_type == 1) {
                                oval_type = 2;
                            }
                            last_xy.add(mouse_X);
                            last_xy.add(mouse_Y);
                            //如果下了棋子,才能使用悔棋和重新游戏的按钮

                            restartBtn.setEnabled(true);
                            regretBtn.setEnabled(true);

                            judge(oval_type % 2 + 1, mouse_X, mouse_Y);

                        }
                        repaint();
                    }
                } else if (isStart == 2) {

                    if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2
                            && e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {
                        mouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;
                        mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;
                        if (table[mouse_X][mouse_Y] == 0) {
                            table[mouse_X][mouse_Y] = 2;
                            oval_type = 1;
                            last_xy.add(mouse_X);
                            last_xy.add(mouse_Y);
                            repaint();
                            judge(2, mouse_X, mouse_Y);
                            if (!isWin) {
                                machine();
                                table[robot_x][robot_y] = 1;
                                oval_type = 2;
                                judge(1, robot_x, robot_y);
                                last_xy.add(robot_x);
                                last_xy.add(robot_y);
                            }
                            step++;
                            restartBtn.setEnabled(true);
                            regretBtn.setEnabled(true);
                        }
                    }
                } else if (isStart == 3) {
                    if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2
                            && e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {
                        mouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;
                        mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;
                        if (table[mouse_X][mouse_Y] == 0) {
                            table[mouse_X][mouse_Y] = 1;
                            oval_type = 2;
                            last_xy.add(mouse_X);
                            last_xy.add(mouse_Y);
                            repaint();
                            judge(1, mouse_X, mouse_Y);
                            if (!isWin) {
                                machine();
                                table[robot_x][robot_y] = 2;
                                oval_type = 1;
                                judge(2, robot_x, robot_y);
                                last_xy.add(robot_x);
                                last_xy.add(robot_y);
                            }
                            step++;
                            restartBtn.setEnabled(true);
                            regretBtn.setEnabled(true);
                        }
                    }
                }
            }
        }

重写mouseMoved()方法

用来画红色的框框,也是比较简单的,和画棋子差不多。

        @Override
        public void mouseMoved(MouseEvent e) {
            if (!isWin) {
                if (isStart > 0) {
                    if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2
                            && e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {
                        select_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;
                        select_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;

                    } else {
                        select_X = -10;
                        select_Y = -10;
                    }
                }
            }
            repaint();
        }

 判断输赢

思路:判断下的位置的四个方向上是否有五个一样的。

    private void judge(int type, int x, int y) {
        //传入参数,来判断是黑(2)或白(1)子

        int sum;
        //判断四个方向
        //1.左 右
        sum = 0;
        for (int k = x - 1; k >= 0; k--) {
            if (table[k][y] == type) {
                sum++;
            } else {
                break;
            }
        }
        for (int k = x + 1; k < NUM; k++) {
            if (table[k][y] == type) {
                sum++;
            } else {
                break;
            }
        }
        if (sum >= 4) {
            isWin = true;
            return;
        }

        //2.上 下
        sum = 0;
        for (int k = y - 1; k >= 0; k--) {
            if (table[x][k] == type) {
                sum++;
            } else {
                break;
            }
        }
        for (int k = y + 1; k < NUM; k++) {
            if (table[x][k] == type) {
                sum++;
            } else {
                break;
            }
        }
        if (sum >= 4) {
            isWin = true;
            return;
        }

        //3。左上 右下
        sum = 0;
        for (int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--) {
            if (table[i][j] == type) {
                sum++;
            } else {
                break;
            }
        }
        for (int i = x + 1, j = y + 1; i < NUM && j < NUM; i++, j++) {
            if (table[i][j] == type)
                sum++;
            else {
                break;
            }
        }
        if (sum >= 4) {
            isWin = true;
            return;
        }

        //3。右上 左下
        sum = 0;
        for (int i = x - 1, j = y + 1; i >= 0 && j < NUM; i--, j++) {
            if (table[i][j] == type) {
                sum++;
            } else {
                break;
            }
        }
        for (int i = x + 1, j = y - 1; i < NUM && j >= 0; i++, j--) {
            if (table[i][j] == type)
                sum++;
            else {
                break;
            }
        }
        if (sum >= 4) {
            isWin = true;
            //return;
        }
    }

按钮功能 

每次进行点击后,改变某些属性的值,并重绘画布。

也没有啥难点。在改变按键是否可用的功能时已经晚上了,脑袋昏昏的,就哪里需要就加在哪里,使用可能导致全部代码里好多地方都有这些方法,各位也是可以自己优化的。

    ActionListener actionListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            JButton jButton = (JButton) e.getSource();
            String text = jButton.getText();
            if ("重新游戏".equals(text)) {
                init();

                if(isStart==3){
                    machine();
                    step++;
                    table[robot_x][robot_y] = 2;
                    oval_type = 1;
                }
                regretBtn.setEnabled(false);
                restartBtn.setEnabled(false);
            } else if ("悔棋".equals(text)) {
                int x = last_xy.get(last_xy.size() - 2);
                int y = last_xy.get(last_xy.size() - 1);
                table[x][y] = 0;
                last_xy.remove(last_xy.size() - 2);
                last_xy.remove(last_xy.size() - 1);
                oval_type = oval_type % 2 + 1;
                if (isStart == 2 || isStart == 3) {
                    x = last_xy.get(last_xy.size() - 2);
                    y = last_xy.get(last_xy.size() - 1);
                    table[x][y] = 0;
                    last_xy.remove(last_xy.size() - 2);
                    last_xy.remove(last_xy.size() - 1);
                    oval_type = oval_type % 2 + 1;
                }

                if (oval_type == 2||isStart==3) {
                    step--;
                }
                if (isWin) {
                    isWin = false;
                }
                if (last_xy.size() == 0) {
                    regretBtn.setEnabled(false);
                    restartBtn.setEnabled(false);
                }
            } else if ("结束游戏".equals(text)) {
                isStart = 0;
                init();
                rrBtn.setEnabled(true);
                rjbBtn.setEnabled(true);
                rjwBtn.setEnabled(true);
                regretBtn.setEnabled(false);
                restartBtn.setEnabled(false);
                endBtn.setEnabled(false);
            } else {
                //上面三个按钮
                if ("人人对战".equals(text)) {
                    isStart = 1;
                } else if ("人机.持黑".equals(text)) {
                    isStart = 2;
                } else if ("人机.持白".equals(text)) {
                    isStart = 3;
                    machine();
                    step++;
                    table[robot_x][robot_y] = 2;
                    oval_type = 1;
                }
                rrBtn.setEnabled(false);
                rjbBtn.setEnabled(false);
                rjwBtn.setEnabled(false);
                endBtn.setEnabled(true);
            }
            repaint();
        }
    };

五元组算法

这也是我在别人博客里面看到的方法,大家可以自行搜索详细的学习。

参考:五元组评价算法实现简易五子棋【人工智能】_YouthUpward的博客-CSDN博客_五元组算法

简单来讲,就是根据不同的情况给每个棋子赋值。我按照网上给的分值写了一下,虽然是做出来了,但感觉不是很强,不知道是哪里写错了还是怎么回事。

代码如下,供各位参考

     private void machine() {
        //传入棋子种类,判断颜色

        int[][] ts = new int[NUM][NUM]; //来记录每个点上的得分

        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM; j++) {
                ts[i][j] = 0;
            }
        }

        int wn; //白色个数
        int bn; //黑色个数

        //分4种情况
        //横向
        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM - 4; j++) {
                wn = 0;
                bn = 0;
                //5个
                for (int k = j; k < j + 5; k++) {
                    if (table[i][k] == 1) {
                        wn++;
                    } else if (table[i][k] == 2) {
                        bn++;
                    }
                }
                for (int k = j; k < j + 5; k++) {
                    if (table[i][k] == 0) {
                        ts[i][k] += score(wn, bn);
                    }
                }
            }
        }

        //纵向
        for (int j = 0; j < NUM; j++) {
            for (int i = 0; i < NUM - 4; i++) {
                wn = 0;
                bn = 0;
                for (int k = i; k < i + 5; k++) {
                    if (table[k][j] == 1) {
                        wn++;
                    } else if (table[k][i] == 2) {
                        bn++;
                    }
                }
                for (int k = i; k < i + 5; k++) {
                    if (table[k][i] == 0) {
                        ts[k][i] += score(wn, bn);
                    }
                }
            }
        }

        //左上 右下
        for (int i = 0; i < NUM - 4; i++) {
            for (int j = 0; j < NUM - 4; j++) {
                wn = 0;
                bn = 0;
                for (int ki = i, kj = j; ki < i + 5; ki++, kj++) {
                    if (table[ki][kj] == 1) {
                        wn++;
                    } else if (table[ki][kj] == 2) {
                        bn++;
                    }
                }
                for (int ki = i, kj = j; ki < i + 5; ki++, kj++) {
                    if (table[ki][kj] == 0) {
                        ts[ki][kj] += score(wn, bn);
                    }
                }
            }
        }

        //右上 左下
        for (int i = 4; i < NUM; i++) {
            for (int j = 0; j < NUM - 4; j++) {
                wn = 0;
                bn = 0;
                for (int ki = i, kj = j; kj < j + 5; ki--, kj++) {
                    if (table[ki][kj] == 1) {
                        wn++;
                    } else if (table[ki][kj] == 2) {
                        bn++;
                    }
                }
                for (int ki = i, kj = j; kj < j + 5; ki--, kj++) {
                    if (table[ki][kj] == 0) {
                        ts[ki][kj] += score(wn, bn);
                    }
                }
            }
        }

        Vector<Integer> vv = new Vector<>();
        int max = Integer.MIN_VALUE;

        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM; j++) {
                if (ts[i][j] > max) {
                    max = ts[i][j];
                }
            }
        }
        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM; j++) {
                if (ts[i][j] == max) {
                    vv.add(i);
                    vv.add(j);
                }
            }
        }
        Random random = new Random();
        int r = random.nextInt(vv.size() / 2);
        robot_x = vv.get(r * 2);
        robot_y = vv.get(r * 2 + 1);
        vv.clear();
    }

    private int score(int w, int b) {
        if (w > 0 && b > 0) {
            return 0;
        }
        if (w == 0 && b == 0) {
            return 7;
        }
        if (w == 1) {
            return 35;
        }
        if (w == 2) {
            return 800;
        }
        if (w == 3) {
            return 15000;
        }
        if (w == 4) {
            return 800000;
        }
        if (b == 1) {
            return 15;
        }
        if (b == 2) {
            return 400;
        }
        if (b == 3) {
            return 1800;
        }
        if (b == 4) {
            return 100000;
        }

        return -1;
    }

代码

TablePanel.java

package game_gobang;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import java.util.Vector;

public class TablePanel extends JPanel {

    //Panel的大小
    final int TABLE_WIDTH = 700;
    final int TABLE_HEIGHT = 580;

    final int NUM = 15;             //棋盘线的条数

    final int OFFSET_X = 30;  //棋盘左上角相对于panel左上角的偏移量(棋盘的起始位置)
    final int OFFSET_Y = 80;

    final int SP = 33; //棋盘每条线的间隔

    final int RECT_SIZE = 6;    //棋盘上五个提示点的位置

    final int OVAL_SIZE = 32;   //棋子的大小

    int[][] table = new int[NUM][NUM];  //二维数字记录棋盘上每个位置上的棋子 (0无棋子  1白子  2黑子)

    int step;

    int oval_type = 2; //所要下的棋子的颜色 1白 2黑

    int mouse_X;
    int mouse_Y;

    int select_X = -10;
    int select_Y = -10;

    //定义一个Vector,存储每次下的位置,来实现悔棋功能
    Vector<Integer> last_xy = new Vector<>();

    boolean isWin;  //是否赢

    int isStart;    //是否开始游戏 0未开始 1 2 3

    int robot_x;
    int robot_y;

    BasicStroke bs; //定义画笔宽度(因为不止一个方法用,就定义在外面)

    SpringLayout springLayout = new SpringLayout(); //设置springLayout布局,方便按钮位置的部署

    Dimension buttonSize = new Dimension(130, 30);    //设置按钮大小
    //设置字体的形状
    Font font1 = new Font("华文行楷", Font.PLAIN, 30);
    Font font2 = new Font("楷体", Font.PLAIN, 20);
    Font font3 = new Font("华文行楷", Font.PLAIN, 50);
    Font font4 = new Font("华文行楷", Font.PLAIN, 35);
    //定义一系列button和label
    JLabel titleLabel = new JLabel("逗呵呵五子棋");
    JLabel selectLabel = new JLabel("游戏选择:");
    JButton rrBtn = new JButton("人人对战");
    JButton rjbBtn = new JButton("人机.持黑");
    JButton rjwBtn = new JButton("人机.持白");
    JLabel elseLabel = new JLabel("其他设置:");
    JButton regretBtn = new JButton("悔棋");
    JButton restartBtn = new JButton("重新游戏");
    JButton endBtn = new JButton("结束游戏");

    public TablePanel() {
        setLayout(springLayout);    //设置弹性布局方式
        setPreferredSize(new Dimension(TABLE_WIDTH, TABLE_HEIGHT)); //设置组件的首选大小
        setBackground(Color.green); //设置背景颜色
        initBtn();  //初始化按钮
        init(); //初始化一些属性
        isStart = 0;
        addMouseListener(mouseAdapter); //添加鼠标监听
        addMouseMotionListener(mouseAdapter);
    }

    //初始化一些属性
    private void init() {
        //初始化二维数组
        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM; j++) {
                table[i][j] = 0;
            }
        }

        //初始化step
        step = 0;

        isWin = false;

        oval_type = 2;

        //初始化list
        last_xy.clear();
    }

    @Override
    public void paint(Graphics g) {
        //定义一个Graphics2D
        Graphics2D gg = (Graphics2D) g;
        gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        gg.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);

        //画棋盘
        initPaint(g, gg);
        //画棋子
        ovalPaint(gg);
        //画提示框
        sidePaint(gg);
    }

    private void ovalPaint(Graphics2D gg) {
        //画棋子
        //每次点击后,会刷新一下棋盘,根据table的值画黑或白字

        //画实体棋子
        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM; j++) {
                int x = OFFSET_X + SP * i - OVAL_SIZE / 2;
                int y = OFFSET_Y + SP * j - OVAL_SIZE / 2;
                if (table[i][j] == 2) {
                    gg.setColor(Color.BLACK);
                    gg.fillOval(x, y, OVAL_SIZE, OVAL_SIZE);
                } else if (table[i][j] == 1) {
                    gg.setColor(Color.WHITE);
                    gg.fillOval(x, y, OVAL_SIZE, OVAL_SIZE);
                } else if (table[i][j] == 3) {
                    gg.setColor(Color.RED);
                    gg.drawOval(x, y, OVAL_SIZE, OVAL_SIZE);
                }
            }
        }

        if (isWin) {
            //赢了就把选择框隐藏起来
            select_X = -10;
            select_Y = -10;
        } else {
            bs = new BasicStroke(1);       // 画笔宽度为1
            gg.setStroke(bs);
            //画选择框
            gg.setColor(Color.RED);
            gg.drawOval(OFFSET_X + SP * select_X - OVAL_SIZE / 2,
                    OFFSET_Y + SP * select_Y - OVAL_SIZE / 2,
                    OVAL_SIZE, OVAL_SIZE);
        }
    }

    //画棋盘
    private void initPaint(Graphics g, Graphics2D gg) {
        super.paint(g);
        //画棋盘的线
        g.setColor(Color.BLACK);
        for (int i = 0; i < NUM; i++) {
            g.drawLine(OFFSET_X + SP * i, OFFSET_Y, OFFSET_X + SP * i, OFFSET_Y + SP * (NUM - 1));
        }
        for (int i = 0; i < NUM; i++) {
            g.drawLine(OFFSET_X, OFFSET_Y + SP * i, OFFSET_X + SP * (NUM - 1), OFFSET_Y + SP * i);
        }

        //加点点缀
        //五个定位的小方块
        g.fillRect(OFFSET_X + SP * 3 - RECT_SIZE / 2, OFFSET_Y + SP * 3 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);
        g.fillRect(OFFSET_X + SP * 11 - RECT_SIZE / 2, OFFSET_Y + SP * 3 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);
        g.fillRect(OFFSET_X + SP * 3 - RECT_SIZE / 2, OFFSET_Y + SP * 11 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);
        g.fillRect(OFFSET_X + SP * 11 - RECT_SIZE / 2, OFFSET_Y + SP * 11 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);
        g.fillRect(OFFSET_X + SP * 7 - RECT_SIZE / 2, OFFSET_Y + SP * 7 - RECT_SIZE / 2, RECT_SIZE, RECT_SIZE);
        //再加几条粗一点的线
        bs = new BasicStroke(3);       // 画笔宽度为5
        gg.setStroke(bs);
        gg.drawRect(OFFSET_X - 7, OFFSET_Y - 7, (NUM - 1) * SP + 14, (NUM - 1) * SP + 14);
        bs = new BasicStroke(2);
        gg.setStroke(bs);
        for (int i = 1; i < NUM; i = i + 4) {
            gg.drawLine(OFFSET_X + SP * i, OFFSET_Y, OFFSET_X + SP * i, OFFSET_Y + SP * (NUM - 1));
        }
        for (int i = 1; i < NUM; i = i + 4) {
            gg.drawLine(OFFSET_X, OFFSET_Y + SP * i, OFFSET_X + SP * (NUM - 1), OFFSET_Y + SP * i);
        }
    }

    //画侧面(右上角)的提示框
    private void sidePaint(Graphics2D gg) {
        if (isStart != 0) {
            //开始游戏时
            if (isWin) {
                //赢了后
                gg.setColor((oval_type == 1 ? Color.black : Color.white));
                gg.setFont(font3);
                gg.drawString((oval_type == 1 ? "黑方赢" : "白方赢"), 520, 170);
            } else {
                //没赢之前
                gg.setColor(Color.red);
                gg.setFont(font4);
                gg.drawString("轮到:", 520, 105);

                if (oval_type == 2) {
                    gg.setColor(Color.black);
                } else if (oval_type == 1) {
                    gg.setColor(Color.white);
                }
                gg.drawString((oval_type == 2 ? "黑方" : "白方"), 530, 150);
                gg.fillOval(610, 125, 40, 40);

                gg.setColor(Color.red);
                gg.drawString("步数:", 520, 200);
                gg.setColor(Color.black);
                gg.drawString(step + "", 620, 200);
            }
        } else {
            gg.setColor(Color.RED);
            gg.setFont(font4);
            gg.drawString("请选择游", 525, 150);
            gg.drawString("戏类型", 525, 190);
        }
    }


    private void initBtn() {
        //将button和label设置各自的属性
        selectLabel.setFont(font1);
        rrBtn.setPreferredSize(buttonSize);
        rrBtn.setFont(font2);
        rjbBtn.setPreferredSize(buttonSize);
        rjbBtn.setFont(font2);
        rjwBtn.setPreferredSize(buttonSize);
        rjwBtn.setFont(font2);
        elseLabel.setFont(font1);
        regretBtn.setPreferredSize(buttonSize);
        regretBtn.setFont(font2);
        restartBtn.setPreferredSize(buttonSize);
        restartBtn.setFont(font2);
        endBtn.setPreferredSize(buttonSize);
        endBtn.setFont(font2);
        titleLabel.setFont(font3); // 标题

        //给按钮加上监听
        rrBtn.addActionListener(actionListener);
        rjbBtn.addActionListener(actionListener);
        rjwBtn.addActionListener(actionListener);
        regretBtn.addActionListener(actionListener);
        restartBtn.addActionListener(actionListener);
        endBtn.addActionListener(actionListener);

        //将其放入
        add(selectLabel);
        add(rrBtn);
        add(rjbBtn);
        add(rjwBtn);
        add(elseLabel);
        add(regretBtn);
        add(restartBtn);
        add(endBtn);
        add(titleLabel);

        //设置各自的位置,使用弹性布局

        //将标题放置到中建位置
        int offsetX = Spring.width(titleLabel).getValue() / 2;
        springLayout.putConstraint(SpringLayout.WEST, titleLabel, -offsetX,
                SpringLayout.HORIZONTAL_CENTER, this);
        springLayout.putConstraint(SpringLayout.NORTH, titleLabel, 10, SpringLayout.NORTH, this);


        springLayout.putConstraint(SpringLayout.WEST, selectLabel, 525,
                SpringLayout.WEST, this);
        springLayout.putConstraint(SpringLayout.NORTH, selectLabel, 260, SpringLayout.NORTH, this);

        springLayout.putConstraint(SpringLayout.WEST, rrBtn, 5,
                SpringLayout.WEST, selectLabel);
        springLayout.putConstraint(SpringLayout.NORTH, rrBtn, 5, SpringLayout.SOUTH, selectLabel);

        springLayout.putConstraint(SpringLayout.WEST, rjbBtn, 0,
                SpringLayout.WEST, rrBtn);
        springLayout.putConstraint(SpringLayout.NORTH, rjbBtn, 5, SpringLayout.SOUTH, rrBtn);

        springLayout.putConstraint(SpringLayout.WEST, rjwBtn, 0,
                SpringLayout.WEST, rjbBtn);
        springLayout.putConstraint(SpringLayout.NORTH, rjwBtn, 5, SpringLayout.SOUTH, rjbBtn);

        springLayout.putConstraint(SpringLayout.WEST, elseLabel, 0,
                SpringLayout.WEST, selectLabel);
        springLayout.putConstraint(SpringLayout.NORTH, elseLabel, 10, SpringLayout.SOUTH, rjwBtn);

        springLayout.putConstraint(SpringLayout.WEST, regretBtn, 5,
                SpringLayout.WEST, elseLabel);
        springLayout.putConstraint(SpringLayout.NORTH, regretBtn, 5, SpringLayout.SOUTH, elseLabel);

        springLayout.putConstraint(SpringLayout.WEST, restartBtn, 0,
                SpringLayout.WEST, regretBtn);
        springLayout.putConstraint(SpringLayout.NORTH, restartBtn, 5, SpringLayout.SOUTH, regretBtn);

        springLayout.putConstraint(SpringLayout.WEST, endBtn, 0,
                SpringLayout.WEST, restartBtn);
        springLayout.putConstraint(SpringLayout.NORTH, endBtn, 5, SpringLayout.SOUTH, restartBtn);

        regretBtn.setEnabled(false);
        restartBtn.setEnabled(false);
        endBtn.setEnabled(false);
    }

    ActionListener actionListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            JButton jButton = (JButton) e.getSource();
            String text = jButton.getText();
            if ("重新游戏".equals(text)) {
                init();

                if(isStart==3){
                    machine();
                    step++;
                    table[robot_x][robot_y] = 2;
                    oval_type = 1;
                }
                regretBtn.setEnabled(false);
                restartBtn.setEnabled(false);
            } else if ("悔棋".equals(text)) {
                int x = last_xy.get(last_xy.size() - 2);
                int y = last_xy.get(last_xy.size() - 1);
                table[x][y] = 0;
                last_xy.remove(last_xy.size() - 2);
                last_xy.remove(last_xy.size() - 1);
                oval_type = oval_type % 2 + 1;
                if (isStart == 2 || isStart == 3) {
                    x = last_xy.get(last_xy.size() - 2);
                    y = last_xy.get(last_xy.size() - 1);
                    table[x][y] = 0;
                    last_xy.remove(last_xy.size() - 2);
                    last_xy.remove(last_xy.size() - 1);
                    oval_type = oval_type % 2 + 1;
                }

                if (oval_type == 2||isStart==3) {
                    step--;
                }
                if (isWin) {
                    isWin = false;
                }
                if (last_xy.size() == 0) {
                    regretBtn.setEnabled(false);
                    restartBtn.setEnabled(false);
                }
            } else if ("结束游戏".equals(text)) {
                isStart = 0;
                init();
                rrBtn.setEnabled(true);
                rjbBtn.setEnabled(true);
                rjwBtn.setEnabled(true);
                regretBtn.setEnabled(false);
                restartBtn.setEnabled(false);
                endBtn.setEnabled(false);
            } else {
                //上面三个按钮
                if ("人人对战".equals(text)) {
                    isStart = 1;
                } else if ("人机.持黑".equals(text)) {
                    isStart = 2;
                } else if ("人机.持白".equals(text)) {
                    isStart = 3;
                    machine();
                    step++;
                    table[robot_x][robot_y] = 2;
                    oval_type = 1;
                }
                rrBtn.setEnabled(false);
                rjbBtn.setEnabled(false);
                rjwBtn.setEnabled(false);
                endBtn.setEnabled(true);
            }
            repaint();
        }
    };

    MouseAdapter mouseAdapter = new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            //赢的时候不能用
            if (!isWin) {
                if (isStart == 1) {
                    //来判断是否在棋盘内
                    if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2
                            && e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {

                        //将坐标转换为二维数组的i和j
                        mouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;
                        mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;
                        if (table[mouse_X][mouse_Y] == 0) {
                            table[mouse_X][mouse_Y] = oval_type;
                            if (oval_type == 2) {
                                oval_type = 1;
                                step++; //根据黑棋下的次数来增加总步数
                            } else if (oval_type == 1) {
                                oval_type = 2;
                            }
                            last_xy.add(mouse_X);
                            last_xy.add(mouse_Y);
                            //如果下了棋子,才能使用悔棋和重新游戏的按钮

                            restartBtn.setEnabled(true);
                            regretBtn.setEnabled(true);

                            judge(oval_type % 2 + 1, mouse_X, mouse_Y);

                        }
                        repaint();
                    }
                } else if (isStart == 2) {

                    if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2
                            && e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {
                        mouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;
                        mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;
                        if (table[mouse_X][mouse_Y] == 0) {
                            table[mouse_X][mouse_Y] = 2;
                            oval_type = 1;
                            last_xy.add(mouse_X);
                            last_xy.add(mouse_Y);
                            repaint();
                            judge(2, mouse_X, mouse_Y);
                            if (!isWin) {
                                machine();
                                table[robot_x][robot_y] = 1;
                                oval_type = 2;
                                judge(1, robot_x, robot_y);
                                last_xy.add(robot_x);
                                last_xy.add(robot_y);
                            }
                            step++;
                            restartBtn.setEnabled(true);
                            regretBtn.setEnabled(true);
                        }
                    }
                } else if (isStart == 3) {
                    if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2
                            && e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {
                        mouse_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;
                        mouse_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;
                        if (table[mouse_X][mouse_Y] == 0) {
                            table[mouse_X][mouse_Y] = 1;
                            oval_type = 2;
                            last_xy.add(mouse_X);
                            last_xy.add(mouse_Y);
                            repaint();
                            judge(1, mouse_X, mouse_Y);
                            if (!isWin) {
                                machine();
                                table[robot_x][robot_y] = 2;
                                oval_type = 1;
                                judge(2, robot_x, robot_y);
                                last_xy.add(robot_x);
                                last_xy.add(robot_y);
                            }
                            step++;
                            restartBtn.setEnabled(true);
                            regretBtn.setEnabled(true);
                        }
                    }
                }
            }
        }

        @Override
        public void mouseMoved(MouseEvent e) {
            if (!isWin) {
                if (isStart > 0) {
                    if (e.getX() > OFFSET_X - OVAL_SIZE / 2 && e.getX() < OFFSET_X + (NUM - 1) * SP + OVAL_SIZE / 2
                            && e.getY() > OFFSET_Y - OVAL_SIZE / 2 && e.getY() < OFFSET_Y + (NUM - 1) * SP + OVAL_SIZE / 2) {
                        select_X = (e.getX() - OFFSET_X + OVAL_SIZE / 2) / SP;
                        select_Y = (e.getY() - OFFSET_Y + OVAL_SIZE / 2) / SP;

                    } else {
                        select_X = -10;
                        select_Y = -10;
                    }
                }
            }
            repaint();
        }
    };

    //判断谁赢,扫描整个棋盘,来判断是否练成五个
    private void judge(int type, int x, int y) {
        //传入参数,来判断是黑(2)或白(1)子

        int sum;
        //判断四个方向
        //1.左 右
        sum = 0;
        for (int k = x - 1; k >= 0; k--) {
            if (table[k][y] == type) {
                sum++;
            } else {
                break;
            }
        }
        for (int k = x + 1; k < NUM; k++) {
            if (table[k][y] == type) {
                sum++;
            } else {
                break;
            }
        }
        if (sum >= 4) {
            isWin = true;
            return;
        }

        //2.上 下
        sum = 0;
        for (int k = y - 1; k >= 0; k--) {
            if (table[x][k] == type) {
                sum++;
            } else {
                break;
            }
        }
        for (int k = y + 1; k < NUM; k++) {
            if (table[x][k] == type) {
                sum++;
            } else {
                break;
            }
        }
        if (sum >= 4) {
            isWin = true;
            return;
        }

        //3。左上 右下
        sum = 0;
        for (int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--) {
            if (table[i][j] == type) {
                sum++;
            } else {
                break;
            }
        }
        for (int i = x + 1, j = y + 1; i < NUM && j < NUM; i++, j++) {
            if (table[i][j] == type)
                sum++;
            else {
                break;
            }
        }
        if (sum >= 4) {
            isWin = true;
            return;
        }

        //3。右上 左下
        sum = 0;
        for (int i = x - 1, j = y + 1; i >= 0 && j < NUM; i--, j++) {
            if (table[i][j] == type) {
                sum++;
            } else {
                break;
            }
        }
        for (int i = x + 1, j = y - 1; i < NUM && j >= 0; i++, j--) {
            if (table[i][j] == type)
                sum++;
            else {
                break;
            }
        }
        if (sum >= 4) {
            isWin = true;
            //return;
        }
    }


    //来写自动下棋的方法
    private void machine() {
        //传入棋子种类,判断颜色

        int[][] ts = new int[NUM][NUM]; //来记录每个点上的得分

        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM; j++) {
                ts[i][j] = 0;
            }
        }

        int wn; //白色个数
        int bn; //黑色个数

        //分4种情况
        //横向
        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM - 4; j++) {
                wn = 0;
                bn = 0;
                //5个
                for (int k = j; k < j + 5; k++) {
                    if (table[i][k] == 1) {
                        wn++;
                    } else if (table[i][k] == 2) {
                        bn++;
                    }
                }
                for (int k = j; k < j + 5; k++) {
                    if (table[i][k] == 0) {
                        ts[i][k] += score(wn, bn);
                    }
                }
            }
        }

        //纵向
        for (int j = 0; j < NUM; j++) {
            for (int i = 0; i < NUM - 4; i++) {
                wn = 0;
                bn = 0;
                for (int k = i; k < i + 5; k++) {
                    if (table[k][j] == 1) {
                        wn++;
                    } else if (table[k][i] == 2) {
                        bn++;
                    }
                }
                for (int k = i; k < i + 5; k++) {
                    if (table[k][i] == 0) {
                        ts[k][i] += score(wn, bn);
                    }
                }
            }
        }

        //左上 右下
        for (int i = 0; i < NUM - 4; i++) {
            for (int j = 0; j < NUM - 4; j++) {
                wn = 0;
                bn = 0;
                for (int ki = i, kj = j; ki < i + 5; ki++, kj++) {
                    if (table[ki][kj] == 1) {
                        wn++;
                    } else if (table[ki][kj] == 2) {
                        bn++;
                    }
                }
                for (int ki = i, kj = j; ki < i + 5; ki++, kj++) {
                    if (table[ki][kj] == 0) {
                        ts[ki][kj] += score(wn, bn);
                    }
                }
            }
        }

        //右上 左下
        for (int i = 4; i < NUM; i++) {
            for (int j = 0; j < NUM - 4; j++) {
                wn = 0;
                bn = 0;
                for (int ki = i, kj = j; kj < j + 5; ki--, kj++) {
                    if (table[ki][kj] == 1) {
                        wn++;
                    } else if (table[ki][kj] == 2) {
                        bn++;
                    }
                }
                for (int ki = i, kj = j; kj < j + 5; ki--, kj++) {
                    if (table[ki][kj] == 0) {
                        ts[ki][kj] += score(wn, bn);
                    }
                }
            }
        }

        Vector<Integer> vv = new Vector<>();
        int max = Integer.MIN_VALUE;

        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM; j++) {
                if (ts[i][j] > max) {
                    max = ts[i][j];
                }
            }
        }
        for (int i = 0; i < NUM; i++) {
            for (int j = 0; j < NUM; j++) {
                if (ts[i][j] == max) {
                    vv.add(i);
                    vv.add(j);
                }
            }
        }
        Random random = new Random();
        int r = random.nextInt(vv.size() / 2);
        robot_x = vv.get(r * 2);
        robot_y = vv.get(r * 2 + 1);
        vv.clear();
    }

    private int score(int w, int b) {
        if (w > 0 && b > 0) {
            return 0;
        }
        if (w == 0 && b == 0) {
            return 7;
        }
        if (w == 1) {
            return 35;
        }
        if (w == 2) {
            return 800;
        }
        if (w == 3) {
            return 15000;
        }
        if (w == 4) {
            return 800000;
        }
        if (b == 1) {
            return 15;
        }
        if (b == 2) {
            return 400;
        }
        if (b == 3) {
            return 1800;
        }
        if (b == 4) {
            return 100000;
        }

        return -1;
    }
}

MFrame.java

package game_gobang;

import javax.swing.*;

public class MFrame {
    public static void main(String[] args) {
        JFrame jf = new JFrame("五子棋小游戏");

        jf.add(new TablePanel());

        jf.pack();  //自动适配大小
        jf.setLocationRelativeTo(null);     //居中
        jf.setResizable(false); //不可调整大小
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //按×关闭
        jf.setVisible(true);    //是否可见
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/753344.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于酒吧的八个大实话

1、酒吧风格定位取决于你酒吧面向的客户群体 2、酒吧要根据所在地区人流量开酒吧&#xff0c;大酒吧开在人流量少的可能死于客流量太小&#xff0c;合理的酒吧规模才能生存。3、酒吧客群不能只面向亲朋好友&#xff0c;再好的朋友也不可能天天来照顾你的生意。4、酒吧注重酒吧…

Task管理系统项目

Task管理系统项目 项目开发意义和目的 本项目所开发的系统为Task管理系统。管理信息系统是一个由人和计算机等组成的能够提供信息以支持一个组织机构内部的作业、管理、分析和决策职能的系统。管理信息系统利用计算机的硬件和软件&#xff0c;手工规程.分析、计划、控制和决策用…

浏览器视口

目录 css单位相对单位绝对单位 像素分类物理像素逻辑像素css像素 DPRPPI浏览器视口布局视口视觉视口理想视口 css单位 在css中我们会使用到许多单位&#xff0c;如px&#xff0c;em&#xff0c;rem&#xff0c;vw&#xff0c;vh等等 整体上&#xff0c;我们可以将它们分成两类…

XXE漏洞

XML基础 概述 XML是一种用于标记电子文件使其具有结构性的可扩展标记语言。 XML是一种灵活的语言&#xff0c;类似于HTML语言&#xff0c;但是并没有固定的标签&#xff0c;所有标签都可以自定义&#xff0c;其设计的宗旨是传输数据&#xff0c;而不是像HTML一样显示数据。 …

Cortex-M3与Aurix的堆栈

1. TC397是一个基于ARM Cortex-M3内核的微控制器芯片&#xff0c;其堆栈是由系统初始化代码初始化的。在ARM Cortex-M3架构中&#xff0c;堆栈通常由两个寄存器来管理&#xff1a;主堆栈指针&#xff08;MSP&#xff09;和进程堆栈指针&#xff08;PSP&#xff09;。 1.1 MSP是…

Vue-品牌列表案例

1.案例效果 2.用到的知识点 bootstrap 4.x 相关的知识点&#xff1a; 卡片&#xff08;Card&#xff09;、表单相关(Forms)、按钮(Buttons)、表格(Tables) vue指令与过滤器相关的知识点&#xff1a; 插值表达式、属性绑定、事件绑定、双向数据绑定、修饰符、条件渲染、列表…

云HIS系统使用和操作过程中的常见问题及解决方法

云HIS系统使用和操作过程中的常见问题及解决方法 一、门诊业务中遇到的问题 &#xff08;1&#xff09;门诊医生如何查询往期病人&#xff1f; 答&#xff1a;点击门诊医生站左侧患者列表&#xff0c;在弹出的页面点击已诊分页&#xff0c;在搜索框输入患者姓名&#xff0c;在…

数据库基本操作--------MySQL存储引擎

目录 一、存储引擎概念介绍 二、MySQL常用的存储引擎 1、MyISAM 2.1.1 MyISAM的特点 2.1.2 MyISAM 表支持 3 种不同的存储格式 2.1.3 MyISAM适用的生产场景 2、InnoDB 2.2.1 InnoDB特点 三、查看系统支持的存储引擎 四、查看表使用的存储引擎 方法一 五、修改存储引擎…

「网络编程」应用层协议_ HTTPS协议学习及原理理解

「前言」文章内容大致是应用层协议的HTTPS协议讲解&#xff0c;续上篇HTTP协议。 「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、HTTPS协议介绍二、什么是"加密"三、为什么要加密四、常见的加密方式五、数据摘要 && 数据指纹六、…

直方图 直方图均衡化

直方图 直方图定义mask操作直方图均衡化均衡化效果自适应直方图均衡化 直方图定义 hist cv2.calcHist(images, channels, mask, histSize, ranges, …) # hist是一个256*1的矩阵&#xff0c;其中每一个值代表了一个灰度值对应的像素点数目 images&#xff1a;原图像格式为ui…

医学图像分割的三视图特征学习

文章目录 Triple-View Feature Learning for Medical Image Segmentation摘要本文方法实验结果 Triple-View Feature Learning for Medical Image Segmentation 摘要 深度学习模型&#xff0c;例如监督编码器-解码器风格的网络&#xff0c;在医学图像分割中表现出很好的性能&…

page_dewarp实现弯曲文本矫正

朋友们&#xff0c;如果你使用ocr&#xff0c;再识别的时候会遇到文本扭曲的问题&#xff0c;为了解决这个问题&#xff0c;需要进行弯曲文本矫正&#xff0c;这里推荐一个开源项目&#xff0c;可以使用上面的功能进行矫正&#xff0c;不过里面可能需要改动一些代码&#xff0c…

Python微服务架构设计使用asyncio提升性能

文章目录 1 引言2 微服务概念3 backend-for-frontend 模式4 实施产品列表 API4.1 实现基础服务4.2 实现BFF服务4.3 重试失败的请求4.4 断路器模式 5 总结 1 引言 许多 Web 应用程序都被构建为单体应用程序&#xff0c;单体应用程序通常是包含多个模块的大中型应用程序&#xf…

clickhouse优化使用clickhouse-keeper替代zookeeper

ClickHouse Keeper 是 ZooKeeper 的替代品&#xff0c;与 ZooKeeper 不同&#xff0c;ClickHouse Keeper 是用 C 编写的&#xff0c;并使用 RAFT 算法实现&#xff0c;该算法允许对读写具有线性化能力。 clikhouse-keeper目的在于替换zookeeper&#xff0c;使用clickhouse后&am…

【python】从Ensembl上,根据Array HumanMethylation450甲基化探针cg编号(比如cg13788592)获取位置

文章目录 1. 写在前面2. 手动查找和探索过程从UCSC查找从Ensembl查找 3. 代码实现 1. 写在前面 一篇专利 1 中提到多种癌种及对应的特异性CpG位点&#xff0c;想获取对应cg位点具体的位置或序列。专利中的一组CpG markers如下&#xff1a; 需求就是&#xff1a;将这些cg编号作…

Learning Enriched Features for Fast Image Restoration and Enhancement 论文阅读笔记

这是2022年TPAMI上发表的大名鼎鼎的MIRNetv2&#xff0c;是一个通用的图像修复和图像质量增强模型&#xff0c;核心是一个多尺度的网络 网络结构整体是残差的递归&#xff0c;不断把残差展开可以看到是一些残差块的堆叠。核心是多尺度的MRB。网络用的损失函数朴实无华&#x…

DuDuTalk:智能语音工牌如何赋能销售过程管理?

智能语音工牌是一种智能语音采集设备&#xff0c;配合ASR、NLP、语音分析、文本挖掘等AI技术&#xff0c;它可以帮助企业实现销售过程的监控、分析和改进。在这篇文章中&#xff0c;我们将探讨如何利用录音工牌实现销售过程管理&#xff0c;并介绍其重要性和应用。 1、什么是销…

3.9 JavaDoc生成文档

3.9 JavaDoc生成文档 javadoc命令是用来生成自己API文档的 javadoc是一种技术&#xff0c;他可以将我们的注释信息生成一个帮助文档 参数信息author 作者名version 版本号since 指明需要最早使用的JDK版本param 参数名return 返回值情况throws 异常抛出情况文档注释 /**回车…

接口测试-Jmeter响应数据结果保存到csv文件2种方式(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 日常接口测试&…

阿里巴巴最新总结 Spring Security Oauth2.0 认证授权全彩笔记

Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。由于它是 Spring 生态系统中的一员&#xff0c;因此它伴随着整个 Spring 生态系统不断修正、升级&#xff0c;在 Spring Boot 项目中加入 Spring Security 更是十分简单&a…