基于Java实现的数独游戏

Carewho

发布日期: 2020-01-01 14:51:09 浏览量: 410
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

一、本游戏背景介绍

相传数独源起于拉丁方阵(Latin Square),1970年代在美国发展,改名为数字拼图(Number Place),之后流传至日本并发扬光大,以数字智力游戏智力拼图游戏发表。在1984年一本游戏杂志《パズル通信ニコリ》正式把它命名为数独,意思是“在每一格只有一个数字”。拼图是九宫格(即3格宽×3格高)的正方形状,每一格又细分为一个九宫格。在每一个小九宫格中,分别填上1至9的数字,让整个大九宫格每一列、每一行的数字都不重复。 数独的玩法逻辑简单,数字排列方式千变万化,不少教育者认为数独是锻炼脑筋的好方法。

二、需求分析

2.1 数独游戏规则

  • 在9×9的大九宫格内,已给定若干数字,其他宫位留白,玩家需要自己按照逻辑推敲出剩下的空格里是什么数字

  • 必须满足的条件:每一行与每一列都有1到9的数字,每个小九宫格里也有1到9的数字,并且一个数字在每行、每列及每个小九宫格里只能出现一次,既不能重复也不能少

  • 每个数独游戏都可根据给定的数字为线索,推算解答出来

2.2 需求分析

按照数独的游戏规则:

  • 用计算机实现已知数独的求解

  • 数独根据用户设定的题目难度的随机出题

  • 用户能玩预设的经典的数独题目

  • 用户能自定义题目并求解

  • 用户能保存和读取游戏

三、实现

3.1 采用的数据结构

一维数组、二维数组以及十字链表。

3.2 实现的方法

3.2.1 二维数组

  1. // 用来处理相应的数据,即显示的数据
  2. private int[][] form1 = new int[20][20];
  3. // 用来辅助form1进行相关判断
  4. private int[][] form2 = new int[20][20];
  5. // 存储答案,用来检验答案
  6. private int[][] form3 = new int[20][20];
  7. // 用来储存form1 的数据,用于重新开始菜单
  8. private int[][] form4 = new int[20][20];

数组的下标都是从1开始的,数据空白处则初始化为0。之所以把数组范围设计为20*20,是为了程序的可读性,符合人的习惯思维。

  1. // 用来显示用户的输入界面数组的下标是从0开始的
  2. JButton[][] bords = new JButton[20][20];

3.2.2 一维数组

  1. // 副界面的9个按键
  2. JButton[] numbers = new JButton[9];

数组的下标是从0开始的。

3.2.3 十字链表

解题时用。

四、GUI界面设计介绍

构造菜单并添加监听器。

使用GridLayout将centrePanel面板分成9*9的格子,两个for循环各添加一个按键,并且设置每个按键属性,可通过监听器修改每个按键的背景、前景、字体。

使用BorderLayout将JFame布局分为四块,主窗口上边显示菜单栏bar,中间显示9*9的数独题目centrePanel,下面显示JLabel欢迎提示bottomPanel,右边显示游戏的时间。

副界面显示为3*3的按键,一个for循环各添加一个按键,并且设置每个按键属性,可通过监听器修改每个按键的背景、前景、字体,用来在主界面填入数字。

最主要的两个监听器,用来控制主窗口和副窗口之间的转换,不同模式下,监听器会有不同的动作设置字体,两个窗口切换时还添加了渐渐出现和消失动画。

frame 中的每个按键的监听器当点击按键时,先判断当前是否已经完成游戏,如果已经完成则按键不会有响应,如果没有完成则判断当前是否是用户自定义题目模式或正常游戏模式下是否已经有题目给出的数字,如果不是用户自定义题目模式且按键不是题目初始化时已经给出的数字则会调出副窗口,如果是用户自定义题目模式,判断k是否符合数独规则,若符合则显示为红色,提示可填写,若不符合数独规则,则显示为黑色,点击后窗口消失,但是主窗口中对应的位置不会改变,如果是和主窗口中的数字相同,则改变颜色为红,继续提示可点击。

subframe中的每个按键的监听器当点击时,先判断当前是否已经完成游戏,如果已经完成则按键不会有响应,如果没有完成则判断是否为用户自定义题目模式,如果是则再判断,如果为已经填过的数或者不符合数独游戏规则,那么将主窗口对应的位置清空,否则填入对应的黑色的数字。如果是非用户自定义题目模式,在主窗口题目的数字为黑色,填入相对应的数字为红色,点击的数字和主界面相同,那么主界面的数会清空。

