简易五子棋

简介

使用Java实现简易五子棋

规则介绍

游戏使用一个标准的15×15方格的棋盘,双方分别用黑白两种颜色的棋子进行对战。黑子先行,双方轮流在空棋盘的交叉点上落子,每人一次只能落一子。游戏的目标是让自己的五颗棋子连成一线,这条线可以是横线、竖线、对角线或斜线。如果一方的五颗棋子按照上述规则连成一线,这一方就获胜并结束游戏。

(1)对局双方各执一色棋子。
(2)空棋盘开局。
(3)黑先、白后,交替下子,每次只能下一子。
(4)棋子下在棋盘的空白点上,棋子下定后不得移动或拿走。
(5)黑方的第一枚棋子必须下在天元点上,即中心交叉点"

功能设计

  • 重新开始
    用户操作【重新开始】功能,弹窗询问是否确定重新开始,如果是则将所有数据重新初始化,否则什么也不做。
  • 悔棋
    用户操作【悔棋】功能,恢复上一步的操作,如果已无上一步操作或者游戏结束,不允许悔棋并弹窗提示。
  • 退出游戏
    用户操作【退出游戏】功能,关闭该应用程序。
  • 帮助
    菜单栏添加玩法提示,引导用户使用。
  • 坐标校准
    由于棋子需下在网格线上,交叉点的坐标很小,故鼠标很难精准点击在符合的坐标上,那么就需要对用户点击的坐标进行校准,将其坐标校准为最贴近的符合坐标。
  • 坐标可行性及输赢判断
    用户落子时,判断该坐标是否可用(是否已有棋子),如果不可行,弹窗提示,否则,判断输赢并且刷新页面绘制棋子。如果某一方获胜,提示游戏结束,禁止继续落下棋子。
  • 输赢判断算法
    以落下棋子坐标出发,向上下、左右、左上右下、右上左下四个方向延伸,朝一个方向至多延伸五次,若有同色棋子,则计数器加一,最终判断计数器是否大于等于5,如果是则获得胜利。

实现

