1、演示视频
基于Java Swing的猜数字小游戏
2、项目截图
三、设计说明
3.1 整体架构设计
项目采用单一类封装所有功能(GuessNumberGame),继承自Swing的JFrame类,遵循“界面与逻辑结合”的设计模式(适合小型桌面应用),主要分为以下模块:
- 组件初始化模块:通过
initComponents()方法初始化所有GUI组件(窗口、面板、输入框、按钮、文本域等),设置组件属性和布局。 - 游戏数据初始化模块:通过
initGame()方法初始化游戏核心数据(谜底、猜测次数、猜测历史集合、数字范围最大值)。 - 事件监听模块:通过
bindEvents()方法为按钮、输入框、下拉框绑定事件监听器,处理用户的交互操作。 - 业务逻辑处理模块:包含
handleSubmit()(处理提交猜测)、handleReset()(处理游戏重置)、setMaxNumberByDifficulty()(根据难度设置数字范围)、updateGuessRecord()(更新猜测历史显示)等方法,处理核心业务逻辑。
3.2 界面布局设计
界面采用Swing的边界布局(BorderLayout)和流式布局(FlowLayout)、网格布局(GridLayout)组合使用,分为三个主要区域:
- 顶部区域:包含难度选择下拉框和游戏提示标签,使用流式布局,居中显示。
- 中间区域:包含输入框和提交按钮,使用流式布局,居中显示。
- 底部区域:分为上下两部分,上部分包含提示标签和猜测历史滚动文本域(边界布局),下部分包含重置按钮(流式布局),整体使用网格布局。
3.3 数据结构设计
int targetNumber:存储随机生成的谜底数字。int guessCount:记录用户的猜测次数。List<Integer> guessNumbers:存储用户本次游戏的所有猜测数字,使用ArrayList实现,支持动态添加和遍历。int maxNumber:存储当前难度对应的数字范围最大值。
3.4 组件设计
| 组件类型 | 组件名称 | 功能描述 |
|---|---|---|
| JComboBox | difficultyComboBox | 难度等级选择下拉框,提供三个难度选项 |
| JTextField | inputField | 用户输入猜测数字的文本框 |
| JButton | submitButton | 提交用户猜测的按钮 |
| JButton | resetButton | 重置游戏的按钮 |
| JLabel | hintLabel | 显示游戏提示信息的标签 |
| JTextArea + JScrollPane | guessRecordTextArea | 显示猜测历史的文本域,包裹在滚动面板中 |
四、算法说明
4.1 随机数生成算法
使用Java内置的Random类生成指定范围的随机整数,核心代码逻辑:
- 步骤1:根据难度等级确定数字范围的最大值
maxNumber(如简单难度为50)。 - 步骤2:调用
Random.nextInt(maxNumber)生成0到maxNumber-1的随机整数。 - 步骤3:将生成的随机数加1,得到1到
maxNumber的随机整数(即谜底)。
该算法保证了随机数在指定范围内均匀分布,满足游戏的随机性要求。
4.2 猜测结果判断算法
核心逻辑为比较用户输入的数字与谜底的大小关系,步骤如下:
- 获取用户输入的文本内容,进行非空、格式、范围验证。
- 将验证通过的文本转换为整数
userInput。 - 比较
userInput与targetNumber:- 若
userInput > targetNumber:提示“猜大了”,并记录猜测次数。 - 若
userInput < targetNumber:提示“猜小了”,并记录猜测次数。 - 若
userInput == targetNumber:提示猜对了,显示猜测次数,并禁用相关组件。
- 若
4.3 猜测历史拼接算法
将guessNumbers集合中的数字拼接为字符串,显示在文本域中,核心逻辑:
- 判断集合是否为空,若为空则显示“你猜过的数字:无”。
- 若集合非空,使用
StringBuilder拼接字符串,开头为“你猜过的数字:”,后续依次添加集合中的数字,数字之间用中文逗号分隔。 - 遍历集合时,判断是否为最后一个元素,若不是则添加分隔符,避免末尾出现多余符号。
使用StringBuilder而非字符串拼接(+),提升了字符串拼接的效率,尤其在猜测次数较多时效果明显。
五、测试说明
5.1 测试环境
- 操作系统:Windows 10/11、macOS、Linux(兼容Java的操作系统均可)。
- JDK版本:JDK 8、JDK 11、JDK 17(测试验证兼容各版本)。
- 开发工具:IntelliJ IDEA 2023.1、Eclipse 2022-12。
5.2 测试用例
| 测试用例ID | 测试场景 | 测试步骤 | 预期结果 | 测试结果 |
|---|---|---|---|---|
| TC001 | 空输入提交 | 1. 打开游戏;2. 直接点击提交按钮 | 提示“请输入数字后再提交!”,输入框保持为空 | 通过 |
| TC002 | 非数字输入 | 1. 打开游戏;2. 输入“abc”并提交 | 提示“请输入有效的整数!”,输入框清空 | 通过 |
| TC003 | 超出范围输入(简单难度) | 1. 选择简单难度(1-50);2. 输入“51”并提交 | 提示“请输入1到50之间的数字!”,输入框清空 | 通过 |
| TC004 | 猜大了提示 | 1. 中等难度,谜底为50;2. 输入“60”并提交 | 提示“猜大了!你已经猜了1次”,输入框清空,历史记录添加60 | 通过 |
| TC005 | 猜小了提示 | 1. 中等难度,谜底为50;2. 输入“40”并提交 | 提示“猜小了!你已经猜了1次”,输入框清空,历史记录添加40 | 通过 |
| TC006 | 猜对数字 | 1. 中等难度,谜底为50;2. 输入“50”并提交 | 提示“恭喜你猜对了!谜底是50,你一共猜了N次”,输入框和提交按钮禁用 | 通过 |
| TC007 | 难度切换 | 1. 打开游戏,选择简单难度;2. 切换为困难难度 | 游戏重置,数字范围变为1-200,输入框和历史记录清空 | 通过 |
| TC008 | 重置游戏 | 1. 猜对数字后;2. 点击重置游戏按钮 | 游戏重置,所有组件恢复可用,输入框和历史记录清空 | 通过 |
| TC009 | 大量猜测记录 | 1. 连续输入20个不同数字并提交 | 历史记录文本域显示所有数字,出现滚动条,可滚动查看 | 通过 |
| TC010 | 回车键提交 | 1. 输入数字;2. 按回车键 | 与点击提交按钮效果一致,正常处理猜测逻辑 | 通过 |
5.3 测试结论
所有测试用例均通过验证,程序能够正确处理各种输入场景和用户操作,功能完整,交互体验良好,无明显bug和异常情况。
六、关键代码
6.1 组件初始化核心代码
/** * 初始化所有GUI组件 */ private void initComponents() { // 设置窗口属性 setTitle("猜数字小游戏"); setSize(550, 320); // 适配滚动面板的窗口大小 setLocationRelativeTo(null); // 窗口居中 setDefaultCloseOperation(EXIT_ON_CLOSE); setResizable(false); // 禁止调整窗口大小 // 创建主面板,使用边界布局 mainPanel = new JPanel(new BorderLayout(10, 10)); mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); // 顶部面板:难度选择 + 标题提示 JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0)); JLabel difficultyLabel = new JLabel("难度选择:"); // 初始化难度下拉框,默认选中中等 difficultyComboBox = new JComboBox<>(new String[]{"简单(1-50)", "中等(1-100)", "困难(1-200)"}); difficultyComboBox.setSelectedIndex(1); JLabel titleLabel = new JLabel("猜一个对应范围的整数:"); topPanel.add(difficultyLabel); topPanel.add(difficultyComboBox); topPanel.add(titleLabel); mainPanel.add(topPanel, BorderLayout.NORTH); // 中间面板:输入框和提交按钮 JPanel centerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0)); inputField = new JTextField(10); submitButton = new JButton("提交"); centerPanel.add(inputField); centerPanel.add(submitButton); mainPanel.add(centerPanel, BorderLayout.CENTER); // 底部面板:提示+历史记录 + 重置按钮 JPanel bottomPanel = new JPanel(new GridLayout(2, 1, 10, 10)); JPanel hintRecordPanel = new JPanel(new BorderLayout(10, 0)); hintLabel = new JLabel("请开始猜数字吧!", SwingConstants.CENTER); // 初始化猜测历史文本域,支持滚动和换行 guessRecordTextArea = new JTextArea(3, 30); guessRecordTextArea.setEditable(false); guessRecordTextArea.setLineWrap(true); guessRecordTextArea.setWrapStyleWord(true); guessRecordTextArea.setText("你猜过的数字:无"); JScrollPane scrollPane = new JScrollPane(guessRecordTextArea); scrollPane.setBorder(BorderFactory.createTitledBorder("猜测历史")); hintRecordPanel.add(hintLabel, BorderLayout.NORTH); hintRecordPanel.add(scrollPane, BorderLayout.CENTER); JPanel resetPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); resetButton = new JButton("重置游戏"); resetPanel.add(resetButton); bottomPanel.add(hintRecordPanel); bottomPanel.add(resetPanel); mainPanel.add(bottomPanel, BorderLayout.SOUTH); }6.2 提交猜测核心逻辑代码
/** * 处理提交猜数字的逻辑 */ private void handleSubmit() { // 获取输入内容并去除首尾空格 String inputText = inputField.getText().trim(); // 验证输入是否为空 if (inputText.isEmpty()) { hintLabel.setText("请输入数字后再提交!"); return; } int userInput; try { // 转换为整数,处理非数字输入异常 userInput = Integer.parseInt(inputText); } catch (NumberFormatException ex) { hintLabel.setText("请输入有效的整数!"); inputField.setText(""); return; } // 验证数字是否在指定范围内 if (userInput < 1 || userInput > maxNumber) { hintLabel.setText("请输入1到" + maxNumber + "之间的数字!"); inputField.setText(""); return; } // 猜测次数加1 guessCount++; // 添加到猜测历史集合 guessNumbers.add(userInput); // 更新历史记录显示 updateGuessRecord(); // 判断猜测结果 if (userInput > targetNumber) { hintLabel.setText("猜大了!你已经猜了" + guessCount + "次"); inputField.setText(""); } else if (userInput < targetNumber) { hintLabel.setText("猜小了!你已经猜了" + guessCount + "次"); inputField.setText(""); } else { // 猜对数字,显示结果并禁用相关组件 hintLabel.setText("恭喜你猜对了!谜底是" + targetNumber + ",你一共猜了" + guessCount + "次"); inputField.setEnabled(false); submitButton.setEnabled(false); difficultyComboBox.setEnabled(false); } // 输入框获得焦点,方便继续输入 inputField.requestFocus(); }6.3 猜测历史更新代码
/** * 更新猜测记录的界面显示(优化拼接逻辑,避免多余符号) */ private void updateGuessRecord() { if (guessNumbers.isEmpty()) { guessRecordTextArea.setText("你猜过的数字:无"); } else { // 使用StringBuilder高效拼接字符串 StringBuilder sb = new StringBuilder("你猜过的数字:"); for (int i = 0; i < guessNumbers.size(); i++) { sb.append(guessNumbers.get(i)); // 最后一个数字后不添加逗号 if (i != guessNumbers.size() - 1) { sb.append(","); } } guessRecordTextArea.setText(sb.toString()); } }6.4 难度等级处理代码
/** * 根据难度选择设置数字范围的最大值 */ private void setMaxNumberByDifficulty() { int selectedIndex = difficultyComboBox.getSelectedIndex(); switch (selectedIndex) { case 0: // 简单难度:1-50 maxNumber = 50; break; case 1: // 中等难度:1-100 maxNumber = 100; break; case 2: // 困难难度:1-200 maxNumber = 200; break; default: // 默认中等难度 maxNumber = 100; } }6.5 游戏重置代码
/** * 处理重置游戏的逻辑 */ private void handleReset() { // 重新初始化游戏数据 initGame(); // 清空输入框 inputField.setText(""); // 恢复组件功能 inputField.setEnabled(true); submitButton.setEnabled(true); difficultyComboBox.setEnabled(true); // 重置提示文字 hintLabel.setText("请开始猜数字吧!"); // 重置历史记录显示 guessRecordTextArea.setText("你猜过的数字:无"); // 输入框获得焦点 inputField.requestFocus(); }