用Java编写简单的五子棋——人机对战!

前言

2022-02-04,农历正月初四
  首先在这祝大家新年快乐。
  距离上两个版本的更新已经过去了很久,因为年前工作非常忙,经常熬到凌晨,导致我看大家私信和回复的时间有限,但我会用上厕所摸鱼的宝贵时间仔细查看并回应大家的互动。
  那天我看到有同学问我人机对战如何实现,说实话这玩意三言两语很难解释清楚,不如直接写一个让大家看来的直接,所以我没有回答他的问题,而是找时间把这个功能做出来,争取让所有想问这个问题的同学找到答案。
  终于来到了年假,招待完亲戚朋友后,脑子里的第一件事就是将这个功能做完展示给大家,博主不才,花了一下午时间干出来,就当我给大家的新年礼物了。
  

测试类

import javax.swing.*;

public class Test {
    public static void main(String[] args) {
        Object[] objects={"人人对战","人机对战"};
        int a = JOptionPane.showOptionDialog(null,"请选择游戏模式","请选择",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE,null, objects, objects[0]);
        System.out.println(a);
        if (a == 0){
            MyJFrame mj = new MyJFrame();
            mj.myJFrame();
        }else if (a == 1){
            MyJFrame_AI mjAI = new MyJFrame_AI();
            mjAI.myJFrame();
        }else{
            System.exit(0);
        }
    }
}

  

MyJFrame类代码

