数独游戏.docx
- 文档编号:23924365
- 上传时间:2023-05-22
- 格式:DOCX
- 页数:41
- 大小:29.32KB
数独游戏.docx
《数独游戏.docx》由会员分享,可在线阅读,更多相关《数独游戏.docx(41页珍藏版)》请在冰豆网上搜索。
数独游戏
数独游戏
益智类游戏是一种比较流行的游戏,其画面都比较简单,很少有复杂的游戏特效,但是通常用到人工智能的算法来控制游戏的难度。
而算法的优化是开发该类游戏的难点。
这类游戏游戏主要包括棋牌类游戏和智力测试类游戏,例如麻将,扫雷、五子棋、扑克牌等。
数独就是益智游戏的一种,玩法简单单数字的排列方式千变万化,很多人认为数独是练头脑的绝佳方式。
本章通过讲解数独游戏在java平台的设计与实现,使读者了解此类游戏的开发过程,掌握实用的开发技巧,学会此类游戏的开发。
1游戏的背景及功能概述
本文在整体上对数独游戏进行了简单的介绍,使读者了解数独游戏的发展,知道什么是数独游戏,以及该游戏的玩法。
1.1背景概述
数独的前身为“九宫格”,最早起源于中国。
但当时的算法比现在的更为复杂,要求纵向、横向、斜向上的三数之和等于15,而不只是数字的不能重复。
儒家典籍《易经》中的“九宫图”也是来源于此。
到了18世纪末,瑞士数学家莱昂哈德·欧拉又发明了一种叫做“拉丁方块”的游戏,之后不久,美国的一家数学逻辑游戏杂志开始刊登这类游戏,使此类游戏得到良好的发展,之后又在日本得到广泛的传播。
2004年,第一个“数独”游戏被刊登上了英国《泰晤士报》的封面,此时开始数独游戏才真正为世界所知晓。
由于此类游戏操作简单,不需要特定的语言基础,也不需要进行数字运算且可玩性高、锻炼思维、开发大脑,所以很快风靡全球。
之后由其衍生的游戏也越来越多,例如杀手数独、角线数独等。
1.2功能及简介
数独游戏的规则很简单,只需在空格处填入1~9的数字,并保证每个数字在每个九宫格内只能出现一次,且每个数字在每一行、每一列也只能出现一次,而一般的游戏过成功是系统随机生成一个棋局,然后玩家需在空白处填上相应的数字使其满足游戏规则。
本文设计的功能如下:
菜单——一些常用的操作都放在菜单里面。
显示时间——可以正确显示用户游戏时间。
主界面——可以通过键盘来输入1~9数字信息。
必要提示——可以通过按钮的不同颜色提示用户信息。
绿色:
表示该格的数字目前没有与任何数字有冲突。
黄色:
表示该格的数字于同行、同列或是同九宫格中的数字有冲突。
可以通过改变其本身的数字或者是与其相关各自的数字来消除。
粉色:
表示该格的数字是题目。
白色:
表示该格目前没有数字。
同时也可以提示游戏胜利、用户自定义题目存在矛盾、不是唯一解、
用户自定义题目和游戏存档名称不合法等提示信息。
快速开始:
可以按照用户设置的难度随机初始化一局有唯一解的游戏。
计时功能:
开局的同时开始计时,计算用户玩完一局游戏所用的时间。
重玩:
清空所有用户已填数据,重新开始计时。
智能解题:
根据题目计算出答案,填满剩下的空单元格。
新建题目:
初始化时,所有单元格都是空的,让用户自己填入数字新建题目,并且新建题目的时候也考虑了数独游戏的数字不能冲突特点,不能随便填入数字,也需要确保新建自定义的题目只有唯一解才能进行保存。
保存题目:
可以保存用户新建的题目到puzzle目录下。
选局:
可以打开你保存的题目并开始一局游戏。
设置难度:
提供用户选择随机产生题目的难度,分为“容易、标准、困难、骨灰”。
随机初始化游戏题目时,根据用户选择的难度初始化不同难度的题目。
(不同难度的题目,初始化时给出空格的数量是不一样的,容易:
15个空格,标准:
30个空格,困难:
45个空格,骨灰:
在确定只有唯一答案的情况下给出最多的空格)。
保存和导入:
保存游戏的中间结果,并可导入保存的结果并继续游戏。
(游戏存档在save目录下)
//排行榜功能:
设置排行榜。
每次游戏成功完成时,若耗时比先前纪录的第三名短,
//将记录玩家姓名和用时。
在游戏完成时会显示排行榜,榜上列出耗时长短列出前三名玩家(包括名次、姓名、耗时)。
2总体设计
(5)数独游戏共由7个部分组成,分别是:
MainFrame.java、Checker.java、Creator.java、MyReader.java、Saver.java、Solver.java、TimeKeeper.java。
(1)MainFrame.java
构造方法:
构造出主界面,并添加按钮、计时器以及菜单,并且初始化。
clear方法:
清空游戏数据。
无返回值。
ExitListener内部类:
监听“退出游戏”菜单选项,并执行退出游戏。
ReplayListener内部类:
监听“重玩”菜单选项,并执行清空用户填入数据,只保留题目。
DifficultyListener内部类:
监听“难度设定”菜单中的所有选项,并在选中难度前显示√,将表示难度的变量设定为相应值。
StartListener内部类:
监听“快速开始”菜单选项,调用clear方法并调用Creator类的creator方法产生随机题目,对菜单选项进行是否可用的设置并开始计时。
设定需要进行胜利判定。
SaveListener内部类:
监听“保存题目”菜单选项,调用Checker类的checkCustom方法对自定义题目进行检查和保存。
SaveInGameListener内部类:
监听“即时存档”菜单选项,调用Saver类中的save方法进行游戏进度的保存。
LoadListener内部类:
监听“载入题目并开局”菜单选项,调用clear方法并调用MyReader类中的read方法读取先前保存的自定义题目,对菜单选项进行是否可用的设置并开始计时。
设定需要进行胜利判定。
LoadInGameListener内部类:
监听“载入先前存档并开局”菜单选项,调用clear方法并调用MyReader类中的read方法读取先前保存的游戏存档,对菜单选项进行是否可用的设置并开始按照保存的时间进行计时。
设定需要进行胜利判定。
AnswerListener内部类:
监听“显示答案”菜单选项,调用Solver类中solve方法显示当前题目的答案,对菜单选项进行是否可用的设置并停止计时。
ButtonListener内部类:
监听按钮是否被点击。
获取哪个按钮被点击,并且如果左击按钮就将按钮的数字加一,右击就减一,若显示9时左击或者显示1时右击将会清楚该格数字,成为未填入状态,
如此循环。
同时调用Checker类的checkWin方法进行胜利判定。
main方法:
实例化MainFrame类,并且设定主界面位置、大小和标题等信息。
(2)Checker.java
check方法:
依次判断输入数字所在的按钮所在行、所在列、所在九宫格内是否有与填入数字相同的数字,如果存在相同数字,便将输入数字的按钮以及矛盾数字的按钮设置为黄色。
如果没有冲突,便将输入数字的按钮设置为绿色。
无返回值。
checkGap方法:
对现存所有数字为0的的按钮进行1~9的试填,并且利用与check方法相同的对于冲突性判定的方法进行判断,如果存在一个按钮无法填入1~9中的任意数字,则该按钮无法填入任何数字,将这个按钮设置为红色。
无返回值。
checkCustom方法:
调用check方法和checkGap方法检查自定义题目是否存在冲突或是无法填入任何数字的按钮,同时调用Solver类中的solve方法以及solveC方法进行正向和反向的解题,如果解出不同的答案表明不是唯一解,这样将弹出相关提示。
如果检查没有问题,就调用Saver类中的save方法保存自定义题目。
无返回值。
checkRandom方法:
利用与checkCustom方法相同的方法检查随机产生的题目是否具有解答的唯一性。
返回代表是否具有答案唯一性的布尔型。
checkWin方法:
检查是否所有按钮都被填了数字,以及是否没有出现红色和黄色两种代表填入数字不正确的颜色。
如果是的话便显示游戏胜利信息和用户所用时间,并读取排行榜文件。
把用户用时与排行榜中冠亚季军的成绩作比较。
如果打破记录便提示用户输入姓名并将排行榜文件进行相应的改写。
最后无论是否破纪录都将显示当前
的排行榜。
返回代表是否游戏胜利的布尔型。
(3)Creator.java
copy方法:
将数组A复制给数组B。
无返回值。
creator方法:
产生指定难度的随机题目。
先在随机位置填入1~9各一个,然后解出答案。
然后挖掉难度要求的空格。
没挖一个测试一下题目是否具有答案的唯一性,如果不是便将挖掉的格子原样填上。
最后将所有有数字的按钮设定为表示题目的粉色。
无返回值。
(4)MyReader.java
构造方法:
获得读取存档或是自定义题目的目录。
read方法:
在指定目录的位置使用FileChooser读取文件。
按照储存的格式读取数据并且进行按钮的文字颜色设定。
无返回值。
(5)Saver.java
构造方法:
获得储存存档或是自定义题目的目录。
save方法:
提示用户输入想要保存的文件名,并在指定目录下新建存档文件。
如果出现同名文件便提示用户是否需要覆盖。
同时进行文件名是否是由字母或者数字组成的判断,若不合法将弹出提示。
无返回值。
dataWrite方法:
按照一定格式向存档文件写入数据。
无返回值。
(6)Solver.java
solve方法:
对现存所有数字为0的的按钮进行1~9的试填,并且利用与check方法相同的对于冲突性判定的方法进行判断,如果有冲突便填入下一个数字。
如果没有冲突将运用递归的手段查看是否后续会出现冲突,如果后续会出现冲突就将该按钮上的数字清空。
若没有问题就将该按钮设置为浅蓝色。
返回布尔型,表明是否存在冲突。
solveC方法:
与solve方法相同。
只是试填的时候是进行9~1倒序的试填。
该方法与solve方法一起使用能检测题目是否具有答案唯一性。
(7)TimeKeeper.java
构造方法:
设定显示时间的字体。
paintComponent方法:
清空先前的时间并画出当前时间。
无返回值。
start方法:
计时器开始计时。
无返回值。
pause方法:
计时器暂停。
无返回值。
stop方法:
计时器停止计时。
无返回值。
getSecond方法:
获取当前游戏时间(用秒表示)。
返回整形。
setSecond方法:
设定当前游戏时间(读档时使用)。
无返回值。
TimerListener内部类:
定时器。
每隔一秒画出当前时间。
3代码实现
3.1MainFrame.java
MainFrame.java的作用为生成数独游戏的主界面,实现对界面中的菜单栏中的各组件、文本、按钮的事件监听。
其代码如下:
importjavax.swing.*;
importjava.awt.*;
importjava.awt.event.*;
importjava.io.*;
importjava.util.*;
publicclassMainFrameextendsJFrame{
publicJPanel[]pnlGame;
publicJTextField[][]txtGame;
booleanstart=false;//是否开始计时
booleanwinCheck=false;//是否要进行胜利判定
intdifficulty=30;
//随机产生题目的难度(即随机产生有多少个空格的题目)。
默认为//产生30个空格的题目
MyReadermr=newMyReader("");//读档器
Solvermy=newSolver();//解题器
Creatorc=newCreator();//随机出题器
int[][]origin=newint[9][9];//题目数字。
int[][]matrix=newint[9][9];
//当前游戏数字填入情况的数据。
Timekeepertime=newTimekeeper();//计时器
JMenuItemjmi1=newJMenuItem("退出");
JMenuItemjmi2=newJMenuItem("快速开局");
JMenuItemjmi3=newJMenuItem("自定义题目");
JMenuItemjmi4=newJMenuItem("显示答案");
JMenuItemjmi5=newJMenuItem("保存题目");
JMenuItemjmi6=newJMenuItem("载入题目");
JMenuItemjmi7=newJMenuItem("即时存档");
JMenuItemjmi8=newJMenuItem("载入先前存档");
JMenuItemjmi9=newJMenuItem("简单");
JMenuItemjmi10=newJMenuItem("√标准");
JMenuItemjmi11=newJMenuItem("困难");
JMenuItemjmi12=newJMenuItem("骨灰");
JMenuItemjmi13=newJMenuItem("重玩");
JButtonbut1=newJButton("PLAY");
JButtonbut2=newJButton("暂停");
JButtonbut3=newJButton("00:
00:
00");
JButtonbut4=newJButton("完成");
publicMainFrame(){//主界面
pnlGame=newJPanel[9];
txtGame=newJTextField[9][9];
BorderLayoutb1=newBorderLayout(5,5);
setLayout(b1);
JMenuBarjmb=newJMenuBar();
JMenujm1=newJMenu("模式");
JMenujm2=newJMenu("游戏");
JMenujm3=newJMenu("自定义题目");
JMenujm4=newJMenu("难度设定");
ActionListenerexitListener=newExitListener();
ActionListenerstartListener=newStartListener();
ActionListenercustomListener=newCustomListener();
ActionListenerloadListener=newLoadListener();
ActionListenersaveInGameListener=newSaveInGameListener();
ActionListeneranswerListener=newAnswerListener();
ActionListenersaveListener=newSaveListener();
ActionListenerloadInGameListener=newLoadInGameListener();
ActionListenerdifficultyListener=newDifficultyListener();
ActionListenerreplayListener=newReplayListener();
MouseListenerbuttonListener=newButtonListener();
//MouseListenertextfieldListener=newTextFieldListener();
jmi1.addActionListener(exitListener);
jmi2.addActionListener(startListener);
jmi3.addActionListener(customListener);
jmi6.addActionListener(loadListener);
jmi4.addActionListener(answerListener);
jmi5.addActionListener(saveListener);
jmi7.addActionListener(saveInGameListener);
jmi8.addActionListener(loadInGameListener);
jmi9.addActionListener(difficultyListener);
jmi10.addActionListener(difficultyListener);
jmi11.addActionListener(difficultyListener);
jmi12.addActionListener(difficultyListener);
jmi13.addActionListener(replayListener);
jm1.add(jmi2);
jm1.add(jmi6);
jm1.add(jmi3);
jm1.add(jmi8);
jm1.add(jmi1);
jm2.add(jmi4);
jm2.add(jmi7);
jm2.add(jmi13);
jm3.add(jmi5);
jm4.add(jmi10);
jm4.add(jmi9);
jm4.add(jmi11);
jm4.add(jmi12);
jmb.add(jm1);
jmb.add(jm2);
jmb.add(jm3);
jmb.add(jm4);
add(jmb,b1.NORTH);
JPanelmainPanel1=newJPanel();
JPanelmainPanel2=newJPanel();
JPanelmainPanel3=newJPanel();
JPanelmainPanel4=newJPanel();
add(mainPanel1,b1.CENTER);
time.setPreferredSize(newDimension(80,300));
add(time,b1.EAST);
mainPanel2.add(but1);
mainPanel2.add(but3);
mainPanel2.add(but2);
mainPanel2.add(but4);
add(mainPanel2,b1.SOUTH);
mainPanel1.setLayout(newGridLayout(3,3));
for(inti=0;i<9;i++){
pnlGame[i]=newJPanel();
pnlGame[i].setBorder(BorderFactory.createLineBorder(Color.black));
pnlGame[i].setLayout(newGridLayout(3,3));
for(intj=0;j<9;j++){
txtGame[i][j]=newJTextField();
txtGame[i][j].setBorder(BorderFactory.createEtchedBorder());
txtGame[i][j].setFont(newFont("Dialog",Font.ITALIC,20));//设置字体大小
txtGame[i][j].setHorizontalAlignment(JTextField.CENTER);//设置字体居中
}
mainPanel1.add(pnlGame[i]);
}
for(inti=0;i<3;i++){
pnlGame[0].add(txtGame[i][0]);
pnlGame[0].add(txtGame[i][1]);
pnlGame[0].add(txtGame[i][2]);
pnlGame[1].add(txtGame[i][3]);
pnlGame[1].add(txtGame[i][4]);
pnlGame[1].add(txtGame[i][5]);
pnlGame[2].add(txtGame[i][6]);
pnlGame[2].add(txtGame[i][7]);
pnlGame[2].add(txtGame[i][8]);
}
for(inti=3;i<6;i++){
pnlGame[3].add(txtGame[i][0]);
pnlGame[3].add(txtGame[i][1]);
pnlGame[3].add(txtGame[i][2]);
pnlGame[4].add(txtGame[i][3]);
pnlGame[4].add(txtGame[i][4]);
pnlGame[4].add(txtGame[i][5]);
pnlGame[5].add(txtGame[i][6]);
pnlGame[5].add(txtGame[i][7]);
pnlGame[5].add(txtGame[i][8]);
}
for(inti=6;i<9;i++){
pnlGame[6].add(txtGame[i][0]);
pnlGame[6].add(txtGame[i][1]);
pnlGame[6].add(txtGame[i][2]);
pnlGame[7].add(txtGame[i][3]);
pnlGame[7].add(txtGame[i][4]);
pnlGame[7].add(txtGame[i][5]);
pnlGame[8].add(txtGame[i][6]);
pnlGame[8].add(txtGame[i][7]);
pnlGame[8].add(txtGame[i][8]);
}
but1.addMouseListener(buttonListener);
but2.addMouseListener(buttonListener);
but4.addMouseListener(buttonListener);
for(inti=0;i<9;i++){
//设定每个按钮大小、是否可用等参数
for(intj=0;j<9;j++){
if(matrix[i][j]==0)
txtGame[i][j].setText("");
else{
txtGame[i][j].setText(""+matrix[i][j]);
txtGame[i][j].setBackground(null);
txtGame[i][j].setSize(50,50);
txtGame[i][j].setEdit
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 游戏