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

151 阅读6分钟

游戏展示

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

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

界面布局 创建窗口 创建一个游戏窗口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);    //是否可见
}

}