import jdk.nashorn.internal.scripts.JO;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class MyJFrame extends JFrame implements MouseListener {
    int qx = 20, qy = 40, qw = 490, qh = 490; //棋盘位置、宽高
    int bw = 150, bh = 50, bx = 570, by = 150; //按钮宽高、位置
    int x = 0, y = 0; //保存棋子坐标
    int[][] SaveGame = new int[15][15]; //保存每个棋子
    int qc = 1;//记录白棋=2,黑棋=1
    int qn = 0;//判断棋子是否重复
    boolean canplay = true; //判断游戏是否开始和结束
    String go = "黑子先行"; //游戏信息
    int bq = 0, hq = 0;


    //---------------------------------------------------------------------------------------------------------------------
    //窗体
    public void myJFrame() {

        this.setTitle("五子棋"); //标题
        this.setSize(800, 550); //窗口大小
        this.setResizable(false); //窗口是否可以改变大小=否
        this.setDefaultCloseOperation(MyJFrame.EXIT_ON_CLOSE); //窗口关闭方式为关闭窗口同时结束程序

        int width = Toolkit.getDefaultToolkit().getScreenSize().width; //获取屏幕宽度
        int height = Toolkit.getDefaultToolkit().getScreenSize().height; //获取屏幕高度
//        System.out.println("宽度:"+width);//测试
//        System.out.println("高度:"+height);//测试

        this.setLocation((width - 800) / 2, (height - 600) / 2); //设置窗口默认位置以屏幕居中

        this.addMouseListener(this);

        this.setVisible(true); //窗口是否显示=是
    }

    public class Position {
        int listx;
        int listy;
    }

    public class chessUI extends JPanel {
        public Position[] ps = new Position[300];
        int i;
    }

    chessUI ui = new chessUI();
    Position p = new Position();


    //---------------------------------------------------------------------------------------------------------------------
    //覆写paint方法,绘制界面
    public void paint(Graphics g) {

        //双缓冲技术防止屏幕闪烁
        BufferedImage bi = new BufferedImage(800, 550, BufferedImage.TYPE_INT_ARGB);
        Graphics g2 = bi.createGraphics();

        //获取图片路径
        BufferedImage image = null;
        try {
            //获取项目文件夹路径
            File directory = new File("");
            //路径拼接
            image = ImageIO.read(new File(directory.getAbsolutePath() + "/tp/wzqbj.jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        g2.drawImage(image, 10, 10, this); //显示图片

        g2.setColor(Color.BLACK);//设置画笔颜色
        g2.setFont(new Font("华文行楷", 10, 50)); //设置字体
        g2.drawString("晓时五子棋", 525, 100); //绘制字符

        //棋盘
        g2.setColor(Color.getHSBColor(30, (float) 0.10, (float) 0.90)); //设置画笔颜色
        g2.fillRect(qx, qy, qw, qh); //绘制棋盘背景矩形

        //开始按钮
        g2.setColor(Color.WHITE); //设置画笔颜色
        g2.fillRect(bx, by, bw, bh); //绘制开始按钮
        g2.setFont(new Font("华文行楷", 10, 30)); //设置字体
        g2.setColor(Color.black); //设置画笔颜色
        g2.drawString("开始", 615, 185); //绘制字符

        //悔棋按钮
        g2.setColor(Color.LIGHT_GRAY); //设置画笔颜色
        g2.fillRect(bx, by + 60, bw, bh); //绘制悔棋按钮
        g2.setFont(new Font("华文行楷", 10, 30)); //设置字体
        g2.setColor(Color.WHITE); //设置画笔颜色  
        g2.drawString("悔棋", 615, 245); //绘制字符

        //认输按钮
        g2.setColor(Color.GRAY); //设置画笔颜色
        g2.fillRect(bx, by + 120, bw, bh); //绘制认输按钮
        g2.setFont(new Font("华文行楷", 10, 30)); //设置字体
        g2.setColor(Color.WHITE); //设置画笔颜色
        g2.drawString("认输", 615, 305); //绘制字符

        //游戏信息栏
        g2.setColor(Color.getHSBColor(30, (float) 0.10, (float) 0.90)); //设置画笔颜色
        g2.fillRect(550, 350, 200, 150); //绘制游戏状态区域
        g2.setColor(Color.black); //设置画笔颜色
        g2.setFont(new Font("黑体", 10, 20)); //设置字体
        g2.drawString("游戏信息", 610, 380); //绘制字符
        g2.drawString(go, 610, 410); //绘制字符
        g2.drawString("作者:晓时谷雨", 560, 440); //绘制字符
        g2.drawString("联系方式:", 560, 465); //绘制字符
        g2.drawString("qq 717535996", 560, 490); //绘制字符


        g2.setColor(Color.BLACK); //设置画笔颜色

        //绘制棋盘格线
        for (int x = 0; x <= qw; x += 35) {
            g2.drawLine(qx, x + qy, qw + qx, x + qy); //绘制一条横线
            g2.drawLine(x + qx, qy, x + qx, qh + qy); //绘制一条竖线
        }

        //绘制标注点
        for (int i = 3; i <= 11; i += 4) {
            for (int y = 3; y <= 11; y += 4) {
                g2.fillOval(35 * i + qx - 3, 35 * y + qy - 3, 6, 6); //绘制实心圆
            }
        }


        //绘制棋子
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                if (SaveGame[i][j] == 1) //黑子
                {
                    int sx = i * 35 + qx;
                    int sy = j * 35 + qy;
                    g2.setColor(Color.BLACK);
                    g2.fillOval(sx - 13, sy - 13, 26, 26); //绘制实心圆
                    hq++;
                }
                if (SaveGame[i][j] == 2) //白子
                {
                    int sx = i * 35 + qx;
                    int sy = j * 35 + qy;
                    g2.setColor(Color.WHITE);
                    g2.fillOval(sx - 13, sy - 13, 26, 26); //绘制实心圆
                    g2.setColor(Color.BLACK);
                    g2.drawOval(sx - 13, sy - 13, 26, 26); //绘制空心圆
                    bq++;
                }
            }
        }
        g.drawImage(bi, 0, 0, this);


//        g.drawRect(20, 20, 20, 20);//绘制空心矩形
    }


    //---------------------------------------------------------------------------------------------------------------------
    //判断输赢
    private boolean WinLose() {
        boolean flag = false; //输赢
        int count = 1; //相连数
        int color = SaveGame[x][y]; //记录棋子颜色

        //判断横向棋子是否相连
        int i = 1; //迭代数
        while (color == SaveGame[x + i][y]) {
            count++;
            i++;
        }

        i = 1; //迭代数
        while (color == SaveGame[x - i][y]) {
            count++;
            i++;
        }
        if (count >= 5) {
            flag = true;
        }


        //判断纵向棋子是否相连
        count = 1;
        i = 1; //迭代数
        while (color == SaveGame[x][y + i]) {
            count++;
            i++;
        }

        i = 1; //迭代数
        while (color == SaveGame[x][y - i]) {
            count++;
            i++;
        }
        if (count >= 5) {
            flag = true;
        }


        //判断斜向棋子是否相连(左上右下)
        count = 1;
        i = 1; //迭代数
        while (color == SaveGame[x - i][y - i]) {
            count++;
            i++;
        }

        i = 1; //迭代数
        while (color == SaveGame[x + i][y + i]) {
            count++;
            i++;
        }
        if (count >= 5) {
            flag = true;
        }


        //判断斜向棋子是否相连(左下右上)
        count = 1;
        i = 1; //迭代数
        while (color == SaveGame[x + i][y - i]) {
            count++;
            i++;
        }

        i = 1; //迭代数
        while (color == SaveGame[x - i][y + i]) {
            count++;
            i++;
        }
        if (count >= 5) {
            flag = true;
        }

        return flag;
    }


    //---------------------------------------------------------------------------------------------------------------------
    //初始化游戏
    public void Initialize() {
        //遍历并初始化数组
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                SaveGame[i][j] = 0;
            }
        }

        //黑子先行
        qc = 1;
        go = "轮到黑子";
    }


    //---------------------------------------------------------------------------------------------------------------------
    @Override //鼠标点击
    public void mouseClicked(MouseEvent e) {

    }

    @Override //鼠标按下
    public void mousePressed(MouseEvent e) {
        //判断是否已开始游戏
        if (canplay) {
            //获取鼠标点击位置
            x = e.getX();
            y = e.getY();

            ui.ps[ui.i] = p;
            //判断点击是否为棋盘内
            if (x > qx && x < qx + qw && y > qy && y < qy + qh) {
                //计算点击位置最近的点
                if ((x - qx) % 35 > 17) {
                    x = (x - qx) / 35 + 1;
                } else {
                    x = (x - qx) / 35;
                }
                if ((y - qy) % 35 > 17) {
                    y = (y - qy) / 35 + 1;
                } else {
                    y = (y - qy) / 35;
                }

                ui.ps[ui.i].listx = x;
                ui.ps[ui.i].listy = y;
                ui.i++;

                //判断当前位置有没有棋子
                if (SaveGame[x][y] == 0) {
                    SaveGame[x][y] = qc;
                    qn = 0;
                } else {
                    qn = 1;
                }

                //切换棋子
                if (qn == 0) {
                    if (qc == 1) {
                        qc = 2;
                        go = "轮到白子";
                    } else {
                        qc = 1;
                        go = "轮到黑子";
                    }
                }

                this.repaint(); //重新执行一次paint方法

//                弹出胜利对话框
                boolean wl = this.WinLose();
                if (wl) {
                    JOptionPane.showMessageDialog(this, "游戏结束," + (SaveGame[x][y] == 1 ? "黑方赢了" : "白方赢了")); //弹出提示对话框
                    canplay = false;
                }

                //弹出平局对话框
                if (bq + hq == 255) {
                    JOptionPane.showMessageDialog(this, "游戏结束,平局!"); //弹出提示对话框
                    canplay = false;
                }


//            System.out.println(1); //测试
            } else {
//            System.out.println(0); //测试
            }
        }


        //实现开始按钮
        //判断是否点击开始按钮
        if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by && e.getY() < by + bh) {
            //判断游戏是否开始
            if (!canplay) {
                //如果游戏结束,则开始游戏
                canplay = true;
                JOptionPane.showMessageDialog(this, "游戏开始");
                //初始化游戏
                Initialize();

                this.repaint(); //重新执行一次paint方法

            } else {
                //如果游戏进行中,则重新开始
                JOptionPane.showMessageDialog(this, "重新开始");
                //初始化游戏
                Initialize();

                this.repaint(); //重新执行一次paint方法

            }
        }


        //实现悔棋按钮
        //判断是否点击悔棋按钮
        if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by + 60 && e.getY() < by + 60 + bh) {
            //判断游戏是否开始
            if (canplay) {
                //遍历棋盘上是否有棋子
                int z = 0;
                for (int i = 0; i < 15; i++) {
                    for (int j = 0; j < 15; j++) {
                        if (SaveGame[i][j] != 0) {
                            z++;
                        }
                    }
                }
                //判断是否有棋子
                if (z != 0) {
                    int result = JOptionPane.showConfirmDialog(this, "确认要悔棋吗?");
                    if (result == 0) {
                        int x = ui.ps[ui.i - 1].listx;
                        int y = ui.ps[ui.i - 1].listy;

                        if (SaveGame[x][y] == 0){
                            JOptionPane.showMessageDialog(this, "已悔过一次棋了!");
                        }else{
                            if (SaveGame[x][y] == 1) {
                                qc = 1;
                                go = "轮到黑子";
                            } else if (SaveGame[x][y] == 2){
                                qc = 2;
                                go = "轮到白子";
                            }
                            SaveGame[x][y] = 0;
                            ui.i--;
                            this.repaint();
                        }

                    }
                } else {
                    JOptionPane.showMessageDialog(this, "棋盘上已无棋子");
                }

            } else {
                JOptionPane.showMessageDialog(this, "请先开始游戏");
            }
        }


        //实现认输按钮
        //判断是否点击认输按钮
        if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by + 120 && e.getY() < by + 120 + bh) {
            //判断游戏是否开始
            if (canplay) {
                //判断是谁认输
                if (qc == 1) {
                    JOptionPane.showMessageDialog(this, "黑方认输,白方获胜");
                    canplay = false;
                } else if (qc == 2) {
                    JOptionPane.showMessageDialog(this, "白方认输,黑方获胜");
                    canplay = false;
                }
            } else {
                JOptionPane.showMessageDialog(this, "请先开始游戏");
            }
        }


    }


    @Override//鼠标抬起
    public void mouseReleased(MouseEvent e) {

    }

    @Override//鼠标进入
    public void mouseEntered(MouseEvent e) {

    }

    @Override//鼠标离开
    public void mouseExited(MouseEvent e) {

    }
}

  