时间控制的面板设计,在类TimeKeeper中,时间格式为 “00:00:00”,通过字符串实现,当小时为双位数时,将原数值转换为字符串,当小时为一位数时,在字符串前添加一个”0”,从而保证了字符串的长度始终保持一致。

五、测试

游戏运行时的界面

选择数字填入的副窗口

开始快速游戏

游戏的窗口显示游戏的名”SUDOKU”,在”Game”菜单的”Difficulty”中可以更改游戏的难度,共设3个级别的难度,分别为”easy”,”normal”,”hard”,默认级别为”normal”。

设置好难度后就可以开始游戏了,在”File”菜单中点击”QUICK PLAY”,将随机生成的本难度数独题目。

QUICK PLAY显示界面如下:

窗口的面板中出现了随机产生的题目,开始游戏并右边开始计时,用户能点击按键选择填入的数字。

填入数字,单击要填入的地方然后将会出现一个有九个数字的小窗口。单击数字即可填入,会有一个小窗口由小而大的显示出来,如点击左上角:

红色为提示当前位置中行、列、宫里没有的数字,黑色的按键点击后将不会改变填入的数值。

单击想填入的数字,比如1,此时填入数字的窗口将由大变小到消失。

为区分用户填入的数字和题目给出的数字,用户填入的数字为红色,题目给出的数字为黑色。其中已经填过的数字只需要在副窗口中再点击相同的数字就可以清除。

当游戏结束时会祝贺玩家,点击确定后时间暂停:

在”File”菜单中点击”PLAY AGAIN”,将清空本题目中填过的数据,重新开始。

开始闯关模式游戏:

在”Game”菜单的”Difficulty”中可以更改游戏的难度,共设3个级别的难度,分别为”easy”,”normal”,”hard”,默认级别为”normal”。

设置好难度后就可以开始游戏了,在”File”菜单中点击”PLAY GAME”。

将弹出以下对话框:

输入一个关卡,输入数字为1到9,如果填入空白,则提示:

如果为含有字母则会提示并回到主界面:

如果数字不符合范围,则需要继续重新填写,点右上角的标记可以退出对话框。

输入正确则会生成预先设定好的题目:

接下来和快速游戏相同。

用户录入题目

在”File”菜单中点击”DIYPuzzle”,点击后提示进入用户录入题目模式,按键可以点了,主要用于智能解题。

智能解题

在快速游戏时,在闯关模式游戏时,在自定义题目之后,在”Game”菜单中点击”Answer”,都会智能解题。

无解时给出提示:

唯一解是直接给出答案;多解时给出其中一个答案并提示:

游戏中途保存

在游戏中途,在”Game”菜单中点击”SAVE”,将自动保存游戏。

载入游戏存档

在游戏中途,在”Game”菜单中点击”LOAD”,将自动读取游戏存档。

关于游戏信息

在”About”菜单中点击”Info”,获取游戏的主要信息。

六、难点解决

在实验中当然了遇到了不少问题:

首先是那个9*9的按钮不能正确显示,只能看到一个,通过查看代码,用了比较久的时间,发现中心面板并没有加到frame上才出现这个问题,然后这个问题就解决了。

然后遇到的另外一个比较难纠错的问题,问题出在团队的合作上,开始快速游戏就会随机生成题目,这时问题来了,有时候会溢出,一开始以为是我界面这边的算法错了,于是就开始检查,删剩下主体部分,后来发现是另一个组员做的类写错了,由此可知,组员之间的交流是很重要的。

其次遇到个比较难解决的问题是游戏时间一直显示为0,不会自动加,TimeKeeper的类中的其中一个方法我写成了public void TimeKeeper(){},这个当然是不对的,我重新编写这个部分还是没发现到这个问题,最后在同学的帮助下解决了问题,应当改为public TimeKeeper(){},有返回值就不对了,void 和空是不一样的。

另一个比较难解决的问题是闯关模式选择关卡时的对话框。有种错误是一直输入不能关闭,因为没有把输入的值转换成正确的数据类型再判断导致死循环,增加个类型转换语句就可以解决问题了;有种错误是点击关闭的时候,总会提示NullPointerException,于是我在原本Exception-Handling的NumberFormatException基础上在添加个try-catch语句来排除这个错误,结果能够顺利关闭窗口了。

上传的附件 cloud_download 基于Java实现的数独游戏.7z ( 2.29mb, 5次下载 )
error_outline 下载需要12点积分

发送私信

人生没有彩排,每天都是现场直播

8
文章数
21
评论数
最近文章
eject