【Java GUI】人机对弈五子棋

news2025/1/16 20:18:32

在学校的Java课程中,我们被分配了一项有趣的任务:开发一款能够实现人机对弈的五子棋游戏。为了更好地理解Java GUI的运用,并与大家分享学习心得,我将整个开发过程记录在这篇博客中。欢迎大家阅读并提供宝贵的意见和建议!"

python版五子棋(讲解的更详细) 

1.绘制棋盘

1.定义myPanel类。

myPanel相当于画板。

myPanel要继承 JPanel类,并要覆盖父类的paint方法,在paint方法里面写负责绘画的代码


public class myPanel extends JPanel {
    static final int start = 6;
    @Override
    public void paint(Graphics g)
    {
        //调用父类的paint初始化画笔
        super.paint(g);
       //绘制背景
        DrawBackground(g);
        //绘制外边框
        DrawBorder(g);
        //绘制棋盘
        DrawChessBoard(g);

    }
    public void DrawBackground(Graphics g)
    {    //绘制背景
        g.setColor(new Color(211, 152, 91));
        g.fillRect(0, 0, 620,620);

    }
    public void DrawBorder(Graphics g)
    {
        //绘制外边框
        g.setColor(Color.BLACK);
        g.fillRect(5,5,610,5);
        g.fillRect(610,5,5,610);
        g.fillRect(5,610,610,5);
        g.fillRect(5,5,5,610);
    }

    public void DrawChessBoard(Graphics g)
    {
        g.setColor(Color.BLACK);
        //画横线
        for (int i = 0; i < 19; i++) {
            g.drawLine(6+i*32,6,6+i*32,614);
        }
        //画竖线
        for (int i = 0; i < 19; i++) {
            g.drawLine(6,6+i*32,614,6+i*32);
        }

    }
    //画棋子
    public void DrawChess(Graphics g,int x,int y,int  type){
        switch (type){
            case 1:
                g.setColor(Color.BLACK);
                break;
            case 2:
                g.setColor(Color.WHITE);
        }
        g.fillOval(x*32+start,y*32+start,30,30);
        
    }
   

}
2.定义myFrame类。

myFrame相当于窗口,画板要放在窗口里。

myFram要继承 JFram类,在初始化函数设置窗口参数


public class MyFrame extends JFrame {
    myPanel mp  = null;
    public MyFrame() {
        mp = new myPanel();
        this.setTitle("五子棋");
        this.setSize(620, 620);
        //添加画板
        this.add(mp);
        //点击窗口叉叉退出程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    static public void main(String[] args) {
        MyFrame mf = new MyFrame();
    }
}

2.核心功能

1.实现下棋功能

 1.定义相关变量

    //偏移量
    static final int IndexOffset = -10;
    static final int ChessOffset = -10;
    //黑子下棋标记
    static boolean black = true;
    boolean gameIsOver = false;

    int chess[][]=new int[19][19];

2.添加事件监听

myPanel实现 MouseListener接口

重写mouseClicked方法

    @Override
    public void mouseClicked(MouseEvent e) {
        //计算棋子坐标
        //# 0表示空棋
        //# 1表示黑棋
        //# 2表示白棋

        int x = (e.getX() - IndexOffset) / 32;
        int y = (e.getY() - 32 - IndexOffset) / 32;
        System.out.println(y);
        chess[x][y] = 1;
        this.repaint();

    }

myFrame添加事件监听

    public MyFrame() {
        mp = new myPanel();
        this.setTitle("五子棋");
        this.setSize(620, 620);
        //添加画板
        this.add(mp);
        //点击窗口叉叉退出程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.addMouseListener(mp);
        this.setVisible(true);
    }
2.实现自动下棋

1.按照优先级从高到低枚举出所有情况