附上如下实现代码

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Objects;
import java.util.Stack;public class Gobang extends JPanel {boolean op = false; //true-white false blackboolean win = false;static final int SCREEN_WIDTH = 700;static final int SCREEN_HEIGHT = 700;static final int UNIT_SIZE = 50;static final int GAME_UNITS = SCREEN_WIDTH / UNIT_SIZE;boolean[][] black;boolean[][] white;Graphics g;Point checkPoint;Stack<Point> opStack;MouseListener mouseListener;JMenuBar menuBar;Gobang() {this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));this.setFocusable(true);this.addKeyListener(new MyKeyAdapter());init();}/*** 初始化网格*/public void initCheckerboard() {if (Objects.isNull(g)) {return;}g.setColor(Color.BLACK);for (int i = 0; i < SCREEN_WIDTH; i += UNIT_SIZE) {g.drawLine(i, 0, i, SCREEN_HEIGHT);}for (int i = 0; i < SCREEN_HEIGHT; i += UNIT_SIZE) {g.drawLine(0, i, SCREEN_WIDTH, i);}}public void initMenu() {menuBar = new JMenuBar();JMenu menu = new JMenu("菜单");JMenuItem restart;(restart = new JMenuItem("重新开始")).addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {int res = JOptionPane.showConfirmDialog(null, "请确定要重新开始吗?", "", JOptionPane.OK_CANCEL_OPTION);if (res == 0) {init();}}});menu.add(restart);JMenuItem regretChess;(regretChess = new JMenuItem("悔棋")).addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {regretChess();}});menu.add(regretChess);JMenuItem exit;(exit = new JMenuItem("退出游戏")).addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {System.exit(0);}});menu.add(exit);menuBar.add(menu);JMenu helpMenu = new JMenu("帮助");JMenuItem playWay;(playWay = new JMenuItem("玩法")).addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JOptionPane.showMessageDialog(null, "游戏使用一个标准的15×15方格的棋盘,双方分别用黑白两种颜色的棋子进行对战。\n" +"黑子先行,双方轮流在空棋盘的交叉点上落子,每人一次只能落一子。\n" +"游戏的目标是让自己的五颗棋子连成一线,这条线可以是横线、竖线、对角线或斜线。\n" +"如果一方的五颗棋子按照上述规则连成一线,这一方就获胜并结束游戏。\n" +"(1)对局双方各执一色棋子。\n" +"(2)空棋盘开局。\n" +"(3)黑先、白后,交替下子,每次只能下一子。\n" +"(4)棋子下在棋盘的空白点上,棋子下定后不得移动或拿走。\n" +"(5)黑方的第一枚棋子必须下在天元点上,即中心交叉点");}});helpMenu.add(playWay);JMenuItem about;(about = new JMenuItem("关于")).addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JOptionPane.showMessageDialog(null, "无聊时候花一点时间写着玩的");}});helpMenu.add(about);menuBar.add(helpMenu);}/*** 游戏数据初始化*/public void init() {initCheckerboard();initMenu();black = new boolean[GAME_UNITS + 1][GAME_UNITS + 1];white = new boolean[GAME_UNITS + 1][GAME_UNITS + 1];op = false;win = false;checkPoint = null;opStack = new Stack<>();super.addMouseListener(mouseListener = new MyMouseAdapter());repaint();}/*** 校准鼠标** @param x* @return*/public double calibration(double x) {if (x % UNIT_SIZE > UNIT_SIZE / 2) {x = ((int) x / UNIT_SIZE + 1) * UNIT_SIZE;} else {x = ((int) x / UNIT_SIZE) * UNIT_SIZE;}return x;}/*** 绘制棋子*/public void drawChessPieces() {String tip = null;if (Objects.nonNull(checkPoint)) {//存记录int x = (int) checkPoint.getX();int y = (int) checkPoint.getY();if (op) {white[x / UNIT_SIZE][y / UNIT_SIZE] = true;} else {black[x / UNIT_SIZE][y / UNIT_SIZE] = true;}tip = judge();op = !op;checkPoint = null;}for (int i = 0; i < black.length; i++) {for (int j = 0; j < black.length; j++) {if (black[i][j]) {g.setColor(Color.BLACK);g.fillOval(i * UNIT_SIZE - UNIT_SIZE / 2, j * UNIT_SIZE - UNIT_SIZE / 2, UNIT_SIZE, UNIT_SIZE);}}}for (int i = 0; i < white.length; i++) {for (int j = 0; j < white.length; j++) {if (white[i][j]) {g.setColor(Color.WHITE);g.fillOval(i * UNIT_SIZE - UNIT_SIZE / 2, j * UNIT_SIZE - UNIT_SIZE / 2, UNIT_SIZE, UNIT_SIZE);}}}if (win && Objects.nonNull(tip)) {g.setFont(new Font("Ink Free", Font.BOLD, 40));g.setColor(Color.RED);g.drawString(tip, (SCREEN_WIDTH - getFontMetrics(g.getFont()).stringWidth(tip)) / 2, SCREEN_HEIGHT / 2);super.removeMouseListener(mouseListener);}}public String judge() {String tip = op ? tip = "White Win!" : "Black Win!";boolean[][] opArr = op ? white : black;int x = (int) checkPoint.getX() / UNIT_SIZE;int y = (int) checkPoint.getY() / UNIT_SIZE;int tempX = x;int tempY = y;int count = 0;//判断横向while (x >= 0 && x > tempX - 5) {if (opArr[x][y]) {count++;x--;if (x >= 0) {continue;}}x = tempX + 1;break;}while (x <= GAME_UNITS && x < tempX + 5) {if (opArr[x][y]) {count++;x++;continue;}break;}if (count >= 5) {win = true;return tip;}//判断纵向x = tempX;y = tempY;count = 0;while (x >= 0 && y >= 0 && x <= GAME_UNITS && y <= GAME_UNITS&& y > tempY - 5) {if (opArr[x][y]) {count++;y--;if (y >= 0) {continue;}}y = tempY + 1;break;}while (x >= 0 && y >= 0 && x <= GAME_UNITS && y <= GAME_UNITS&& y < tempY + 5) {if (opArr[x][y]) {count++;y++;continue;}break;}if (count >= 5) {win = true;return tip;}//判断左斜向x = tempX;y = tempY;count = 0;while (x >= 0 && y >= 0 && x <= GAME_UNITS && y <= GAME_UNITS&& y > tempY - 5 && x > tempX - 5) {if (opArr[x][y]) {count++;x--;y--;if (x >= 0 && y >= 0) {continue;}}x = tempX + 1;y = tempY + 1;break;}while (x >= 0 && y >= 0 && x <= GAME_UNITS && y <= GAME_UNITS&& y < tempY + 5 && x < tempY + 5) {if (opArr[x][y]) {count++;y++;x++;continue;}break;}if (count >= 5) {win = true;return tip;}//判断右斜向x = tempX;y = tempY;count = 0;while (x >= 0 && y >= 0 && x <= GAME_UNITS && y <= GAME_UNITS&& y > tempY - 5 && x < tempX + 5) {if (opArr[x][y]) {count++;x++;y--;if (y >= 0 && x <= GAME_UNITS) {continue;}}x = tempX - 1;y = tempY + 1;break;}while (x >= 0 && y >= 0 && x <= GAME_UNITS && y <= GAME_UNITS&& y <= tempY + 5 && x >= tempX - 5) {if (opArr[x][y]) {count++;y++;x--;continue;}break;}if (count >= 5) {win = true;return tip;}return null;}public void regretChess() {if (win) {JOptionPane.showMessageDialog(null, "游戏结束无法悔棋!");return;}if (opStack.isEmpty()) {JOptionPane.showMessageDialog(null, "无效操作,已无上一步棋!");return;}Point point = opStack.pop();if (Objects.isNull(point)) {return;}if (op) {black[(int) point.getX() / UNIT_SIZE][(int) point.getY() / UNIT_SIZE] = false;} else {white[(int) point.getX() / UNIT_SIZE][(int) point.getY() / UNIT_SIZE] = false;}op = !op;repaint();}public void paintComponent(Graphics g) {super.paintComponent(g);this.g = g;initCheckerboard();drawChessPieces();}/*** 自定义鼠标适配器*/public class MyMouseAdapter extends MouseAdapter {@Overridepublic void mouseClicked(MouseEvent e) {super.mouseClicked(e);checkPoint = e.getPoint();System.out.println("点击坐标x:" + checkPoint.getX() + " y:" + checkPoint.getY());checkPoint.setLocation(calibration(checkPoint.getX()), calibration(checkPoint.getY()));System.out.println("校准坐标x:" + checkPoint.getX() + " y:" + checkPoint.getY());//去除无效点击if (black[(int) checkPoint.getX() / UNIT_SIZE][(int) checkPoint.getY() / UNIT_SIZE]|| white[(int) checkPoint.getX() / UNIT_SIZE][(int) checkPoint.getY() / UNIT_SIZE]) {JOptionPane.showMessageDialog(null, "无效操作,\n此处已有棋子!");return;}opStack.push(checkPoint);repaint();}}/*** 自定义按键适配器*/public class MyKeyAdapter extends KeyAdapter {public void keyPressed(KeyEvent e) {int keyCode = e.getKeyCode();if (KeyEvent.VK_1 == keyCode) {System.out.println("重新开始");init();}if (KeyEvent.VK_2 == keyCode) {System.out.println("悔棋");regretChess();}if (KeyEvent.VK_ESCAPE == keyCode) {System.out.println("退出游戏");System.exit(0);}}}public static void main(String[] args) {JFrame frame = new JFrame();frame.setTitle("五子棋");Gobang gobang = new Gobang();frame.setJMenuBar(gobang.menuBar);frame.add(gobang);frame.setResizable(false);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.pack();frame.setVisible(true);}}

效果展示

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024-06-08 Unity 编辑器开发之编辑器拓展9 —— EditorUtility

文章目录 1 准备工作2 提示窗口2.1 双键窗口2.2 三键窗口2.3 进度条窗口 3 文件面板3.1 存储文件3.2 选择文件夹3.3 打开文件3.4 打开文件夹 4 其他内容4.1 压缩纹理4.2 查找对象依赖项 1 准备工作 ​ 创建脚本 “Lesson38Window.cs” 脚本&#xff0c;并将其放在 Editor 文件…

01——生产监控平台——WPF

生产监控平台—— 一、介绍 VS2022 .net core(net6版本&#xff09; 1、文件夹&#xff1a;MVVM /静态资源&#xff08;图片、字体等&#xff09; 、用户空间、资源字典等。 2、图片资源库&#xff1a; https://www.iconfont.cn/ ; 1.资源字典Dictionary 1、…

5.数据仓库与数据挖掘期末复习

ETL的含义Extract 、 Transformation、Load。ODS的全称Operational Data Store。 DW全称 Data WarehourseDM全称是Data Mart数据仓库数据抽取时所用到技术是增量、全量、定时、调度STAGE层作用是提供业务系统数据文件的临时存储ODS层作用ods提供业务系统细节数据长期沉淀MID层…

Go TOKEN机制与跨域处理方式

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

【Python推导式秘籍】:一行代码的艺术,高效数据处理之道

文章目录 &#x1f68b;Python推导式&#x1f680;一、列表推导式&#x1f308;1. 了解推导式❤️2. 实践&#x1f4a5;3. 总结 &#x1f680;二、字典推导式&#x1f308;1. 了解字典推导式❤️2. 实践&#x1f4a5;3. 总结 &#x1f680;三、集合推导式&#x1f308;1. 了解集…

Sobel边缘检测

声明&#xff1a;学习过程中的知识总结&#xff0c;欢迎批评指正。 基本原理 灰度处理&#xff1a;边缘检测是基于图像亮度变化实现的&#xff0c;而图像的亮度信息通过灰度图像体现&#xff0c;因此需要把彩色图像转换成灰度图像。平滑处理&#xff1a;可以使用高斯滤波等滤…

SUSTAINABILITY,SCIESSCI双检期刊还能投吗?

本期&#xff0c;小编给大家介绍的是一本MDPI出版社旗下SCIE&SSCI双检“毕业神刊”——SUSTAINABILITY。据悉&#xff0c;早在2024年1月&#xff0c;ElSEVIER旗下的Scopus数据库已暂停收录检索期刊SUSTAINABILITY所发表文章&#xff0c;同时重新评估是否继续收录该期刊。随…

【数据结构】——常见排序

文章目录 一、 冒泡排序二、 选择排序三、插入排序四、 快速排序1. hoare版本2. 优化版本3. 前后指针法4. 非递归版本 五、 堆排序六、 希尔排序七、 归并排序1. 递归版本2. 非递归版本 八、 计数排序 在开始之前先准备一个交换数据的函数&#xff0c;排序会经常用到 //交换位置…

【博士每天一篇文献-算法】Progressive Neural Networks

阅读时间&#xff1a;2023-12-12 1 介绍 年份&#xff1a;2016 作者&#xff1a;Andrei A. Rusu,Neil Rabinowitz,Guillaume Desjardins,DeepMind 研究科学家,也都是EWC(Overcoming catastrophic forgetting in neural networks)算法的共同作者。 期刊&#xff1a; 未录用&am…

Nginx配置详细解释:(6)实现反向代理服务器,动静分离,负载均衡

目录 单台反向代理 proxy_pass后面加不加/的问题&#xff1a; 反向代理动静分离 反向代理负载均衡 作为代理服务器是当客户端访问代理服务器时&#xff0c;代理服务器代理客户端去访问真实web服务器。proxy_pass; 用来设置将客户端请求转发给的后端服务器的主机。 需要模块…

【Unity学习笔记】第十八 基于物理引擎的日月地系统简单实现

转载请注明出处: https://blog.csdn.net/weixin_44013533/article/details/139701843 作者&#xff1a;CSDN|Ringleader| 目录 目标数学理论资源准备数据准备代码实现Unity准备效果展示注意事项后记 目标 目标&#xff1a;利用Unity的物理引擎实现 “日地月三体系统” 。 效果…

UC Berkeley简介以及和Stanford的区别与联系

UC Berkeley Source: Google Map 中文版 UC Berkeley&#xff0c;全称University of California, Berkeley&#xff0c;是一所位于美国加利福尼亚州伯克利市的世界知名公立研究型大学。以下是关于UC Berkeley的详细介绍&#xff1a; 学术声誉和排名 学术声誉&#xff1a; U…

VisionOS的未来愿景:苹果VisionPro创业者的愿望清单

随着苹果公司在增强现实(AR)领域的不断探索,VisionPro作为其前沿产品,已经开始展现出改变我们与数字世界互动方式的潜力。作为一名VisionPro创业者,对未来VisionOS的更新充满了期待,并提出了一系列愿望清单,这些愿望不仅代表了个人的需求,也反映了用户社区对苹果AR生态的…

LaDM3IL:多实例学习用于免疫库分类

一个人的免疫组库由某一时间点的大量适应性免疫受体组成&#xff0c;代表了该个体的适应性免疫状态。免疫组库分类和相关受体识别有可能为新型疫苗的开发做出贡献。大量的实例对免疫组库分类提出了挑战&#xff0c;这可以表述为大规模多实例学习 (MMIL&#xff0c;Massive Mult…

自动驾驶场景下TCP协议参数优化调整案例分享

RTT 往返时间&#xff0c;从tcp协议栈决定发包&#xff0c;到收到回包的时间。 包含本地驱动&#xff0c;网卡硬件&#xff0c;网线&#xff0c;交换机&#xff0c;收包方处理的耗时。需注意如果开了delayed ack&#xff0c;协议栈未做特殊处理&#xff08;默认没做&#xff…

Photoshop中颜色与色调的调整

Photoshop中颜色与色调的调整 Photoshop中的颜色模式RGB模式灰度模式位图模式索引模式CMYK模式Lab模式 Photoshop中的颜色/色调调整命令颜色/色调调整命令的分类亮度/对比度调整命令色阶命令曲线命令曝光度命令自然饱和度命令色相/饱和度命令色彩平衡命令照片滤镜调整命令通道混…

LLVM Cpu0 新后端10

想好好熟悉一下llvm开发一个新后端都要干什么&#xff0c;于是参考了老师的系列文章&#xff1a; LLVM 后端实践笔记 代码在这里&#xff08;还没来得及准备&#xff0c;先用网盘暂存一下&#xff09;&#xff1a; 链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?…

[RL9] Rocky Linux 9.4 搭载 PG 16.1

副标题&#xff1a;Rocky Linux 9.4 升级实录&#xff0c;及 PG 16 相关内容 背景 Rocky Linux 9.4 (以下简称 RL) 于5月9日正式发布&#xff0c;本文记录了从 RL 9.3 升级到 9.4 的过程&#xff0c;以及升级前后的一些变化。 之前介绍过 RL 9 的相关内容&#xff0c;请戳&…

windows环境如何运行python/java后台服务器进程而不显示控制台窗口

1.通常我们在windows环境下使用Java或Python语言编写服务器程序&#xff0c;都希望他在后台运行&#xff0c;不要显示黑乎乎的控制台窗口&#xff1a; 2.有人写了一个bat文件: cd /d D:\lottery\server && python .\main.py 放到了开机自启动里&#xff0c;可是开机的…

MT2093 活动安排

贪心策略&#xff1a; 每次选择结束时间最早的活动 代码&#xff1a; #include <bits/stdc.h> using namespace std; const int N 5e5 10; int n; struct pp {int a, b; } p[N]; bool cmp(pp x, pp y) {return x.b < y.b; } int ans 0;int main() {cin >>…