MyJFrame_AI类代码

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class MyJFrame_AI extends JFrame implements MouseListener {
    int qx = 20, qy = 40, qw = 490, qh = 490; //棋盘位置、宽高
    int bw = 150, bh = 50, bx = 570, by = 150; //按钮宽高、位置
    int x = 0, y = 0; //保存棋子坐标
    int[][] SaveGame = new int[15][15]; //保存每个棋子
    int qc = 1;//记录白棋=2,黑棋=1
    int qn = 0;//判断棋子是否重复
    boolean canplay = true; //判断游戏是否开始和结束
    String go = "黑子先行"; //游戏信息
    int bq = 0, hq = 0;
    //人机对战增加参数
    int machine = 0;// 该数值为1代表电脑先行
    int[][] score = new int[15][15];// 权值表,保存每个位置的分数


    //---------------------------------------------------------------------------------------------------------------------
    //窗体
    public void myJFrame() {

        this.setTitle("五子棋(人机对战)"); //标题
        this.setSize(800, 550); //窗口大小
        this.setResizable(false); //窗口是否可以改变大小=否
        this.setDefaultCloseOperation(MyJFrame_AI.EXIT_ON_CLOSE); //窗口关闭方式为关闭窗口同时结束程序

        int width = Toolkit.getDefaultToolkit().getScreenSize().width; //获取屏幕宽度
        int height = Toolkit.getDefaultToolkit().getScreenSize().height; //获取屏幕高度
//        System.out.println("宽度:"+width);//测试
//        System.out.println("高度:"+height);//测试

        this.setLocation((width - 800) / 2, (height - 600) / 2); //设置窗口默认位置以屏幕居中

        this.addMouseListener(this);

        this.setVisible(true); //窗口是否显示=是

        first();
    }

    public static class Position {
        static int listx;
        static int listy;
    }

    public static class chessUI extends JPanel {
        public static Position[] ps = new Position[300];
        int i;
    }

    static chessUI ui = new chessUI();
    static Position p = new Position();


    //---------------------------------------------------------------------------------------------------------------------
    //覆写paint方法,绘制界面
    public void paint(Graphics g) {

        //双缓冲技术防止屏幕闪烁
        BufferedImage bi = new BufferedImage(800, 550, BufferedImage.TYPE_INT_ARGB);
        Graphics g2 = bi.createGraphics();

        //获取图片路径
        BufferedImage image = null;
        try {
            //获取项目文件夹路径
            File directory = new File("");
            //路径拼接
            image = ImageIO.read(new File(directory.getAbsolutePath() + "/tp/wzqbj.jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        g2.drawImage(image, 10, 10, this); //显示图片

        g2.setColor(Color.BLACK);//设置画笔颜色
        g2.setFont(new Font("华文行楷", 10, 50)); //设置字体
        g2.drawString("晓时五子棋", 525, 100); //绘制字符

        //棋盘
        g2.setColor(Color.getHSBColor(30, (float) 0.10, (float) 0.90)); //设置画笔颜色
        g2.fillRect(qx, qy, qw, qh); //绘制棋盘背景矩形

        //开始按钮
        g2.setColor(Color.WHITE); //设置画笔颜色
        g2.fillRect(bx, by, bw, bh); //绘制开始按钮
        g2.setFont(new Font("华文行楷", 10, 30)); //设置字体
        g2.setColor(Color.black); //设置画笔颜色
        g2.drawString("开始", 615, 185); //绘制字符

        //悔棋按钮
        g2.setColor(Color.LIGHT_GRAY); //设置画笔颜色
        g2.fillRect(bx, by + 60, bw, bh); //绘制悔棋按钮
        g2.setFont(new Font("华文行楷", 10, 30)); //设置字体
        g2.setColor(Color.WHITE); //设置画笔颜色  
        g2.drawString("悔棋", 615, 245); //绘制字符

        //认输按钮
        g2.setColor(Color.GRAY); //设置画笔颜色
        g2.fillRect(bx, by + 120, bw, bh); //绘制认输按钮
        g2.setFont(new Font("华文行楷", 10, 30)); //设置字体
        g2.setColor(Color.WHITE); //设置画笔颜色
        g2.drawString("认输", 615, 305); //绘制字符

        //游戏信息栏
        g2.setColor(Color.getHSBColor(30, (float) 0.10, (float) 0.90)); //设置画笔颜色
        g2.fillRect(550, 350, 200, 150); //绘制游戏状态区域
        g2.setColor(Color.black); //设置画笔颜色
        g2.setFont(new Font("黑体", 10, 20)); //设置字体
        g2.drawString("游戏信息", 610, 380); //绘制字符
        g2.drawString(go, 610, 410); //绘制字符
        g2.drawString("作者:晓时谷雨", 560, 440); //绘制字符
        g2.drawString("联系方式:", 560, 465); //绘制字符
        g2.drawString("qq 717535996", 560, 490); //绘制字符


        g2.setColor(Color.BLACK); //设置画笔颜色

        //绘制棋盘格线
        for (int x = 0; x <= qw; x += 35) {
            g2.drawLine(qx, x + qy, qw + qx, x + qy); //绘制一条横线
            g2.drawLine(x + qx, qy, x + qx, qh + qy); //绘制一条竖线
        }

        //绘制标注点
        for (int i = 3; i <= 11; i += 4) {
            for (int y = 3; y <= 11; y += 4) {
                g2.fillOval(35 * i + qx - 3, 35 * y + qy - 3, 6, 6); //绘制实心圆
            }
        }


        //绘制棋子
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                if (SaveGame[i][j] == 1) //黑子
                {
                    int sx = i * 35 + qx;
                    int sy = j * 35 + qy;
                    g2.setColor(Color.BLACK);
                    g2.fillOval(sx - 13, sy - 13, 26, 26); //绘制实心圆
                    hq++;
                }
                if (SaveGame[i][j] == 2) //白子
                {
                    int sx = i * 35 + qx;
                    int sy = j * 35 + qy;
                    g2.setColor(Color.WHITE);
                    g2.fillOval(sx - 13, sy - 13, 26, 26); //绘制实心圆
                    g2.setColor(Color.BLACK);
                    g2.drawOval(sx - 13, sy - 13, 26, 26); //绘制空心圆
                    bq++;
                }
            }
        }
        g.drawImage(bi, 0, 0, this);


//        g.drawRect(20, 20, 20, 20);//绘制空心矩形
    }


    //---------------------------------------------------------------------------------------------------------------------
    //判断输赢
    private boolean WinLose() {
        boolean flag = false; //输赢
        int count = 1; //相连数
        int color = SaveGame[x][y]; //记录棋子颜色

        //判断横向棋子是否相连
        int i = 1; //迭代数
        while (color == SaveGame[x + i][y]) {
            count++;
            i++;
        }

        i = 1; //迭代数
        while (color == SaveGame[x - i][y]) {
            count++;
            i++;
        }
        if (count >= 5) {
            flag = true;
        }


        //判断纵向棋子是否相连
        count = 1;
        i = 1; //迭代数
        while (color == SaveGame[x][y + i]) {
            count++;
            i++;
        }

        i = 1; //迭代数
        if (y > 0) {
            while (color == SaveGame[x][y - i]) {
                count++;
                i++;
            }
        }
        if (count >= 5) {
            flag = true;
        }


        //判断斜向棋子是否相连(左上右下)
        count = 1;
        i = 1; //迭代数
        while (color == SaveGame[x - i][y - i]) {
            count++;
            i++;
        }

        i = 1; //迭代数
        while (color == SaveGame[x + i][y + i]) {
            count++;
            i++;
        }
        if (count >= 5) {
            flag = true;
        }


        //判断斜向棋子是否相连(左下右上)
        count = 1;
        i = 1; //迭代数
        while (color == SaveGame[x + i][y - i]) {
            count++;
            i++;
        }

        i = 1; //迭代数
        while (color == SaveGame[x - i][y + i]) {
            count++;
            i++;
        }
        if (count >= 5) {
            flag = true;
        }

        return flag;
    }


    //---------------------------------------------------------------------------------------------------------------------
    //初始化游戏
    public void Initialize() {
        //遍历并初始化棋子位置数组
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                SaveGame[i][j] = 0;
            }
        }
        //遍历并初始化权值数组
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                score[i][j] = 0;
            }
        }
        //黑子先行
        qc = 1;
        go = "轮到黑子";

        first();
    }

    /**
     * 判断谁先走
     */
    public void first() {
        Object[] objects = {"玩家先走", "电脑先走"};
        int a = JOptionPane.showOptionDialog(null, "请选择先行者", "请选择", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, objects, objects[0]);
        if (a == -1) {
            System.exit(0);
        }
        if (a == 1) {
            machine = 1;
        }
        if (a == 0) {
            machine = 0;
        }
        // 如果电脑先走,在中间位置下棋
        if (machine == 1) {
            SaveGame[7][7] = 1;
            qc = 2;
            go = "轮到白子";
            this.repaint();
        }
    }

    /**
     * 计算五元组分数
     */
    public int score(int blackNum, int whiteNum) {
        // 通过电脑是否先行判断电脑棋子颜色
        //  如果电脑执黑
        if (machine == 1) {
            // 如果五元组中两种棋子都有,分值为0
            if (blackNum > 0 && whiteNum > 0) {
                return 0;
            }
            // 都没有,分值为7
            if (blackNum == 0 && whiteNum == 0) {
                return 7;
            }
            // 判断其中白棋数量计算分数
            if (blackNum == 1) {
                return 35;
            }
            if (blackNum == 2) {
                return 800;
            }
            if (blackNum == 3) {
                return 15000;
            }
            if (blackNum == 4) {
                return 800000;
            }
            // 判断其中白棋数量计算分数
            if (whiteNum == 1) {
                return 15;
            }
            if (whiteNum == 2) {
                return 400;
            }
            if (whiteNum == 3) {
                return 1800;
            }
            if (whiteNum == 4) {
                return 100000;
            }
            // 如果改五元组白棋数量为0
//            if (whiteNum == 0) {
//                // 判断其中黑棋数量计算分数
//                if (blackNum == 0) {
//                    score = 7;
//                }
//                if (blackNum == 1) {
//                    score = 35;
//                }
//                if (blackNum == 2) {
//                    score = 800;
//                }
//                if (blackNum == 3) {
//                    score = 15000;
//                }
//                if (blackNum == 4) {
//                    score = 800000;
//                }
//            }
//            // 如果改五元组黑棋数量为0
//            if (blackNum == 0) {
//                // 判断其中白棋数量计算分数
//                if (whiteNum == 0) {
//                    score = 7;
//                }
//                if (whiteNum == 1) {
//                    score = 15;
//                }
//                if (whiteNum == 2) {
//                    score = 400;
//                }
//                if (whiteNum == 3) {
//                    score = 1800;
//                }
//                if (whiteNum == 4) {
//                    score = 100000;
//                }
//            }
        }
        // 如果电脑执白
        if (machine == 0) {
            // 如果五元组中两种棋子都有,分值为0
            if (blackNum > 0 && whiteNum > 0) {
                return 0;
            }
            // 都没有,分值为7
            if (blackNum == 0 && whiteNum == 0) {
                return 7;
            }
            // 判断其中白棋数量计算分数
            if (blackNum == 1) {
                return 15;
            }
            if (blackNum == 2) {
                return 400;
            }
            if (blackNum == 3) {
                return 1800;
            }
            if (blackNum == 4) {
                return 100000;
            }
            // 判断其中白棋数量计算分数
            if (whiteNum == 1) {
                return 35;
            }
            if (whiteNum == 2) {
                return 800;
            }
            if (whiteNum == 3) {
                return 15000;
            }
            if (whiteNum == 4) {
                return 800000;
            }
//            // 如果改五元组白棋数量为0
//            if (whiteNum == 0) {
//                // 判断其中黑棋数量计算分数
//                if (blackNum == 0) {
//                    score = 7;
//                }
//                if (blackNum == 1) {
//                    score = 15;
//                }
//                if (blackNum == 2) {
//                    score = 400;
//                }
//                if (blackNum == 3) {
//                    score = 1800;
//                }
//                if (blackNum == 4) {
//                    score = 100000;
//                }
//            }
//            // 如果改五元组黑棋数量为0
//            if (blackNum == 0) {
//                // 判断其中白棋数量计算分数
//                if (whiteNum == 0) {
//                    score = 7;
//                }
//                if (whiteNum == 1) {
//                    score = 35;
//                }
//                if (whiteNum == 2) {
//                    score = 800;
//                }
//                if (whiteNum == 3) {
//                    score = 15000;
//                }
//                if (whiteNum == 4) {
//                    score = 800000;
//                }
//            }
        }
        return -1;
    }

    /**
     * 判断人机最佳下棋位置
     */
    public void machineGo(int pieces) {

        int blackNum = 0;
        int whiteNum = 0;
        // 横向
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 11; j++) {
                int k = j;
                while (k < j + 5) {
                    if (SaveGame[i][k] == 1) {
                        blackNum++;
                    } else if (SaveGame[i][k] == 2) {
                        whiteNum++;
                    }
                    k++;
                }
                // 给五元组每个没有落子的位置添加分数
                for (k = j; k < j + 5; k++) {
                    if (score[i][k] == 0) {
                        score[i][k] += score(blackNum, whiteNum);
                    }
                }
                // 将上次值归零,以便下次计算
                blackNum = 0;
                whiteNum = 0;
            }
        }
        // 纵向
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 11; j++) {
                int k = j;
                while (k < j + 5) {
                    if (SaveGame[k][i] == 1) {
                        blackNum++;
                    } else if (SaveGame[k][i] == 2) {
                        whiteNum++;
                    }
                    k++;
                }
                // 给五元组每个没有落子的位置添加分数
                for (k = j; k < j + 5; k++) {
                    score[k][i] += score(blackNum, whiteNum);
                }
                // 将上次值归零,以便下次计算
                blackNum = 0;
                whiteNum = 0;
            }
        }
        //右上左下,上部分
        for (int i = 14; i >= 4; i--) {
            for (int k = i, j = 0; j < 15 && k >= 0; j++, k--) {
                int m = k;
                int n = j;
                while (m > k - 5 && k - 5 >= -1) {
                    if (SaveGame[m][n] == 1) {
                        blackNum++;
                    } else if (SaveGame[m][n] == 2) {
                        whiteNum++;
                    }
                    m--;
                    n++;
                }
                // 斜向判断时,可能无法构成五元组,进行判断对其忽略
                if (m == k - 5) {
                    for (m = k, n = j; m > k - 5; m--, n++) {
                        score[m][n] += score(blackNum, whiteNum);
                    }
                }
                // 将上次值归零,以便下次计算
                blackNum = 0;
                whiteNum = 0;
            }
        }
        //右上左下,下部分
        for (int i = 1; i < 15; i++) {
            for (int k = i, j = 14; j >= 0 && k < 15; j--, k++) {
                int m = k;
                int n = j;
                while (m < k + 5 && k + 5 <= 15) {
                    if (SaveGame[n][m] == 1) {
                        blackNum++;
                    } else if (SaveGame[n][m] == 2) {
                        whiteNum++;
                    }
                    m++;
                    n--;
                }
                // 斜向判断时,可能无法构成五元组,进行判断对其忽略
                if (m == k + 5) {
                    for (m = k, n = j; m < k + 5; m++, n--) {
                        score[n][m] += score(blackNum, whiteNum);
                    }
                }
                // 将上次值归零,以便下次计算
                blackNum = 0;
                whiteNum = 0;
            }
        }
        // 左上右下,上部分
        for (int i = 0; i < 11; i++) {
            for (int k = i, j = 0; j < 15 && k < 15; j++, k++) {
                int m = k;
                int n = j;
                while (m < k + 5 && k + 5 <= 15) {
                    if (SaveGame[m][n] == 1) {
                        blackNum++;
                    } else if (SaveGame[m][n] == 2) {
                        whiteNum++;
                    }
                    m++;
                    n++;
                }
                // 斜向判断时,可能无法构成五元组,进行判断对其忽略
                if (m == k + 5) {
                    //为该五元组的每个位置添加分数
                    for (m = k, n = j; m < k + 5; m++, n++) {
                        score[m][n] += score(blackNum, whiteNum);
                    }
                }
                // 将上次值归零,以便下次计算
                blackNum = 0;
                whiteNum = 0;
            }
        }
        // 左上右下,下部分
        for (int i = 1; i < 11; i++) {
            for (int k = i, j = 0; j < 15 && k < 15; j++, k++) {
                int m = k;
                int n = j;
                while (m < k + 5 && k + 5 <= 15) {
                    if (SaveGame[n][m] == 1) {
                        blackNum++;
                    } else if (SaveGame[n][m] == 2) {
                        whiteNum++;
                    }
                    m++;
                    n++;
                }
                // 斜向判断时,可能无法构成五元组,进行判断对其忽略
                if (m == k + 5) {
                    //为该五元组的每个位置添加分数
                    for (m = k, n = j; m < k + 5; m++, n++) {
                        score[n][m] += score(blackNum, whiteNum);
                    }
                }
                // 将上次值归零,以便下次计算
                blackNum = 0;
                whiteNum = 0;
            }
        }
        int maxScore = 0;
        // 从没有落子的位置,找到分数最大的
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                if (SaveGame[i][j] == 0 && score[i][j] > maxScore) {
                    x = i;
                    y = j;
                    maxScore = score[i][j];
                }
            }
        }
        SaveGame[x][y] = pieces;

        ui.ps[ui.i].listx = x;
        ui.ps[ui.i].listy = y;
        ui.i++;

        this.repaint(); //重新执行一次paint方法

        // 弹出胜利对话框
        boolean wl = this.WinLose();
        if (wl) {
            JOptionPane.showMessageDialog(this, "游戏结束," + (SaveGame[x][y] == 1 ? "黑方赢了" : "白方赢了")); //弹出提示对话框
            canplay = false;
        }

        //弹出平局对话框
        if (bq + hq == 255) {
            JOptionPane.showMessageDialog(this, "游戏结束,平局!"); //弹出提示对话框
            canplay = false;
        }
    }

    //---------------------------------------------------------------------------------------------------------------------
    @Override //鼠标点击
    public void mouseClicked(MouseEvent e) {

    }

    @Override //鼠标按下
    public void mousePressed(MouseEvent e) {
        //判断是否已开始游戏
        if (canplay) {
            //获取鼠标点击位置
            x = e.getX();
            y = e.getY();

            ui.ps[ui.i] = p;
            //判断点击是否为棋盘内
            if (x > qx && x < qx + qw && y > qy && y < qy + qh) {
                //计算点击位置最近的点
                if ((x - qx) % 35 > 17) {
                    x = (x - qx) / 35 + 1;
                } else {
                    x = (x - qx) / 35;
                }
                if ((y - qy) % 35 > 17) {
                    y = (y - qy) / 35 + 1;
                } else {
                    y = (y - qy) / 35;
                }

                ui.ps[ui.i].listx = x;
                ui.ps[ui.i].listy = y;
                ui.i++;

                //判断当前位置有没有棋子
                if (SaveGame[x][y] == 0) {
                    SaveGame[x][y] = qc;
                    qn = 0;
                } else {
                    qn = 1;
                }

                //切换棋子
                if (qn == 0) {
                    if (qc == 1) {
                        qc = 2;
                        go = "轮到白子";
                    } else {
                        qc = 1;
                        go = "轮到黑子";
                    }
                }

                this.repaint(); //重新执行一次paint方法

//                弹出胜利对话框
                boolean wl = this.WinLose();
                if (wl) {
                    JOptionPane.showMessageDialog(this, "游戏结束," + (SaveGame[x][y] == 1 ? "黑方赢了" : "白方赢了")); //弹出提示对话框
                    canplay = false;
                }

                //弹出平局对话框
                if (bq + hq == 255) {
                    JOptionPane.showMessageDialog(this, "游戏结束,平局!"); //弹出提示对话框
                    canplay = false;
                }

//            System.out.println(1); //测试
            }
        }


        //实现开始按钮
        //判断是否点击开始按钮
        if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by && e.getY() < by + bh) {
            //判断游戏是否开始
            if (!canplay) {
                //如果游戏结束,则开始游戏
                canplay = true;
                JOptionPane.showMessageDialog(this, "游戏开始");
                //初始化游戏
                Initialize();

                this.repaint(); //重新执行一次paint方法

            } else {
                //如果游戏进行中,则重新开始
                JOptionPane.showMessageDialog(this, "重新开始");
                //初始化游戏
                Initialize();

                this.repaint(); //重新执行一次paint方法

            }
        }


        //实现悔棋按钮
        //判断是否点击悔棋按钮
        if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by + 60 && e.getY() < by + 60 + bh) {
            //判断游戏是否开始
            if (canplay) {
                //遍历棋盘上是否有棋子
                int z = 0;
                for (int i = 0; i < 15; i++) {
                    for (int j = 0; j < 15; j++) {
                        if (SaveGame[i][j] != 0) {
                            z++;
                        }
                    }
                }
                //判断是否有棋子
                if (z != 0) {
                    int result = JOptionPane.showConfirmDialog(this, "确认要悔棋吗?");
                    if (result == 0) {
                        int x = ui.ps[ui.i - 1].listx;
                        int y = ui.ps[ui.i - 1].listy;

                        if (SaveGame[x][y] == 0) {
                            JOptionPane.showMessageDialog(this, "已悔过一次棋了!");
                        } else {
                            if (SaveGame[x][y] == 1) {
                                qc = 1;
                                go = "轮到黑子";
                            } else if (SaveGame[x][y] == 2) {
                                qc = 2;
                                go = "轮到白子";
                            }
                            SaveGame[x][y] = 0;
                            ui.i--;
                            this.repaint();
                        }

                    }
                } else {
                    JOptionPane.showMessageDialog(this, "棋盘上已无棋子");
                }

            } else {
                JOptionPane.showMessageDialog(this, "请先开始游戏");
            }
        }


        //实现认输按钮
        //判断是否点击认输按钮
        if (e.getX() > bx && e.getX() < bx + bw && e.getY() > by + 120 && e.getY() < by + 120 + bh) {
            //判断游戏是否开始
            if (canplay) {
                //判断是谁认输
                if (qc == 1) {
                    JOptionPane.showMessageDialog(this, "黑方认输,白方获胜");
                    canplay = false;
                } else if (qc == 2) {
                    JOptionPane.showMessageDialog(this, "白方认输,黑方获胜");
                    canplay = false;
                }
            } else {
                JOptionPane.showMessageDialog(this, "请先开始游戏");
            }
        }


    }


    @Override//鼠标抬起
    public void mouseReleased(MouseEvent e) {
        //如果电脑先行,就也代表电脑执黑子,否则反之。在相应回合时让电脑做出反应
        if (machine == 1) {
            if (qc == 1) {
                machineGo(qc);
                qc = 2;
                go = "轮到白子";
            }
        } else {
            if (qc == 2) {
                machineGo(qc);
                qc = 1;
                go = "轮到黑子";
            }
        }
    }

    @Override//鼠标进入
    public void mouseEntered(MouseEvent e) {

    }

    @Override//鼠标离开
    public void mouseExited(MouseEvent e) {

    }
}

  

结束语

  原来的MyJFrame类里的代码没有改变,依然是人人对战;MyJFrame_AI类是在MyJFrame类的基础上修改为人机对战。
  博主测试的比较匆忙,只玩了一遍,没有发现BUG,大家在游玩过程中如果发现BUG,欢迎私信。
  往期文章可以翻阅我的主页,我一直坚持“分享知识”的原则,免费透明的将全部代码公开展示,如果帮到了你,请顺手点个赞吧(#.#)。

更新

2022-02-04
  不放心,又测试了一晚上BUG,果然有问题:
1.修复了悔棋时只能撤回电脑棋子的BUG
2.修复了在特定情况下,电脑方或玩家方胜利没有反应的BUG
3.优化了电脑的权值计算,但还是不太聪明的样子