//# 0表示空棋
//# 1表示黑棋
//# 2表示白棋
//# 3表示下棋的位置


  

    private static final int[][] cdata = {

            {3, 1, 1, 1, 1}, {1, 3, 1, 1, 1}, {1, 1, 3, 1, 1}, {1, 1, 1, 3, 1}, {1, 1, 1, 1, 3},

            {2, 2, 3, 2, 2}, {2, 2, 2, 3, 2}, {2, 3, 2, 2, 2}, {3, 2, 2, 2, 2}, {2, 2, 2, 2, 3},

            {3, 1, 1, 1, 0}, {1, 1, 1, 3, 0}, {1, 1, 3, 1, 0}, {1, 3, 1, 1, 0},

            {3, 2, 2, 2, 0}, {2, 3, 2, 2, 0}, {2, 2, 3, 2, 0}, {2, 2, 2, 3, 0},

            {1, 1, 3, 3, 0}, {3, 1, 1, 0, 0}, {0, 1, 3, 1, 0},

            {3, 2, 2, 0, 0}, {2, 2, 3, 0, 0}, {1, 3, 1, 0, 0},

            {3, 1, 0, 0, 0}, {1, 3, 0, 0, 0}

    };

2.选出最佳下棋位置 

    public Point getBestPoint() {
        //记录最低分(分值越低,优先级越高)
        int score = 100;
        //最佳位置
        Point point = new Point(0, 0);
        //每次都要遍历四个方向 左下 下 右下 右
        int[] dx = {-1, 0, 1, 1};
        int[] dy = {1, 1, 1, 0};
        for (int i = 0; i < 19; i++) {

            for (int j = 0; j < 19; j++) {
                for (int k = 0; k < 4; k++) {
                    int cnt = 0;
                    for (int[] e : cdata) {
                        int m;
                        int x = i;
                        int y = j;
                        int bestX = 0;
                        int bestY = 0;
                        for (m = 0; m < 5; m++) {
                            if (e[m] == 3 && chess[x][y] == 0) {
                                bestX = x;
                                bestY = y;
                            } else {
                                if (chess[x][y] != e[m]) {
                                    break;
                                }
                            }
                            x += dx[k];
                            y += dy[k];
                            if (x < 0 || x >= 19 || y < 0 || y >= 19) {
                                break;
                            }

                        }
                        if (m == 5) {
                            if (cnt < score) {
                                score = cnt;
                                point.x = bestX;
                                point.y = bestY;
                            }
                            break;
                        }
                        cnt++;
                    }
                }

            }
        }
        if (score < 100) {
            return point;
        } else {
            int x = (int) (Math.random() * 19);
            int y = (int) (Math.random() * 19);
            while (chess[x][y] != 0) {
                x = (int) (Math.random() * 19);
                y = (int) (Math.random() * 19);
            }
            return new Point(x, y);
        }

    }
3.判断游戏是否结束

遍历棋盘

   public boolean check() {
        //每次都要遍历四个方向 左下 下 右下 右
        int[] dx = {-1, 0, 1, 1};
        int[] dy = {1, 1, 1, 0};
        for (int i = 0; i < 19; i++) {
            for (int j = 0; j < 19; j++) {
                for (int k = 0; k < 4; k++) {
                    int x = i;
                    int y = j;
                    int m;
                    boolean flag = true;
                    for (m = 0; m < 4; m++) {
                        int tx = x + dx[k];
                        int ty = y + dy[k];
                        if (tx < 0 || tx > 19 || ty < 0 || ty > 19) {
                            flag = false;
                            break;
                        }
                        if (chess[x][y] != chess[x + dx[k]][y + dy[k]]) {
                            flag = false;
                            break;
                        } else if (chess[x][y] == 0) {
                            flag = false;
                            break;
                        }
                        x = tx;
                        y = ty;
                    }
                    if (flag) {
                        gameIsOver = true;
                        return true;
                    }

                }
            }
        }
        return false;
    }
4.事件循环
   @Override
    public void paint(Graphics g) {
        //调用父类的paint初始化画笔
        super.paint(g);
        //绘制背景
        DrawBackground(g);
        //绘制外边框
        DrawBorder(g);
        //绘制棋盘
        DrawChessBoard(g);
        DrawChess(g);
        //开始游戏

            if (!gameIsOver)
                game();

        //游戏结束
        if (check()) {
            gameOver(g);
        }

    }

