数独游戏设计论文.docx
《数独游戏设计论文.docx》由会员分享,可在线阅读,更多相关《数独游戏设计论文.docx(37页珍藏版)》请在冰豆网上搜索。
数独游戏设计论文
XXXXXX大学信息工程学院
C++面向对象实习报告
题目:
数独游戏的设计与实现
学号
0000000000
姓名
XXX
专业班级
计算机科学与技术XX班
指导教师
XXX
实践日期
XXXXXXX
一、综合训练目的与要求
1.综合训练目的:
1)能够熟练运用CodeBlocks编译和调试程序。
2)以实习来强化C++知识,熟练运用C++。
3)学习QT编程,了解QT中各个类以及函数,并利用QT为数独游戏进行界面设计
2.综合训练要求:
1)按时到达实习机房,不迟到,不早退。
2)在实习之前,做好实习计划,合理安排时间。
3)在编程和界面设计时要尽量的专注和细心,再设计算法时要考虑周全。
二、综合训练任务
1.设计算法自动随机生成不完整数独,并且设计算法求解,从而完成数独游戏的设计与实现。
2.编译并调试程序,利用QT设计界面,完善各个功能。
三、总体设计
1.主菜单:
主菜单中主要设计了开始游戏,游戏提示,查看答案,游戏技巧,游戏说明及退出游戏等工具条。
2.游戏界面:
游戏界面分为游戏区和功能区。
游戏区主要是有一个9×9的宫格组成,玩家可以在每个宫格中输入数字。
功能区主要包括游戏难度选择,提示,重玩,答案,确认及退出按钮。
可实现相应的功能。
四、详细设计说明
1.主菜单中各个功能的详细介绍:
(1)进入游戏
含义:
进入游戏会提供四个不同的难度进行游戏,分别是简单,一般,困难,特难四个等级。
代码实现如下:
operaMenu=newQMenu(tr("菜单(&O)"),this);
ui->menuBar->addMenu(operaMenu);
startMenu=newQMenu(tr("开始游戏(&Q)"),this);
operaMenu->addMenu(startMenu);
而这四个难度分别由SudokuClear1(),SudokuClear2(),SudokuClear3(),SudokuClear4()来控制的。
(2)重玩本局
含义:
玩家可以通过此操作来清除自己填过的数字,重新开始本局游戏。
本操作主要通过SudokuReplay()函数来实现清除操作。
(3)答案提示
含义:
玩家可通过此操作来获取一个空位的正确填法,也可以纠正玩家填错的数字。
提示操作是由SudokuHint()函数实现。
(4)查看答案
含义:
此功能的本质是数独的自动求解,玩家可通过此操作来查看数独的正确答案。
本操作由SudokuRun()来实现的。
(5)游戏技巧
含义:
在游戏技巧中,主要是为玩家提供求解数独的几种方法,便于求解数独。
(6)关于
含义:
对数独游戏的基本介绍,包括其版本信息及游戏来历等。
(7)退出游戏
含义:
退出系统,close()函数实现。
2.游戏界面各个功能详细介绍:
(1)游戏区
含义和内容:
游戏界面是实现玩家直接与计算机交流的地方。
对于游戏区我采用的是81个可编辑的文本框按9×9的顺序排列方式来形成数独显示的界面。
而程序内部采用一个二维数组与81个文本框相对应进行操作。
游戏设置了简单,一般,困难和特难4个等级的难度。
当玩家选择一个难度开始游戏时,系统内部会调用随机生成的不完整数独数组,然后将对应的数字显示在81个文本框内,如果遇到数组中的值为0的元素,那么对应的文本框将不显示数字并将此文本框的值标记为-1。
遇到不为0值时文本框会将其显示出来,并使此文本框成为不可编辑的为文本框。
同时,系统会对生成的数独进行求解,将答案储存在这个二维数组中。
当玩家填完数独后,系统会对玩家所填好的数独与此数组中的值逐一对比若发现有不同的将提示玩家答案错误,若完全相同则将提示玩家答案正确。
玩家若想退出游戏直接点击相应的操作即可退出游戏。
(2)函数实现
详见核心代码清单。
(3)算法讲解
1)数独自动随机生成算法:
对于数独的随机生成,我采用的是将一个正确而完整的数独进行随机的变换得到新的数独然后对其进行随机的挖空。
具体来说是将一个完整的数独,即二维数组matrix[9][9]当中的所有行或列中某两个数进行交换,然后将得到的数独记为map[9][9],在对其进行随机的挖空,即可得到数独题目。
此算法由函数:
voidSudokuSwap(int*number1,int*number2)和voidSudokuGeneration(intdegree)实现。
2)数独求解算法;
数独求解主要运用于数独的自动求解即给玩家提供数独正确的答案。
具体来说是利用深度优先搜索对每个空位进行1~9的填充,然后检测所填数字在所在行、列以及3×3的宫格中是否有与之相同的数字。
若有,则函数返回0说明此数字错误,检测下一数字。
若没有,则函数返回1,说明所填数字正确,此时对下以空格进行相同的操作。
此算法对应函数boolDFS(intsum)。
3),判断数独算法:
判断数独算法主要是用来判断玩家所完成的数独是否正确。
该算法是先对原数独进行求解,得到正确答案map[9][9]。
然后将玩家所完成的数独app[9][9]与之进行逐一对比。
再次设置一个标记的变量a;若有app[i][j]!
=map[i][j],则令a=1。
检查完成后若有a=1则说明玩家答案错误。
反之说明答案正确。
此算法对应函数为:
voidSudokuSure()。
4)重玩算法:
重玩算法主要是用来实现让玩家重新开始本局游戏的。
该算法是将原先生成的不完成的数独记录在arr[9][9]中。
当玩家需要重玩时,系统将arr[9][9]中的元素输出到宫格中覆盖掉玩家输入的数,此时玩家可以重新开始游戏。
相应函数为:
voidSudokuReplay()。
5)答案提示算法:
此算法主要用于提示玩家下一个空位的正确填法或纠正玩家填错的地方。
其具体实现过程是现将原数独求解出来记为map[9][9],然后将玩家所填的数独记为app[9][9],然后将两个数独进行逐一对比。
若发现app[i][j]与map[i][j]的值不同则将map[i][j]的值输出到文本框,若玩家已经填过但错误那么将会被map[i][j]所覆盖。
若没填过则将直接将map[i][j]的值输出,然后跳出循环。
即每次只提示一个空位或错位。
此算法所调用函数为:
voidSudokuHint()。
3.界面设计
1)游戏区界面设计
本游戏采用的是81个9×9的文本框组成。
首先定义一个Block类。
classBlock:
publicQWidget
{
Q_OBJECT
public:
Block(QWidget*parent=0);
voidchangeColor(constQColor&color);
intdata();
QPointgetPos();
voidsetPos(constQPoint&p);
voidsetPos(intx,inty);
voidsetValue(inta);
voidsetEna(boolok);
privateslots:
voiddataChange(constQString&data);
private:
QLineEdit*nubEidt;
intda;
QPointp;
};
在这个类中包括文本框的的一些基本属性,包括文本框的位置,颜色,值等等。
文本框具体是通过MainWindow类里面的voidcreateBlocks()函数来实现。
为了游戏的更好体验,再次定义了一个Gline类。
Gline类是用来画线,画出六条纵横交错的线将81个小格分成9个3×3的格,可以让玩家更好的判断某一个空格属于哪个3×3的格子。
classGLine:
publicQWidget
{
public:
GLine(QWidget*parent=0);
voidsetPen(intpenSize,constQColor&color);
voiddraw(intz,intlen);///z=0H,z=1,V
protected:
voidpaintEvent(QPaintEvent*);
private:
intpenSize;
QColorpenColor;
intz;
intlen;
};
2)功能区界面设计:
功能区主要包括游戏菜单和按钮。
菜单中包括对游戏的基本操作以及对游戏的介绍。
菜单:
a)开始游戏
开始游戏中分为四个难度的选择:
简单,一般,困难,特难。
这四个操作分别调用MainWindow中的槽函数:
voidSudokuClear1(),voidSudokuClear2(),voidSudokuClear3(),voidSudokuClear4()。
b)重玩本局
调用MainWindow中的槽函数:
voidSudokuReplay()。
c)答案提示
调用MainWindow中的槽函数:
voidSudokuReplay()。
d)查看答案
调用MainWindow中的槽函数:
voidSudokuHint()。
e)退出游戏
调用close()函数。
帮助:
a)游戏技巧
介绍游戏的几种基本解题方法,为玩家提供参考。
调用函数:
voidSudokuSkill()
b)关于
对游戏基本介绍。
调用函数:
voidSudokuAbout()
备注:
为了游戏的更好体验我将菜单中的各个操作设置了相对应的按钮,其功能不变在次不作特别说明。
五、调试与测试
1.游戏界面展示
图1.1游戏主界面
2.帮助界面
图1.2技巧介绍界面
图1.3游戏介绍界面
3.开始游戏界面
图1.4开始游戏界面
4.答案提示界面
图1.5答案提示界面
5.查看答案界面
图1.6查看答案界面
6.重玩界面
图1.7重玩界面
7.判断界面
图1.8判断界面
8.遇到的问题
问题:
当进入系统后直接点击答案提示,重玩本局,查看答案时系统会崩溃。
解决方法:
设置一个标志mark变量,来标记玩家是否开始了一局游戏
if(mark==0)
{
QMessageBox:
:
about(NULL,"提示",tr("请先选择游戏难度"));
}
六、实习日志
(1)3月2日选题
今天主要进行选题,我们组选择了“数独游戏的设计与实现”。
选题之后我查阅了有关数独的资料,由于玩过数独游戏所以就数独的原理来说还是不难理解的。
主要在于如何设计算法来实现数独的生成与求解。
虽说玩过游戏但是其中的各种设计我还是比较陌生,所以查阅了一些数独游戏设计方法。
(2)3月3日项目总体设计与模块划分
今天是对数独游戏进行总体的设计,大概分了三个模块:
数独的生成,数独的求解,游戏界面设计。
我负责数独生成算法的代码编写,同伴负责求解算法。
然后各自设计界面。
(3)3月4日设计具体算法
由于我负责数独生成的算法,即生成一个不完整的数独提供给玩家使用。
我大概的思路是先找一个正确而完整的数独,然后在随机交换其中的数,使之成为新的数独,在进行随机的挖空,便可形成不完整的数独
(4)3月5日撰写代码,中期检查
由于基本算法已设计好了,今天的主要任务就是编写代码。
在进行数独中数字交换时遇到了一点麻烦,好几次交换过后的数独都是错误或无解的。
调试了很多次均出现同样的问题,于是不得不从头开始一步一步的检验,耗费了很多时间,好在最终解决了。
老师检查后提了一些意见,同时也给予了肯定。
(5)3月6日继续完善和调试
今天我对自己写的代码进行了再一次的调试,再确认基本完善后与同伴进行了讨论。
因为我们负责的部分不同,所以要进行连部分代码的无缝链接。
在链接的过程中遇到了一些问题,最终我们各修改了自己的代码。
经过几次调试终于可以运行。
(6)3月9日界面总体设计
数独算法已经设计完成,所以今天的任务便是设计游戏的界面,大概分为游戏区和功能区。
我初步给这游戏设计了几个简单的功能:
开始游戏,难度选择,提示以及查看答案等等。
在菜单上设计了几个对应的工具条,又在功能区设计了几个按钮。
下午的时候开始进行QT编程,对所设计的各个功能进行实现。
首先是将各个操作对应的函数写出来,然后将各个幸好与槽进行链接。
放学时,基本的都实现了,但有待完善。
(7)3月10日完善代码,准备论文
今天我是将昨天的QT代码进行了完善对界面进行了美化,虽然我设计的游戏有些方面不够完善,但是由于实习的时间紧迫,无法做到面面俱到。
下午的时候我就开始准备论文资料,将这几天所做的东西进行了整理和总结。
(8)3月11日撰写实习报告。
由于实习论文比较重要,所以我打算今天用一整天的时间来撰写论文。
所以今天基本所有时间都在写论文。
(9)3月12日完善论文,制作答辩PPT
今天将论文完善了一遍,将其中的错误进行了纠正。
由于明天就要进行实习答辩,所以剩下的时间都用来制作答辩PPT了。
(10)3月13日实习答辩
今天是实习的最后一天,同时也要进行实习答辩。
整个上午我将答辩的资整理了一下,下午进行了答辩。
七、实习总结
通过此次C++面向对象编程的实习,我学到了许多东西。
首先经过一个寒假的休整,由于过年的原因没有时间巩固C++知识,然而这次实习就给我提供了一个很好的机会。
在实习过程中不断地运用上学期学的C++知识,使我对其中的一些以前难以消化的东西有了新的理解。
而且编程过程中也找到了以规范化的东西,老师也说规范对于程序员来说是至关重要的。
而在实习中我也得到了一些提升,虽然说不上标准,但最起码比以前有了进步。
这次实习的另一个较大的收获就是,我认识到了如何利用QT进行界面设计。
老师也讲了一些关于界面设计的知识,由于时间紧迫无法讲透彻,只是做了大概的介绍。
我在用QT做界面设计的时候遇到了不少问题,只得自己查阅资料了解QT里的各种函数。
由于时间有限没法对QT进行升入的研究,所以游戏的界面做的可能还有很多缺陷。
但是这次界面设计让我认识到了QT的强大,我想在以后的学习中慢慢的了解它,争取做出美观的界面。
总而言之,这次课程设计对于我学习有很大的促进作用,这样的实习很有意思,同时也很有意义。
八、附录:
核心代码清单
1.主界面及个菜单的建立
MainWindow类:
#ifndefMAINWINDOW_H
#defineMAINWINDOW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"block.h"
#include"gline.h"
namespaceUi{
classMainWindow;
}
classMainWindow:
publicQMainWindow
{
Q_OBJECT
public:
explicitMainWindow(QWidget*parent=0);
~MainWindow();
privateslots:
voidSudokuRun();
voidSudokuClear1();
voidSudokuClear2();
voidSudokuClear3();
voidSudokuClear4();
voidSudokuAbout();
voidSudokuHint();
voidSudokuSkill();
voidSudokuReplay();
voidSudokuSure();
private:
voiddrawLine();
voidcreateBlocks();
voidcreateAction_Menu();
boolDFS(intsum);
voidInit();
boolCmps(inti,intj,intk);
boolCmp1();
voidSudokuSwap(int*number1,int*number2);
voidSudokuGeneration(intdegree);
private:
Ui:
:
MainWindow*ui;
enum{Max=9};
Block*blocks[Max][Max];
QFrame*frame;
QMenu*startMenu;
QMenu*operaMenu;
QMenu*helpMenu;
QAction*easyAction;
QAction*normalAction;
QAction*hardAction;
QAction*difficultAction;
QAction*replayAction;
QAction*clearAction;
QAction*runAction;
QAction*quitAction;
QAction*aboutAction;
QAction*hintAction;
QAction*skillAction;
QAction*degreeAction;
QPushButton*easyButton;
QPushButton*normalButton;
QPushButton*hardButton;
QPushButton*difficultButton;
QPushButton*hintButton;
QPushButton*replayButton;
QPushButton*runButton;
QPushButton*quitButton;
QPushButton*sureButton;
intmap[9][9];
intarr[9][9];
intmark;
intfw[9][9],fh[9][9],fs[5][5][9];
};
#endif
创建窗口:
MainWindow:
:
MainWindow(QWidget*parent):
QMainWindow(parent),
ui(newUi:
:
MainWindow)
{
mark=0;
ui->setupUi(this);
createAction_Menu();
frame=newQFrame(this);
createBlocks();
drawLine();
this->setFixedSize(700,500);
frame->move(0,25);
this->setWindowIcon(QIcon(":
/icon/icon2.png"));
this->setWindowTitle("数独");
QPalettepalette(this->palette());
palette.setColor(QPalette:
:
Background,Qt:
:
green);
this->setPalette(palette);
}
创建9×9的文本框:
voidMainWindow:
:
createBlocks()//创建文本框
{
for(inti=0;i{
for(intj=0;j{
blocks[i][j]=newBlock(frame);
blocks[i][j]->setPos(i,j);
blocks[i][j]->move(j*50,i*50);
blocks[i][j]->setEna(false);
}
}
intw=(50)*9+1;
frame->setMinimumSize(w,w);
}
voidMainWindow:
:
drawLine()//绘制线条
{
GLine*line_H[4];
QColorcolor;
QRgbrgb=qRgb(255,0,0);
color.setRgb(rgb);
for(inti=0;i<4;i++)
{
line_H[i]=newGLine(frame);
line_H[i]->setPen(3,color);
line_H[i]->draw(1,frame->height());
if(i>0)
line_H[i]->move(blocks[0][i*3+1]->pos().x()+blocks[0][i*3+1]->width()-2,0);
else
line_H[i]->move(0,0);
}
GLine*line_V[4];
for(inti=0;i<4;i++)
{
line_V[i]=newGLine(frame);
line_V[i]->setPen(3,color);
line_V[i]->draw(0,frame->width());
if(i>0)
line_V[i]->move(0,blocks[i*3-1][0]->pos().y()+blocks[i*3-1][0]->height()+ui->menuBar->height()-2);
else
line_V[i]->move(0,0);
}
}
创建菜单及按钮:
voidMainWindow:
:
createAction_Menu()//菜单
{
operaMenu=newQMenu(tr("菜单(&O)"),this);
ui->menuBar->addMenu(operaMenu);
startMenu=newQMenu(tr("开始游戏(&Q)"),this);
operaMenu->addMenu(startMenu);
easyAction=newQAction(tr("简单"),this);
easyAction->setShortcut(tr("ctrl+e"));
easyAction->setStatusTip("数独较简单");
connect(easyAction,SIGNAL(triggered()),this,SLOT(SudokuClear1()));
startMenu->addAction(easyAction);
normalAction=newQAction(tr("一般"),this);
normalAction->setShortcut(tr("ctrl+n"));
normalAction->setStatusTip("数独较一般");
connect(normalAction,SIGNAL(trigger