【进阶篇-Day4:使用JAVA编写石头迷阵游戏】

目录
- 1、绘制界面
- 2、打乱石头方块
- 3、移动业务
- 4、游戏判定胜利
- 5、统计步数
- 6、重新游戏
- 7、完整代码:
1、绘制界面





上述思路是:使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。


代码如下:
package com.itheima.stonepuzzle;
import javax.swing.*;public class MainFrame extends JFrame {//data使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。int[][] data = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},{13, 14, 15, 0}};/*** 因为初始化窗体 和 绘制游戏界面,是在进入游戏就要执行的,* 因此只需要在new对象时执行即可,而new对象时构造方法一定会执行,* 所以在构造方法里调用即可*/public MainFrame(){//初始化窗体initFrame();//绘制游戏界面paintView();//设置窗体可见setVisible(true);}/*** 此方法用于窗体初始化*/public void initFrame(){
// JFrame jf = new JFrame(); --因为此类继承了JFrame,因此下面的方法可以直接调用//设置窗体大小setSize(514, 595);//设置窗体关闭模式:关闭窗口时,结束程序setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);//设置窗体标题setTitle("石头迷阵单机版V1.0");//设置窗体永在最上层setAlwaysOnTop(true);//设置窗体居中setLocationRelativeTo(null);//设置取消默认布局setLayout(null);}/*** 此方法用于绘制游戏的界面*/public void paintView(){for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {JLabel jl = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\" + data[i][j] + ".jpg"));//设置图片对象大小jl.setBounds(50 + 100 * j, 90 + 100 * i, 100, 100);//将图片对象塞进窗体getContentPane().add(jl);}}JLabel background = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\background.jpg"));//设置图片对象大小background.setBounds(26, 30, 450, 484);//将图片对象塞进窗体super.getContentPane().add(background);}
}
运行代码,绘制界面的结果如下:
2、打乱石头方块

代码:
/*** 初始化数据(随机打乱石头)*/
public void initData(){Random r = new Random();//1、遍历二维数组,获取每一个元素for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {//2、随机获取 (x坐, y坐标),找到其中一个数int x = r.nextInt(4);//x坐标int y = r.nextInt(4);//y坐标//3、将当前遍历到的元素,和随机获取到的元素做交换int temp = data[i][j];data[i][j] = data[x][y];data[x][y] = temp;}}
}
3、移动业务

/*** 按下键盘时出发事件* @param e*/@Overridepublic void keyPressed(KeyEvent e) {int keyCode = e.getKeyCode();move(keyCode);}/*** 此方法用于处理移动业务* @param keyCode*/private static void move(int keyCode) {if (keyCode == 37){System.out.println("左移动业务...");} else if (keyCode == 38) {System.out.println("上移动业务...");} else if (keyCode == 39) {System.out.println("右移动业务...");} else if (keyCode == 40) {System.out.println("下移动业务...");}}

移动石头块,实际上只需要交换二维数组中的两个数即可,然后再刷新就实现了移动业务。
做法:
//寻找0号元素的位置
lo:
for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {if (data[i][j] == 0) {row = i;col = j;break lo;}}
}
下面看下上、下、左、右移动:
注意:
/*** 此方法用于处理移动业务** @param keyCode*/
private void move(int keyCode) {int temp = data[row][col];//0号元素if (keyCode == 37 && col < 3) {System.out.println("左移动业务...");//左移动时,空白块和右边的数做交换data[row][col] = data[row][col + 1];data[row][col + 1] = temp;//记录0号元素的列坐标也要随之改变col++;} else if (keyCode == 38 && row < 3) {System.out.println("上移动业务...");//上移动时,空白块和下边的数做交换data[row][col] = data[row + 1][col];data[row + 1][col] = temp;//记录0号元素的列坐标也要随之改变row++;} else if (keyCode == 39 && col > 0) {System.out.println("右移动业务...");//右移动时,空白块和左边的数做交换data[row][col] = data[row][col - 1];data[row][col - 1] = temp;//记录0号元素的列坐标也要随之改变col--;} else if (keyCode == 40 && row > 0) {System.out.println("下移动业务...");//下移动时,空白块和上边的数做交换data[row][col] = data[row - 1][col];data[row - 1][col] = temp;//记录0号元素的列坐标也要随之改变row--;}else if (keyCode == 90){//z键//触发作弊器data = new int[][]{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},{13, 14, 15, 0}};}System.out.println(row + "," + col);
}
4、游戏判定胜利