完整代码 

myPanel

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

/**
 * 
 *
 * @author yuwei
 * @date 23:29 2024/4/23
 */
public class myPanel extends JPanel implements MouseListener {
    //偏移量
    static final int IndexOffset = -10;
    static final int ChessOffset = -10;
    //黑子下棋标记
    static boolean black = true;
    boolean gameIsOver = false;

//# 0表示空棋
//# 1表示黑棋
//# 2表示白棋
//# 3表示下棋的位置


    private static final int[][] cdata = {

            {3, 1, 1, 1, 1}, {1, 3, 1, 1, 1}, {1, 1, 3, 1, 1}, {1, 1, 1, 3, 1}, {1, 1, 1, 1, 3},

            {2, 2, 3, 2, 2}, {2, 2, 2, 3, 2}, {2, 3, 2, 2, 2}, {3, 2, 2, 2, 2}, {2, 2, 2, 2, 3},

            {3, 1, 1, 1, 0}, {1, 1, 1, 3, 0}, {1, 1, 3, 1, 0}, {1, 3, 1, 1, 0},

            {3, 2, 2, 2, 0}, {2, 3, 2, 2, 0}, {2, 2, 3, 2, 0}, {2, 2, 2, 3, 0},

            {1, 1, 3, 3, 0}, {3, 1, 1, 0, 0}, {0, 1, 3, 1, 0},

            {3, 2, 2, 0, 0}, {2, 2, 3, 0, 0}, {1, 3, 1, 0, 0},

            {3, 1, 0, 0, 0}, {1, 3, 0, 0, 0}

    };
    int chess[][] = new int[20][20];

    @Override
    public void paint(Graphics g) {
        //调用父类的paint初始化画笔
        super.paint(g);
        //绘制背景
        DrawBackground(g);
        //绘制外边框
        DrawBorder(g);
        //绘制棋盘
        DrawChessBoard(g);
        DrawChess(g);
        //开始游戏

            if (!gameIsOver)
                game();

        //游戏结束
        if (check()) {
            gameOver(g);
        }

    }

    public void gameOver(Graphics g) {
        Font font = new Font("Arial", Font.BOLD, 24);
        g.setColor(Color.red);
        g.setFont(font);
        g.drawString("游戏结束", 270, 270);
    }

    public void DrawBackground(Graphics g) {    //绘制背景
        g.setColor(new Color(211, 152, 91));
        g.fillRect(0, 0, 620, 620);

    }

    public void DrawBorder(Graphics g) {
        //绘制外边框
        g.setColor(Color.BLACK);
        g.fillRect(5, 5, 610, 5);
        g.fillRect(610, 5, 5, 610);
        g.fillRect(5, 610, 610, 5);
        g.fillRect(5, 5, 5, 610);
    }

    public void DrawChessBoard(Graphics g) {
        g.setColor(Color.BLACK);
        //画横线
        for (int i = 0; i < 19; i++) {
            g.drawLine(6 + i * 32, 6, 6 + i * 32, 614);
        }
        //画竖线
        for (int i = 0; i < 19; i++) {
            g.drawLine(6, 6 + i * 32, 614, 6 + i * 32);
        }

    }

    //画棋子
    public void DrawChess(Graphics g) {
        for (int i = 0; i < 19; i++) {
            for (int j = 0; j < 19; j++) {
                if (chess[i][j] == 1) {
                    g.setColor(Color.BLACK);
                } else if (chess[i][j] == 2) {
                    g.setColor(Color.WHITE);
                } else {
                    continue;
                }
                g.fillOval(i * 32 + ChessOffset, j * 32 + ChessOffset, 30, 30);
            }
        }


    }

    public Point getBestPoint() {
        //记录最低分(分值越低,优先级越高)
        int score = 100;
        //最佳位置
        Point point = new Point(0, 0);
        //每次都要遍历四个方向 左下 下 右下 右
        int[] dx = {-1, 0, 1, 1};
        int[] dy = {1, 1, 1, 0};
        for (int i = 0; i < 19; i++) {

            for (int j = 0; j < 19; j++) {
                for (int k = 0; k < 4; k++) {
                    int cnt = 0;
                    for (int[] e : cdata) {
                        int m;
                        int x = i;
                        int y = j;
                        int bestX = 0;
                        int bestY = 0;
                        for (m = 0; m < 5; m++) {
                            if (e[m] == 3 && chess[x][y] == 0) {
                                bestX = x;
                                bestY = y;
                            } else {
                                if (chess[x][y] != e[m]) {
                                    break;
                                }
                            }
                            x += dx[k];
                            y += dy[k];
                            if (x < 0 || x >= 19 || y < 0 || y >= 19) {
                                break;
                            }

                        }
                        if (m == 5) {
                            if (cnt < score) {
                                score = cnt;
                                point.x = bestX;
                                point.y = bestY;
                            }
                            break;
                        }
                        cnt++;
                    }
                }

            }
        }
        if (score < 100) {
            return point;
        } else {
            int x = (int) (Math.random() * 19);
            int y = (int) (Math.random() * 19);
            while (chess[x][y] != 0) {
                x = (int) (Math.random() * 19);
                y = (int) (Math.random() * 19);
            }
            return new Point(x, y);
        }

    }

    public boolean check() {
        //每次都要遍历四个方向 左下 下 右下 右
        int[] dx = {-1, 0, 1, 1};
        int[] dy = {1, 1, 1, 0};
        for (int i = 0; i < 19; i++) {
            for (int j = 0; j < 19; j++) {
                for (int k = 0; k < 4; k++) {
                    int x = i;
                    int y = j;
                    int m;
                    boolean flag = true;
                    for (m = 0; m < 4; m++) {
                        int tx = x + dx[k];
                        int ty = y + dy[k];
                        if (tx < 0 || tx > 19 || ty < 0 || ty > 19) {
                            flag = false;
                            break;
                        }
                        if (chess[x][y] != chess[x + dx[k]][y + dy[k]]) {
                            flag = false;
                            break;
                        } else if (chess[x][y] == 0) {
                            flag = false;
                            break;
                        }
                        x = tx;
                        y = ty;
                    }
                    if (flag) {
                        gameIsOver = true;
                        return true;
                    }

                }
            }
        }
        return false;
    }

    public void game()  {

        if (check()) {
            return;
        }
        if (black) {
            Point point = getBestPoint();
            chess[point.x][point.y] = 1;
            black = false;
            this.repaint();
        }


    }


    @Override
    public void mouseClicked(MouseEvent e) {
        //计算棋子坐标
        //# 0表示空棋
        //# 1表示黑棋
        //# 2表示白棋
        if (!black&&!gameIsOver) {
            int x = (e.getX() - IndexOffset) / 32;
            int y = (e.getY() - 32 - IndexOffset) / 32;
            chess[x][y] = 2;
            black = true;
            this.repaint();

        }

    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }
}

myFrame

import javax.swing.*;

/**
 * 用户服务
 *
 * @author yuwei
 * @date 23:42 2024/4/23
 */
public class MyFrame extends JFrame {
    myPanel mp  = null;
    public MyFrame() {
        mp = new myPanel();
        this.setTitle("五子棋");
        this.setSize(620, 620);
        //添加画板
        this.add(mp);
        //点击窗口叉叉退出程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.addMouseListener(mp);
        this.setVisible(true);
    }

    static public void main(String[] args) {
        MyFrame mf = new MyFrame();
    }
}

感谢阅读,希望本文对你有所帮助 

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

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

相关文章

PSoc™62开发板之SPI显示屏