/*** 判断游戏是否胜利* @return*/
public boolean victory(){for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {if(data[i][j] != win[i][j]){return false;}}}//运行到这里,表明游戏胜利了return true;}

5、统计步数

6、重新游戏

7、完整代码:
package com.itheima.stonepuzzle;public class Test {public static void main(String[] args) {//启动器new MainFrame();}
}
package com.itheima.stonepuzzle;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;public class MainFrame extends JFrame implements KeyListener {//data使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。int[][] data = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},{13, 14, 15, 0}};//胜利的结果int[][] win = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},{13, 14, 15, 0}};int row; //0号元素的行坐标int col; //0号元素的列坐标int count = 0;//记录操作的次数/*** 因为初始化窗体 和 绘制游戏界面,是在进入游戏就要执行的,* 因此只需要在new对象时执行即可,而new对象时构造方法一定会执行,* 所以在构造方法里调用即可*/public MainFrame() {//键盘监听://窗体对象.addKeyListener(KeyListener实现类对象)//this:当前对象,两个身份//1)窗体对象//2)KeyListener实现类对象this.addKeyListener(this);//初始化窗体initFrame();//初始化数据(随机打乱石头)initData();//绘制游戏界面paintView();//设置窗体可见setVisible(true);}/*** 此方法用于窗体初始化*/public void initFrame() {
// JFrame jf = new JFrame(); --因为此类继承了JFrame,因此下面的方法可以直接调用//设置窗体大小setSize(514, 595);//设置窗体关闭模式:关闭窗口时,结束程序setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);//设置窗体标题setTitle("石头迷阵单机版V1.0");//设置窗体永在最上层setAlwaysOnTop(true);//设置窗体居中setLocationRelativeTo(null);//设置取消默认布局setLayout(null);}/*** 初始化数据(随机打乱石头)*/public void initData() {Random r = new Random();//1、遍历二维数组,获取每一个元素for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {//2、随机获取 (x坐, y坐标),找到其中一个数int x = r.nextInt(4);//x坐标int y = r.nextInt(4);//y坐标//3、将当前遍历到的元素,和随机获取到的元素做交换int temp = data[i][j];data[i][j] = data[x][y];data[x][y] = temp;}}//寻找0号元素的位置lo:for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {if (data[i][j] == 0) {row = i;col = j;break lo;}}}}/*** 此方法用于绘制游戏的界面*/public void paintView() {//每次绘制之前,都清空之前绘制的界面super.getContentPane().removeAll();//加载胜利图片资源,添加到窗体中if (victory()){JLabel victoryJl = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\victory.jpg"));victoryJl.setBounds(124, 230, 266, 100);getContentPane().add(victoryJl);}//加载重新开始按钮if (count > 0){JButton jb = new JButton("重新开始");jb.setBounds(350, 10, 100, 20);jb.setFocusable(false);//取消焦点jb.addActionListener(new AbstractAction() {@Overridepublic void actionPerformed(ActionEvent e) {//统计步数归0count = 0;//重新初始化数据initData();//重新绘制游戏界面paintView();}});getContentPane().add(jb);}//加载记录步数组件JLabel stepJl = new JLabel("步数:" + count);stepJl.setBounds(50, 10, 100, 20);getContentPane().add(stepJl);for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {JLabel jl = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\" + data[i][j] + ".jpg"));//设置图片对象大小jl.setBounds(50 + 100 * j, 90 + 100 * i, 100, 100);//将图片对象塞进窗体getContentPane().add(jl);}}//加载背景图JLabel background = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\background.jpg"));//设置图片对象大小background.setBounds(26, 30, 450, 484);//将图片对象塞进窗体super.getContentPane().add(background);//刷新super.getContentPane().repaint();}/*** 按下键盘时出发事件** @param e*/@Overridepublic void keyPressed(KeyEvent e) {int keyCode = e.getKeyCode();move(keyCode);//判断是否胜利victory();//每次移动之后,都重新绘制游戏界面paintView();}/*** 此方法用于处理移动业务** @param keyCode*/private void move(int keyCode) {//如果游戏胜利了,则不允许操作if (victory()){return;}int temp = data[row][col];//0号元素if (keyCode == 37 && col < 3) {
// System.out.println("左移动业务...");//左移动时,空白块和右边的数做交换data[row][col] = data[row][col + 1];data[row][col + 1] = temp;//记录0号元素的列坐标也要随之改变col++;count++;} else if (keyCode == 38 && row < 3) {
// System.out.println("上移动业务...");//上移动时,空白块和下边的数做交换data[row][col] = data[row + 1][col];data[row + 1][col] = temp;//记录0号元素的列坐标也要随之改变row++;count++;} else if (keyCode == 39 && col > 0) {
// System.out.println("右移动业务...");//右移动时,空白块和左边的数做交换data[row][col] = data[row][col - 1];data[row][col - 1] = temp;//记录0号元素的列坐标也要随之改变col--;count++;} else if (keyCode == 40 && row > 0) {
// System.out.println("下移动业务...");//下移动时,空白块和上边的数做交换data[row][col] = data[row - 1][col];data[row - 1][col] = temp;//记录0号元素的列坐标也要随之改变row--;count++;}else if (keyCode == 90){//z键//触发作弊器data = new int[][]{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},{13, 14, 15, 0}};count++;}
// System.out.println(row + "," + col);}/*** 判断游戏是否胜利* @return*/public boolean victory(){for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {if(data[i][j] != win[i][j]){return false;}}}//运行到这里,表明游戏胜利了return true;}//-------------------------------------@Overridepublic void keyTyped(KeyEvent e) {}@Overridepublic void keyReleased(KeyEvent e) {}//-------------------------------------
}
界面图片已放在资源里,可下载。
相关文章:
【进阶篇-Day4:使用JAVA编写石头迷阵游戏】
目录 1、绘制界面2、打乱石头方块3、移动业务4、游戏判定胜利5、统计步数6、重新游戏7、完整代码: 1、绘制界面 上述思路是:使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。 代码如下: package com.itheima.s…...
探索 LLamaWorker:基于LLamaSharp的.NET本地大模型服务
LLamaWorker 是一个基于 LLamaSharp 项目开发的 HTTP API 服务器。它提供与 OpenAI 兼容的 API,使得开发者可以轻松地将大型语言模型(LLM)集成到自己的应用程序中。 1. 背景 在人工智能领域,大型语言模型(LLM…...
Qt开发 | Qt控件 | QTabWidget基本用法 | QListWidget应用详解 | QScrollArea应用详解
文章目录 一、QTabWidget基本用法二、QListWidget应用详解1.列表模式1.1 基本操作1.2 添加自定义item1.3 如何添加右键菜单1.4 QListWidget如何删除item 2.图标模式 三、QScrollArea应用详解 一、QTabWidget基本用法 QTabWidget 是 Qt 框架中的一个类,它提供了一个选…...
2023年 AI APT可持续攻击的调查研究报告
总览 随着网络技术的不断发展,网络安全威胁也日益严峻。高级持续性威胁(APT)攻击以其目标明确、手段多样、隐蔽性强等特点,成为网络安全领域的重要挑战。本文分析2023年当前 APT 攻击的主要特点、活跃组织、攻击趋势以及漏洞利用…...
Leetcode 102.目标和
给定一个正整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 ‘’ 或 ‘-’ ,然后串联起所有整数,可以构造一个 表达式 : 例如,nums [2, 1] ,可以在 2 之前添加 ‘’ ,在 1 之前添加 ‘-’ &…...
LLM AI工具和Delphi名称的起源
LLM AI工具和Delphi名称的起源 使用ChatGPT,直接或通过微软工具,以及其他基于llm的引擎。我很欣赏他们提供好的总结和比较的能力,并且还编写了一些样板代码。与此同时,当你问一些重要的问题时,你会得到一些令人惊讶的好…...
打破数据分析壁垒:SPSS复习必备(十一)
一、方差分析 方差分析的应用条件如下: (1)独立,各组数据相互独立,互不相关; (2)正态:即各组数据符合正态分布; (3)方差齐性&…...
【十六】【QT开发应用】Menu菜单,contextMenuEvent,setContextMenuPolicy,addAction
在 Qt 框架中,QMenu 类用于创建和管理菜单。菜单是用户界面的一部分,可以包含多个选项或动作,用户可以选择这些选项来执行特定的功能。菜单通常显示在菜单栏、上下文菜单(右键菜单)或工具栏中。 基本用法 创建菜单对象…...
华为DCN技术:M-LAG
M-LAG(Multichassis Link Aggregation Group)即跨设备链路聚合组,是一种实现跨设备链路聚合的机制。M-LAG主要应用于普通以太网络、VXLAN和IP网络的双归接入,可以起到负载分担或备份保护的作用。相较于另一种常见的可靠性接入技术…...
k8s持久化之emptyDir使用
目录 概述实践代码 概述 理解emptyDir使用,是后续k8s持久化进阶,高阶使用的基础。 实践 代码 详细说明在代码中 # 缓存数据,可以让多个容器共享数据 # 删除 Pod 时,emptyDir 数据同步消失 # 定义 initContainer -> 下载数据…...
Java露营基地预约小程序预约下单系统源码
轻松开启户外探险之旅 🌟 露营热潮来袭,你准备好了吗? 随着人们对户外生活的热爱日益增加,露营已成为许多人周末和假期的首选活动。但你是否曾因找不到合适的露营基地而烦恼?或是因为繁琐的预约流程而错失心仪的营地…...
七天速通javaSE:第四天 java方法
文章目录 前言一、什么是方法?二、方法的定义与调用1. 方法的定义2. 方法的调用3. 练习:定义比大小方法并调用 三、方法的重载四、递归五、可变参数拓展:命令行传递参数 前言 本章将学习java方法。 一、什么是方法? java方法是用…...
jupyter notebook的markdown语法不起作用
在这个界面编辑,发现markdown你编辑的是什么就是什么,不起作用,然而点一下: 右上角“Notebook转发”,就会单独跳出一个jupyter notebook的界面,此时就会奏效:...
Redis 学习笔记(2)
目录 1 Redis的持久化1.1 RDB持久化方案1.2 AOF持久化方案 2 Redis架构2.1 主从复制架构2.2 哨兵集群设计2.3 哨兵集群设计 3 Redis事务机制4 Redis过期策略与内存淘汰机制4.1 过期策略4.2 内存淘汰机制 5 Redis高频面试题4.1 缓存穿透4.2 缓存击穿4.3 缓存雪崩 1 Redis的持久化…...
快慢指针:删除有序数组中的重复项
题目链接:. - 力扣(LeetCode) 思路好想,代码实现不好想 class Solution {public int removeDuplicates(int[] nums) {int fast 1,slow 1;while(fast < nums.length){if(nums[fast] ! nums[fast-1]){nums[slow] nums[fast]…...
用户登录错误次数太多锁定账号
当用户登录验证码错误次数太多时,需要限制用户在10分钟之内不能再次登录。 限制方案: 1.通过Redis ZSet key可以设置为用户名,value可以设置为UUID,score设置为当前时间戳 每次用户登录时,通过 rangeByScore 查询对…...
tedsign vue3 web-端框架中封装一个验证码组件 以及对应node 接口逻辑说明
一个这样的组件 我直接上代码了 <template><t-loading size"small" :loading"loading" show-overlay><div class"container" click"refresh"><div v-if"svg" class"svg" v-html"svg&…...
探索Scala并发编程之巅:高效并行处理的艺术
标题:探索Scala并发编程之巅:高效并行处理的艺术 引言 在现代软件开发中,随着多核处理器的普及,编写能够充分利用硬件能力的并发程序变得至关重要。Scala,这门结合了面向对象和函数式编程特性的语言,提供…...
AudioLM: 音频生成的革命性模型
AudioLM: 音频生成的革命性模型 AudioLM是一种革命性的音频生成模型,它结合了深度学习和自然语言处理的先进技术,能够生成高质量、逼真的音频内容。本文将探讨AudioLM的基本原理、工作机制、应用场景以及对音频生成领域的影响和未来发展方向。 一、Aud…...
C++ Vector的模拟实现
vector的介绍 1. vector是表示可变大小数组的序列容器。 2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...