实验目的 使用PSoc62™开发板驱动OLED模块&#xff0c;显示字符串、中文、数字 实验准备 PSoc62™开发板SSD1309 OLED模块 模块电路 引脚对应关系如下&#xff0c;这次实验采用的是SPI的驱动方式&#xff0c;可以无视SDA、SCL的命名 开发板GPIOSSD1309A0P10.0CSA1P10.1DC…

锂电池SOH预测 | 基于CNN的锂电池SOH预测(附matlab完整源码)

锂电池SOH预测 锂电池SOH预测完整代码锂电池SOH预测 锂电池的SOH(状态健康度)预测是一项重要的任务,它可以帮助确定电池的健康状况和剩余寿命,从而优化电池的使用和维护策略。 SOH预测可以通过多种方法实现,其中一些常用的方法包括: 容量衰减法:通过监测电池的容量衰减…

Python脚本抢票【笔记】

Python脚本抢票【笔记】 前言版权推荐Python脚本抢票【Python】microsoft edge驱动器下载以及使用最后 前言 2024-4-17 18:19:15 以下内容源自《【笔记】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN日星月云 博客主页是ht…

Spring Web MVC入门(2)——请求

目录 一、传递单个参数 基础类型和包装类型的区别 1、基础类型 &#xff08;1&#xff09;不传参 &#xff08;2&#xff09;传字符串 2、包装类型 &#xff08;1&#xff09;不传参 &#xff08;2&#xff09;传字符串 3、小结 二、传递多个参数 三、传递对象 四、…

Fast-DetectGPT 无需训练的快速文本检测

本文提出了一种新的文本检测方法 ——Fast-DetectGPT&#xff0c;无需训练&#xff0c;直接使用开源小语言模型检测各种大语言模型&#xff0c;如GPT等生成的文本内容。 Fast-DetectGPT 将检测速度提高了 340 倍&#xff0c;将检测准确率相对提升了 75%&#xff0c;超过商用系…

Redis缓存问题:穿透,击穿,雪崩,双写一致性等

Redis缓存问题:穿透,击穿,雪崩,双写一致性等 在高并发场景下,数据库往往是最薄弱的环节,我们通常选择使用redis来进行缓存,以起到缓冲作用,来降低数据库的压力,但是一旦缓存出现问题,也会导致数据库瞬间压力过大甚至崩溃,从而导致整个系统崩溃.今天就聊聊常见的redis缓存问题.…

多路递归的一些算法题

前言 首先我想讲一下&#xff0c;我对多路递归的理解吧&#xff0c;我认为多路递归就是循环中套回调&#xff0c;对于循环有几次就是几叉树&#xff0c;就好比我们常用的二叉树的dfs(node.left) 和 dfs(node.right)等前中后序遍历&#xff0c;也就是for (int i 0; i < 2; …

AIGC - SD(中英文本生成图片) + PaddleHub/HuggingFace + stable-diffusion-webui

功能 stable-diffusion(文本生成图片)webui-win搭建&#xff08;开启api界面汉化&#xff09;PaddleHubHuggingFace: SD2&#xff0c;中文-alibaba/EasyNLP stable-diffusion-webui 下载与安装 环境相关下载 python&#xff08;文档推荐&#xff1a;Install Python 3.10.6 …

区块链技术与应用学习笔记(1-4节)——北大肖臻课程

目录 1. 区块链初识(课程简介&#xff09; 被过度炒作&#xff0c;落地应用有限&#xff1f; 下一代的价值互联网&#xff1f;世界上最慢的数据库&#xff1f; 2. BTC-密码学原理&#xff08;比特币&#xff09; 1)哈希 哈希函数特点 个人学习所得 2)签名 个人对于…

U-boot 21.10 启动流程梳理

目录 背景平台启动入口确认启动源码DuoS_SG2000_RISCVLubancat2_RK3568_ARM 初始化流程board_init_fboard_init_r 参考 背景 设备&#xff1a;MilkV Duo S 版本&#xff1a;U-boot 2021.10 编译命令 # Milkv-DuoS SD卡版本&#xff0c;对应[board]与[config]分别为&#xff1…

Leetcode_相交链表

✨✨所属专栏&#xff1a;LeetCode刷题专栏✨✨ ✨✨作者主页&#xff1a;嶔某✨✨ 题目&#xff1a; 题解&#xff1a; 看到这个题目首先我们要排除链表逆置的想法&#xff0c;如图、因为c1节点只有一个next指针&#xff0c;逆置后不可能同时指向a2和b3节点。 其次有的的同学…

24深圳杯AC题完整思路+可执行代码+参考论文!!!!

比赛题目的完整版思路可执行代码数据参考论文都会在第一时间更新上传的&#xff0c;大家可以参考我往期的资料&#xff0c;所有的资料数据以及到最后更新的参考论文都是一次付费后续免费的。注意&#xff1a;&#xff08;建议先下单占坑&#xff0c;因为随着后续我们更新资料数…

【AIGC调研系列】大型语言模型如何减少幻觉生成

在解读大型语言模型&#xff08;LLMs&#xff09;中的长格式事实性问题时&#xff0c;我们首先需要认识到这些模型在生成内容时可能会产生与既定事实不一致的情况&#xff0c;这种情况通常被称为“幻觉”[2][3]。这种现象不仅可能导致信息的误传&#xff0c;还可能对社会造成误…

新时代凌迟:考研

我不喜欢上班&#xff0c;但我很欣赏老板的品味&#xff0c;因为咱们公司竟然还在订阅报纸&#xff0c;而且只有一份&#xff0c;《中国青年报》。 这份报纸我最喜欢看的是“冰点周刊”专栏&#xff0c;因为这个栏目能让读者相信&#xff1a;报纸远远可以超越一天的生命。 昨天…

跨境代买淘宝系统,跨境代采系统,淘宝代购系统,淘宝代购集运系统,1688代采系统

淘宝代购系统是一种集成的电商平台服务&#xff0c;主要针对海外用户提供购买中国大陆商品的便利通道。以下是其核心功能与特点&#xff1a; 多语言支持&#xff1a;为了满足全球用户的需求&#xff0c;代购系统提供多语言界面&#xff0c;让不同国家和地区的用户都能方便地浏…

c++初阶——类和对象(下)

大家好&#xff0c;我是小锋&#xff0c;今天我们来学习我们类和对象的最后一个章节&#xff0c;我们本期的内容主要是类和对象的一些细节进行讲解 再谈构造函数 我们在初始化时有两种方式一种是函数体内初始化&#xff0c;一种是初始化列表 我们先来看看日期类的初始化 构造…

Web3技术解析:区块链在去中心化应用中的角色

引言 在过去几年中&#xff0c;Web3技术已经成为了互联网领域的一个热门话题。作为区块链技术的延伸&#xff0c;Web3不仅仅是数字货币的代名词&#xff0c;更是一个能够为各种应用提供去中心化解决方案的强大工具。本文将深入探讨区块链在Web3去中心化应用中的关键角色&#…

【考研数学】武忠祥考研课优缺点大盘点

虽然每年大家推荐的最多的是张宇和汤家凤&#xff0c;但是我强烈推荐武忠祥老师&#xff01; 武忠祥老师真宝藏老师&#xff0c;他讲课不像张宇老师那样段子频出&#xff0c;也不想汤家凤老师那样&#xff0c;武忠祥老师有自己的方法论&#xff0c;真的有点东西&#xff0c;武…

一周学会Django5 Python Web开发-Django5 ORM执行SQL语句

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计49条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

AI工具集:解锁智能新境界,一站式解决你的所有需求!

在这个信息爆炸的时代&#xff0c;我们每天都在与大量的数据和信息打交道。如何高效地处理这些信息&#xff0c;提高工作效率和生活品质&#xff0c;成为了我们亟待解决的问题。而AI工具集(AI-321.com)的出现&#xff0c;无疑为我们提供了一把解锁智能新境界的钥匙。 AI-321 | …