24点游戏课程设计报告

目录

1.... 基本功能描述... 2

2.... 设计思路... 2

3.... 软件设计... 4

3.1  设计步骤... 4

3.2  界面设计... 5

3.3  关键功能实现... 6

3.3.1  发牌功能的实现... 6

3.3.2  计时功能的实现... 7

3.3.3  计算功能的实现... 7

3.3.4  验算功能的实现... 9

4.... 结论与心得体会... 9

5.... 参考文献... 11

6.... 思考题... 11

7.... 附录... 12

7.1  调试报告... 12

7.1.1  变量未定义造成的错误... 12

7.1.2管件类未添加... 13

7.1.3进度条错误... 13

7.2  测试结果... 14

7.2.1在规定时间内完成点击“验算”按钮操作... 14

7.2.2在规定时间内未完成点击按钮操作... 16

7.3  关键源代码... 17


24点游戏课程设计报告

1         基本功能描述

24点游戏是一种使用扑克牌来进行的益智的游戏,游戏内容为:从一副扑克牌四个花色的1到K等52张牌中,任意抽取4张牌,运用加、减、乘、除和括号等运算符把牌面上的数进行运算得到24。游戏有不同的版本,其实是对J、Q、和K的处理有所不同。有的版本版本是把J、Q、和K去除,只用1到10来进行游戏;有的版本是把J、Q、和K当成10;还有的版本是用J表示11,Q表示12,K表示13。此次课程设计采用的是把J表示11,Q表示12,K表示13,使游戏的四张牌在1~K这13张牌中随机取牌。具体功能如下:

1)对游戏设计三个难易级别,分别为一级、二级和三级。每次开始游戏前可以根据玩家的需要进行难度设置,如若不设置,系统默认难度级别为一级,设置完难度级别之后就可以开始游戏了,单击“开始”按钮,桌面上出现四张翻开的扑克牌,与此同时,游戏开始计时,进度条开始前进。

2) 在规定的时间内,玩家可以在“输入结果”的编辑框中输入自己想好的算式,然后点击“验算”按钮:如果输入的算式经运算后所的答案正确,则会弹出“Congregations,答对了!”的窗口;如果输入的数字与给出的牌的数字不符或者符号不合法,则会弹出“Sorry,请输入正确的算式!”的窗口;如果输入的数字与四张牌相符、字符亦合法但是答案不正确,则会弹出“  Your answer is wrong!”的窗口;如果未输入任何的数字和算符,则会弹出“输入不能为空!”的窗口。

3)如果在规定的时间内,玩家没有点击验算按钮,则会弹出“Time Over!”的窗口。

4)在结束本轮游戏后,如果玩家想继续游戏,则可点击“开始”按钮即可重新发牌,开始下一轮的游戏;如果玩家想结束游戏,则可点击“结束”按钮即可结束游戏

2         设计思路

24点游戏的具体流程图如下图“图1”所示。下面是对流程图的详细说明。

在游戏开始前有有难度级别设置选项,玩家可以根据自己的实际水平来进行设置。难度级别有三个级别,分别为一级、二级和三级。此三个级别是通过给玩家的思考的时间的长短来区别的,级别越高,可用时间越少。这个难易程度设置不是必选项。如果玩家不设置难易程度,那么系统就默认为难度级别一。

按下“发牌”按钮游戏开始,通过调用srand()和rand()函数,桌面上会随机显示出4张纸牌,这四张牌从1~K这10张牌中随机的调出。与此同时,标识耗时时标的进度条开始前进。计时同步开始(SpendTime++)。通过每隔不同的时间来发送信息来控制三个级别的时间不同。设置了时间限制,如果(m_progress.GetPos()>=100)代表游戏结束,用户没有时间进行思考了,本轮游戏结束,在函数OnTimer()的作用下,会弹出对话“超时!”。

如果用户在限定时间内按下了“验证” 按钮,系统会通过对SubCompute()和TotalCompute()两函数的调用进行相应运算,接下来系统调用OnYanSuan()函数对编辑框玩家输入的算式结果进行验算,根据不同的验算情况给出相应的结果。结果分别为:(1)如果玩家在编辑框中没有输入任何数字和算符而直接按下了“验算”按钮,则会弹出“输入不能为空白!”的提示对话框。(2)如果玩家输入的数字与扑克牌给出的数字不符合,则会弹出“Sorry,请输入正确的算式!”的提示对话框。(3)如果玩家输入的数字与四张牌相符、字符亦合法但是计算结果不为24,会弹出“Your answer is wrong!”的提示对话框。(4)如果玩家输入算式经运算后所得答案正确,则会弹出“Congregations,答对了!”的提示对话框。上述任意一种情况下,只要点击弹出框中的“确定”按钮,系统会自动结束此次游戏,接下来可以单击“开始按钮”进行下一轮的游戏或则单击“结束”按钮推出此游戏。

3         软件设计

3.1  设计步骤

具体的设计步骤如下:

1)在VC++6.0中,用自己的名字gaoqingzhi建立一个MFC AppWizard(exe)工程,在应用程序类型中选择“基本对话框”,其余的都采用默认选项,即可完成对话框的创建。

2)在对话框中添加4个图像(分别用于四张扑克牌),9个按钮(分别是(、+、—、*、/、)、开始、运算、结束),1个编辑框(输入算式),一个进度条和三个单选按钮(用于选择难度级别)接着根据属性对以上所添加的控件进行属性修改,主要进行重命名,以便编辑源代码的时候区分,另外对图像的处理除了对其进行重命名外还要对其添加位图。之后通过打开C:\WINDOWS\system32打开cards.dll加载Bitmap图片,并选中对其进行重命名。

3)接着对以上添加的控件建立类向导。主要有Add Function、Add Variable和Edit Code这三项的添加。

4)根据流程图在类的原文件中逐一添加实现各个模块其功能所需要的各种函数,并添加相应的源代码,同时在头文件中添加对各种函数及变量的声明。

5)对编译好的程序进行保存,开始进行调试,边调试边根据报错对原程序进行修改,直到程序不再进行报错为止。

图2  24点游戏运行图

3.2  界面设计

24点游戏所用控件说明图如下:

表1  控件类型、ID及相关说明

3.3  关键功能实现

3.3.1  发牌功能的实现

首先,通过Number[i]=rand()%13。来产生0-12的随机数,利用该函数加载了标号1~K的13张纸牌和一张背景纸牌。然后运行中的以下一段代码,即可在图像框中得到四张铺开的纸牌。代码如下:

srand((int)time(0));

    for(int i=0;i<4;i++)

    Number[i]=rand()%13;//产生0-12的随机数

    m_picture0.SetBitmap(m_card[Number[0]]);//发牌

    m_picture1.SetBitmap(m_card[Number[1]]);

    m_picture2.SetBitmap(m_card[Number[2]]);

    m_picture3.SetBitmap(m_card[Number[3]]);srand()用来设置rand()产生随机数时的随机数种子。参数必须是个整数,所以用int

型通常可以利用geypid()或time(0)的返回值来当做seed。如果每次seed都设相同值,rand()所产生的随机数值每次就会一样。

rand的内部实现是用线性同余法实现的,可以产生随机数,rand()会返回一随机数值,范围在0至RAND_MAX 间。调用此函数可以产生随机数,但必须先利用srand()设好随机数的种子,如果没有设置随机数的种子,rand()在调用时会自动把其设置为1。这样就可以实现随机发牌的功能。

3.3.2  计时功能的实现

首先,在OnStart()中,通过每隔不同的时间来发送信息来控制三个级别的时间不同。设置了时间限制,如果(m_progress.GetPos()>=100)代表游戏结束,用户没有时间进行思考了,本轮游戏结束,在函数OnTimer()的作用下,会弹出对话“超时!”。源代码如下:

  m_progress.StepIt();

  if(m_progress.GetPos()>=100)

  {

     KillTimer(1);

     AfxMessageBox("超时!");

  }

  else

  CDialog::OnTimer(nIDEvent);

3.3.3  计算功能的实现

对于输入结果的计算,主要是通过int LastPos(CString Str),int FirstPos(CString Str),char FirstF(CString Str),int SubCompute(CString Str),int TotalCompute(CString Str)等函数来来确定输入的算式的优先级别并且计算出输入算式的最终结果。现摘两段代码进行详细说明。

代码1:

      int First=Str.ReverseFind('(')+1;

    while(First)

      {

             CString SubStr =Str.Mid(First,(Str.GetLength()-First));

             int Last= SubStr.Find(')')+1;

             Last+=First; 

             CString LeftStr=Str.Mid(0,First-1);

             CString Middle =Str.Mid(First,Last-First-1);

             CString Right  =Str.Mid(Last,Str.GetLength()-Last);

             int Result=SubCompute(Middle);  

             Middle.Format("%d",Result);

             Str=LeftStr+Middle+Right;

             First=Str.ReverseFind('(')+1;

      }

      int Result=SubCompute(Str);

      return Result;

}

int First=Str.ReverseFind('(')+1;的作用是定位最后一个“(”号位置。Last+=First;作用是定位最后一个“(”号以后的最开始的“)”号位置。CString LeftStr=Str.Mid(0,First-1);是标明“(”号左边的字符串。CString Right  =Str.Mid(Last,Str.GetLength()-Last);是标明“)”号右边的字符串。则可以确定出最高优先级别()的位置,然后对其之间的数字与算符进行最先计算。

代码2:

//定位第一个*号或/号的位置

 int MulPos=Str.Find('*')+1;

 int DivPos=Str.Find('/')+1;

 First=MulPos;

 if(MulPos>DivPos)

   First=DivPos;

 if(DivPos==0  && MulPos!=0)

   {

    First=MulPos;

    DivPos=2000; // 将除号所在位置设置成一个大于MulPos但又不可能的值

   }

 if(DivPos!=0  && MulPos==0)

   {

    First=DivPos; // 将乘号所在位置设置成一个大于DivPos但不可能的值

    MulPos=2000;

   }

代码2的作用是定位第一个*号或/号的位置。系统通过int MulPos=Str.Find('*')+1来查找定位 “*”所在的位置,然后通过First=DivPos将乘号所在位置设置成一个大于DivPos但不可能的值。通过int DivPos=Str.Find('/')+1来查找定位 “/”所在的位置,然后通过DivPos=2000将除号所在位置设置成一个大于MulPos但又不可能的值。这样就完成可定为第一个“*”或“/”的位置。

3.3.4  验算功能的实现

只简单介绍弹出框的实现的功能完成。在规定的时间内玩家输入算式进行验算,根据不同的情况会弹出不同的对话框。有以下四种情况: (1)如果玩家在编辑框中没有输入任何数字和算符而直接按下了“验算”按钮,则会弹出“输入不能为空白!”的提示对话框。(2)如果玩家输入的数字与扑克牌给出的数字不符合,则会弹出“Sorry,请输入正确的算式!”的提示对话框。(3)如果玩家输入的数字与四张牌相符、字符亦合法但是计算结果不为24,会弹出“Your answer is wrong!”的提示对话框。(4)如果玩家输入算式经运算后所得答案正确,则会弹出“Congregations,答对了!”的提示对话框。具体代码如下:

if(Str=="") {MessageBox("表达式不能为空白!","Warning!",MB_OK);flag=0;}

if(Result==24) MessageBox("你输入正确!","TURE!",MB_OK);

由于代码很长,只只是摘取了“不输入任何数字和算符而直接按下了验算按钮”与“输入算式经运算后所得答案正确”两种情况来进行说明。当输入Str为空时,通过MessageBox()显示“输入不能为空白!”。当输入算式正确,判断计算结果Result==24,通过MessageBox()显示“Congregations,答对了!”。当输入字符有错,通过一段很长的程序判断,然后通过MessageBox()显示“Sorry,请输入正确的算式!”。

4         结论与心得体会

6月27号晚上考完我们这学期的最后一门考试,紧接着就开始了开始了为期两周的紧张的C++课程设计,这已经是大学时代的第三次课程设计了,较之之前的两次,感觉这次的与以往大大不同,是利用自己的知识开发一个小游戏,心里着实兴奋了一把,但是这个设计用的是大二上学期学的C++的知识,几乎已经忘得所剩无几了,所以刚刚开始的时候,毫无头绪,感觉好难真的好难,难于上青天。心里障碍阻当着我让我不敢向前迈步。我很怕自己做不好,怕自己不能按时完成,很怕自己不如其他同学。内心满是恐惧,被恐惧占具的心灵又怎么能出色的完成课程设计呢?

但是转念一想,大家都一样,都是一年以前学的知识,都要重新拾起,慢慢的调整了心态,开始进入状态,第一天和室友到图书馆书城去找资料,翻看之前的课件,按着书上实例做了一个计算器的笑例子,头脑又开始小兴奋了,原来拾起之前的知识真的不是很难,接着感觉越做越做越上手,心里充满了自豪感和自信心,感觉自己充满了干劲,接着全身心的投入都接下来的工作中。最后在遇到重重困难,走了好多次的弯路之后终于完成了此次课设。一下是这次课设的历程,过程虽然你艰辛,但终于做出了成果,很有成就感。

最初进行设计的时候,没有一点头绪,后来对照课本基本控件这一章,将计算器和菜单栏制作这两个范例做了几遍。感觉很有收获,但是对于进程条的设置还是不清楚,又翻出课件来看重新学习,经与同学讨论,终于弄清了进程条的设置。而对于编程,是最庞大又棘手的一块,那是忘得更多了,于是把课本和图书馆借来的参考书重新针对性的学了一次,遇到难处先是仔细的思考然后在向同学请教。可以说开始的那么几天都是在查找资料,翻阅相关的书籍。在最后添加代码的时候还有一些程序不知道怎么写。于是,于是又利用了网络资源,收集里了一些,经分析、查询资料仍有一些地方看不懂。就请教同学,尝试往对话框中添加相应代码的方法。根据一大段的分析,感觉程序执行某个功能,将这段代码添加到对应位置。所有的代码添加完后,运行、调试,开始会出现了很多很多的错误。逐条进行修改,再进行运行和调试,有时候错误看不懂,就找同学商量。也不知道错了多少次,改了多少次,终于最后做出了完美的游戏界面。终于完成了设计。

但是本次课程设计是自己第一次开发小游戏,心理很甜。通过此次课程设计,收获颇多,最主要的是对C++知识重新学习了一遍,感受到了它的博大精深;同时对word又有了进一步的了解和掌握。

首先,编程有了很大的提高,虽然有时候自己没有思路,但是可以借鉴别人的代码,看别人设计的思路,理解的同时自己小试一下也可以编出来,所以凡事不能被困难吓倒,只要有开始,去尝试。就会有意想不到的收获。

再次,在运行、调试过程中也学到了很多,以前编程最怕的就是报错,尤其是错误多了的时候,感觉毫无头绪直接头大,但是编程不可能不出错,报错,只要逐一对付,然后细心研究改正,终究一切问题都会迎刃而解的,所以遇到问题,不能急,要心平气和的去应对,才能把所学的只是真正用于实际,这不得不说正是我们当代大学生所严重缺乏的,以后的学习中更应注意。

其次,对word有了更进一步的了解。尽管上次课设就用了word,但是这次用起来还是感觉不是很顺手,比如不知道一个在word里面如何写画系统流程图,这次知道了原来word强大的功能我只了解其最基本的一些东西,在以后的学习中要多加利用多加学习,以后再要写什么东西的话,我想应该要轻松很多吧。

综上,不到两周的课程设计即将结束,虽然时间有些紧凑,虽然中间遇到好多的挫折,但毕竟是自己努力了的,自己收获的是过程中的酸甜苦辣,总体收获很大,有了此次的学习经验,我想以后的课程设计应该就会轻松的多吧。通过这次课程设计,加强了我动手、思考和解决问题的能力。比如细心还有耐心还有对自己有一定的自信等等。而且课程设计同时也是对课本知识的巩固和加强,由于课本上的知识太多,平时只有课间的学习是远远不够的,所以以后要多花时间温故知新。两个星期的课程设计,过程曲折可谓一语难尽。在此期间我也从毫无头绪到一度热情高涨。到从开始时满富盛激情到调不出结果的焦头烂额,到最后慧心的笑,点点滴滴无不令我回味无长。总之对我而言,知识上的收获重要,精神上的丰收更加可喜。挫折是一份财富,经历是一份拥有。这次课设必是我人生旅途上一个非常美好的回忆!

5         参考文献

[1]揣锦华.面向对象程序设计与VC++实践.西安电子科技大学出版社,2005:

[2]刘弘,刘希玉.面向对象程序设计——VC++6.0与基于ACIS的几何造型.北京邮电大学出版社,2005:282-292

[3]刘浩,陈曙东.C#编程实例与技巧.清华大学出版社,2002:166-226

6         思考题

1)  改变难度可以变化游戏的限时和游戏加分的规则,如何实现?

游戏的限时是通过对进度条的设置来实现的,通过定义了一个m_Hardlevel变量来实现的,通过这个定义的变量来设置进度条的范围(SetRange(0,m_Hardlevel);),当玩家选择了不同级别的游戏,相应的进度条的范围会随着m_Hardlevel的值而不同,游戏难度越大,m_Hardlevel的值越小,时间也就越短,反之时间越长。

游戏的加分规则综合玩家选择的游戏级别和完成一局游戏所花费时间的长短而得出的,即:m_score=100*(m_Hardlevel-SpendTime)/m_Hardlevel;说难度的选择和用户所用时间同时决定最后的得分。

2)  如何使用随机函数控制扑克牌的显示?

首先通过资源把纸牌加载到Bitmap[]中,在对纸牌重新命名。通过随机函数得到四个随机数之后,亦即得到四张系统随机发放的纸牌;然后利用指针将得到的纸牌在void CDingluDlg::OnStart()中进行相应设置;最后在void CDingluDlg:: OnYanSuan()中,通过Mid()和int m=(int)(int)(strtod(Mul1.GetBuffer(Mul1. GetLength()),&stopstring)); 获取用户输入到编辑框中的数据,将m和Number[i]进行比较,从而最终确保程序是根据给出的牌来书写算式的。

3)  考虑如何保证程序是根据给出的牌来书写算式的?

首先在BOOL CDingluDlg::OnInitDialog()中,用纸牌对应的ID号对纸牌进行加载(如Bitmap[12].LoadBitmap(IDB_BITMAP12)),然后在void CDingluDlg::OnStart()中,利用srand((int)time(0));和Number[i]=rand()%13;两条语句选出相对应的四张纸牌,即可得到随机发放的四张扑克牌了。

7         附录

7.1  调试报告

7.1.1  变量未定义造成的错误

在代码添加过程中,由于涉及到很多的函数和变量,有时候可能会出现某几个变量忘定义的情况,这些变量有可能是在头文件中忘记定义或者在某个函数体中忘记定义。下面举一个在头文件中变量忘定义的例子,如下所示:

图3  因变量未定义而出现的错误截面图

在添加完各个函数的代码完毕后,以为头文件会自动对相应得变量进行定义,但头文件没有对所有的变量都定义,于是出现了如上图所示的错误。打开头文件,双击gaoqingzhiDlg.h,在class CDgaoqingzhiDlg : public Cdialog类定义函数中添加对m_back参数的定义。添加完毕后,重新进行编译,程序不再报这个错误。

此类错误出过几次,都是由于自己变成不严谨以后一定注意。

7.1.2管件类未添加

建立好工程之后,在画图对话框中,添加各种控件后,逐一对每个控件重命名并且添加类向导。对话框中出现的控件一般都不会忘记建立类向导,但有1个类向导是容易忘记的,它是IDC_PROGRESS1建立的类向导名称是OnOutofmemoryProgress1。下面用图形表示这个错误,如下所示:

根据错误提示,重新选中图片,建立OnOutofmemoryProgress1的类向导。建立完毕后,重新运行程序,不再提示开错误。

图4  因关键类未添加而出现的错误截面图

7.1.3进度条错误

在类导向和代码添加完后,运行程序,出现游戏界面。点击游戏界面内的“发牌”按钮,出现四张扑克展开,但是没过2秒钟跳出“Time Over!”对话框,并且进度条不动。下面用图形表示这个错误,如下图所示:

 

图5  进度条设置错误而出现的错误截面图

这个错误可能是计时时间设置的太短,进度条的步长设置的不合理。重新设置计时时间范围和进度条步长,然后运行程序,错误仍然存在。再从头到尾把程序检查一遍,做相应修改,再运行,错误仍然存在。于是将所有类删除后重新添加,并且添加相应程序,重新运行,错误消失。

7.2  测试结果

7.2.1在规定时间内完成点击“验算”按钮操作

测试过程中,由于既涉及到纸牌点数和运算符,又会涉及到运算式结果,于是相应地会显示出四种结果,(1)如果玩家在编辑框中没有输入任何数字和算符而直接按下了“验算”按钮,则会弹出“输入不能为空”的提示对话框。(2)如果玩家输入的数字与扑克牌给出的数字不符合,则会弹出“Sorry,请输入正确的算式!”的提示对话框。(3)如果玩家输入的数字与四张牌相符、字符亦合法但是计算结果不为24,会弹出“Your answer is wrong!”的提示对话框。(4)如果玩家输入算式经运算后所得答案正确,则会弹出“Congregations,答对了!”的提示对话框。如果输入算式经运算后所得答案正确,则会弹出“你做对了!”。下面用图形做相应说明:

1)没有输入任何数字和算符而直接按下了“验算”按钮,则会弹出“输入不能为空!”的提示对话框。如下图所示:

图6  输入表达式为空而出现的游戏界面

2)输入的数字与扑克牌给出的数字不符合,则会弹出“Sorry,请输入正确的算式!”的提示对话框。如下图所示:

图7  输入字符错误而出现的游戏界面

3)输入的数字与四张牌相符、字符亦合法但是计算结果不为24,会弹出“Your answer is wrong!”的提示对话框。如下图所示:

 

图8  输入字符正确而运算结果不正确出现的游戏界面

4)输入输入算式经运算后所得答案正确,则会弹出“Congregations,答对了!”的提示对话框。如下图所示:

 

图9  输入结果正确而出现的游戏界面

7.2.2在规定时间内未完成点击按钮操作

规定时间内未进行输入,或输入后未完成点击“验算”按钮操作,显示“Time Over!”,如下图所示:

图9  规定时间内未进行输入出现的游戏界面

7.3  关键源代码

BOOL CGaoqingzhiDlg::OnInitDialog()程序初始化

m_back.LoadBitmap(59);//开始前牌面的显示

      m_picture0.SetBitmap(m_back);

      m_picture1.SetBitmap(m_back);

      m_picture2.SetBitmap(m_back);

      m_picture3.SetBitmap(m_back);

      m_card[0].LoadBitmap(1);//存储13张牌

      m_card[1].LoadBitmap(2);

      m_card[2].LoadBitmap(3);

      m_card[3].LoadBitmap(4);

      m_card[4].LoadBitmap(5);

      m_card[5].LoadBitmap(6);

      m_card[6].LoadBitmap(7);

      m_card[7].LoadBitmap(8);

      m_card[8].LoadBitmap(9);

      m_card[9].LoadBitmap(10);

      m_card[10].LoadBitmap(11);

      m_card[11].LoadBitmap(12);

      m_card[12].LoadBitmap(13);

void CGaoqingzhiDlg::OnStart() //“Start”按钮响应函数

{

      srand((int)time(0));

    for(int i=0;i<4;i++)

    Number[i]=rand()%13;//产生0-12的随机数

      m_picture0.SetBitmap(m_card[Number[0]]);//发牌

      m_picture1.SetBitmap(m_card[Number[1]]);

      m_picture2.SetBitmap(m_card[Number[2]]);

      m_picture3.SetBitmap(m_card[Number[3]]);

   

      m_progress.SetPos(0);

      UpdateData(true);

    if(m_time==0)m_Hardlevel=2000;

    if(m_time==1)m_Hardlevel=1000;

      if(m_time==2)m_Hardlevel=500;

             m_input.Empty();

    UpdateData(false);

      SetTimer(1,m_Hardlevel,NULL);

   

}

void CGaoqingzhiDlg::OnTimer(UINT nIDEvent) //计时器响应函数

{

             m_progress.StepIt();

      if(m_progress.GetPos()>=100)//时间到?

      {

             KillTimer(1);

             AfxMessageBox("超时!");

      }

      else

      CDialog::OnTimer(nIDEvent);

}

void CGaoqingzhiDlg::OnZoukuo() //“(”按钮响应函数

{

      UpdateData(true);

      m_input+="(";

      UpdateData(false);

}

void CGaoqingzhiDlg::OnYoukuo() //“)”按钮响应函数

{

    UpdateData(true);

      m_input+=")";

      UpdateData(false);   

}

void CGaoqingzhiDlg::OnAdd() //“+”按钮响应函数

{

      // TODO: Add your control notification handler code here

      UpdateData(true);

      m_input+="+";//在末尾添上“+”字符

      UpdateData(false);

}

void CGaoqingzhiDlg::OnJian() //“-”按钮响应函数

{

      UpdateData(true);

      m_input+="-";

      UpdateData(false);

}

void CGaoqingzhiDlg::OnCheng() //“*” 按钮响应函数

{

      UpdateData(true);

      m_input+="*";

      UpdateData(false);

}

void CGaoqingzhiDlg::OnChu() //“/”按钮响应函数

{

      UpdateData(true);

      m_input+="/";

      UpdateData(false);

}

void CGaoqingzhiDlg::OnJieshu() //“结束” 按钮响应函数

{

      OnOK();

}

void CGaoqingzhiDlg::OnYansuan() “验算” 按钮响应函数

{

      // TODO: Add your control notification handler code here

      CString s,s1,s2;

    t1=Number[0]+1;

      t2=Number[1]+1;

      t3=Number[2]+1;

      t4=Number[3]+1;

    s=compu(t1,t2,t3,t4);

      s1=compu(t3,t2,t1,t4);//四张牌的计算

    s2=compu(t4,t2,t1,t3);

    m_none = false;

                    KillTimer(1);

            n=      TotalCompute(m_input);

                    if(n==24)

                    {

                           MessageBox("正确,请继续!");

                    }

                    else MessageBox("错误!");

}

//算法

CString CGaoqingzhiDlg::compu(int i1, int i2, int i3, int i4)

{

      CString s;

      int i,j,k,l;

      float a[4];

      a[0]=(float)i1;

      a[1]=(float)i2;

      a[2]=(float)i3;

      a[3]=(float)i4;

      for (i=0;i<4;i++)

             for (j=0;j<4;j++)

                    for (k=0;k<4;k++)

                           for (l=0;l<4;l++)

                                  if (i!=j&&i!=k&&j!=k&&i!=l&&j!=l&&k!=l)

                                         if (compu1(a[i],a[j],a[k],a[l],s))

                                                return s;

      s.Format("%d,%d,%d,%d",i1,i2,i3,i4);

      return s;

}

int CGaoqingzhiDlg::compu1(float i1, float i2, float i3, float i4, CString &s)

{char op[4][6]={"+","-","*","/"};

      int i,j,k;

      float f;

      for(i=0;i<4;i++)

             for (j=0;j<4;j++)

                    for (k=0;k<4;k++)

                    {

                                  f =compu3(compu3(compu3(i1,i2,i),i3,j),i4,k);

                                  if (f>23.9999&&f<24.0001)

                                  {

                                         s.Format("((%2d %s %2d) %s %2d) %s %2d=24",(int)i1,op[i],(int)i2,op[j],(int)i3,op[k],(int)i4);

                                         return 1;

                                  }

                                  f =compu3(compu3(i1,i2,i),compu3(i3,i4,k),j);

                                  if (f>23.9999&&f<24.0001)

                                  {

                                         s.Format("(%2d %s %2d) %s (%2d %s %2d)=24",(int)i1,op[i],(int)i2,op[j],(int)i3,op[k],(int)i4);

                                         return 1;

                                  }

                                  f =compu3(compu3(i1,compu3(i2,i3,j),i),i4,k);

                                  if (f>23.9999&&f<24.0001)

                                  {

                                         s.Format("(%2d %s (%2d %s %2d)) %s %2d=24",(int)i1,op[i],(int)i2,op[j],(int)i3,op[k],(int)i4);

                                         return 1;

                                  }

                                  f =compu3(i1,compu3(compu3(i2,i3,j),i4,k),i);

                                  if (f>23.9999&&f<24.0001)

                                  {

                                         s.Format("%2d %s ((%2d %s %2d) %s %2d)=24",(int)i1,op[i],(int)i2,op[j],(int)i3,op[k],(int)i4);

                                         return 1;

                                  }

                                  f =compu3(i1,compu3(i2,compu3(i3,i4,k),j),i);

                                  if (f>23.9999&&f<24.0001)

                                  {

                                         s.Format("%2d %s (%2d %s (%2d %s %2d))=24",(int)i1,op[i],(int)i2,op[j],(int)i3,op[k],(int)i4);

                                         return 1;

                                  }

                    }

                    return 0;

}

float CGaoqingzhiDlg::compu3(float i1, float i2, int i)

{switch(i)

      {

      case 0:

             return i1+i2;

      case 1:

             return i1-i2;

      case 2:

             return i1*i2;

      case 3:

             if (i2>0.0001||i2<-0.0001) return i1/i2;

             else return 9999.9;

      }

      return 9999.9;

}

int CGaoqingzhiDlg::TotalCompute(CString Str)

{

      int First=Str.ReverseFind('(')+1; //定位最后一个(号位置

    while(First)

      {

             CString SubStr =Str.Mid(First,(Str.GetLength()-First));

             int Last= SubStr.Find(')')+1;

             Last+=First;  //定位最后一个(号以后的最开始的)号位置

             CString LeftStr=Str.Mid(0,First-1); //(号左边的字符串

             CString Middle =Str.Mid(First,Last-First-1); //()号中间的字符串

             CString Right  =Str.Mid(Last,Str.GetLength()-Last); //)号右边的字符串

             int Result=SubCompute(Middle);  //进入下面的计算

             Middle.Format("%d",Result);

             Str=LeftStr+Middle+Right;

             First=Str.ReverseFind('(')+1;

      }

      int Result=SubCompute(Str);

      return Result;

}

int CGaoqingzhiDlg::SubCompute(CString Str)

{

      CString Middle="";

    CString Mul2="";

     CString Right="";

 //定位第一个^号位置 ,计算乘方

 int First=Str.Find("^")+1;

 if(First) //循环计算乘方

   {

     CString tempStr=Str.Mid(0,First-1);

    int        temp=AnyLastPos(tempStr);

    CString Left=Str.Mid(0,temp);

    CString Mul1 =Str.Mid(temp,First-temp-1);

    tempStr=Str.Mid(First,Str.GetLength()-First);

    temp=AnyFirstPos(tempStr);

    if(temp==200)

     {

      Mul2=tempStr;

      Right="";

     }

    else

     {

      Mul2 =tempStr.Mid(0,temp-1);

      Right=tempStr.Mid(temp-1,tempStr.GetLength()-temp+1);

     }

    Middle.Format("%d",(int)(pow(atof(Mul1),atof(Mul2))));

    Str=Left+Middle+Right;

    First=Str.Find("^")+1;

      }

 //定位第一个*号或/号的位置

 int MulPos=Str.Find('*')+1;

 int DivPos=Str.Find('/')+1;

 First=MulPos;

 if(MulPos>DivPos)

   First=DivPos;

 if(DivPos==0  && MulPos!=0)

   {

    First=MulPos;

    DivPos=2000; // 将除号所在位置设置成一个大于MulPos但又不可能的值

   }

 if(DivPos!=0  && MulPos==0)

   {

    First=DivPos; // 将乘号所在位置设置成一个大于DivPos但不可能的值

    MulPos=2000;

   }

 while(First) //循环计算乘、除

   {

    CString tempStr=Str.Mid(0,First-1);

    int        temp=AnyLastPos(tempStr);

    CString Left=Str.Mid(0,temp);

    CString Mul1 =Str.Mid(temp,First-temp-1);

    tempStr=Str.Mid(First,Str.GetLength()-First);

    temp=AnyFirstPos(tempStr);

    if(temp==200)

     {

      Mul2=tempStr;

      Right="";

     }

    else

     {

      Mul2 =tempStr.Mid(0,temp-1);

      Right=tempStr.Mid(temp-1,tempStr.GetLength()-temp+1);

     }

    if(MulPos>DivPos)

       Middle.Format("%d",(int)(strtod(Mul1.GetBuffer(Mul1.GetLength()),&stopstring)/strtod(Mul2.GetBuffer(Mul2.GetLength()),&stopstring)));

    else

         Middle.Format("%d",(int)(strtod(Mul1.GetBuffer(Mul1.GetLength()),&stopstring)*strtod(Mul2.GetBuffer(Mul2.GetLength()),&stopstring)));

    Str=Left+Middle+Right;

    MulPos=Str.Find('*')+1;

    DivPos=Str.Find('/')+1;

    First=MulPos;

    if(MulPos>DivPos)

       First=DivPos;

    if(DivPos==0  && MulPos!=0)

      {

       First=MulPos;

       DivPos=2000; // 将除号所在位置设置成一个大于MulPos但又不可能的值

      }

    if(DivPos!=0  && MulPos==0)

      {

       First=DivPos; // 将乘号所在位置设置成一个大于DivPos但不可能的值

       MulPos=2000;

      }

   }

 //定位+、-号首先出现的位置

 First=AnyFirstPos(Str);

 if(First==200)//如果没有+、-号,则可以直接返回结果

   return (int)strtod(Str.GetBuffer(Str.GetLength()),&stopstring);

 char Fuhao=AnyFirstF(Str); //确定首先出现的符号是+号还是-号

 while(First)

   {//如果找到+号或-号

     CString tempStr=Str.Mid(0,First-1);

     int        temp=AnyLastPos(tempStr);

     CString Left=Str.Mid(0,temp);

     CString Mul1 =Str.Mid(temp,First-temp-1);

     tempStr=Str.Mid(First,Str.GetLength()-First);

     temp=AnyFirstPos(tempStr);

     if(temp==200)

       {

        Mul2=tempStr;

        Right="";

       }

     else

       {

        Mul2 =tempStr.Mid(0,temp-1);

        Right=tempStr.Mid(temp-1,tempStr.GetLength()-temp+1);

       }

     if(Fuhao=='+')

       Middle.Format("%d",(int)(strtod(Mul1.GetBuffer(Mul1.GetLength()),&stopstring)+strtod(Mul2.GetBuffer(Mul2.GetLength()),&stopstring)));

     else

       Middle.Format("%d",(int)(strtod(Mul1.GetBuffer(Mul2.GetLength()),&stopstring)-strtod(Mul2.GetBuffer(Mul2.GetLength()),&stopstring)));

     Str=Left+Middle+Right;

     First=AnyFirstPos(Str);

     if(First==200)

       break;

     Fuhao=AnyFirstF(Str);

   }

 return (int)strtod(Middle.GetBuffer(Middle.GetLength()),&stopstring);

}

char CGaoqingzhiDlg::AnyFirstF(CString Str)

{

int SubPos=Str.Find('-')+1;

 int PluPos=Str.Find('+')+1;

 int MulPos=Str.Find('*')+1;

 int DivPos=Str.Find('/')+1;

 if(SubPos==0)

   SubPos=200;

 if(PluPos==0)

   PluPos=200;

 if(MulPos==0)

   MulPos=200;

 if(DivPos==0)

   DivPos=200;

 char Result='-';

 int tempPos=SubPos;

 if(PluPos<tempPos)

   {

    Result='+';

    tempPos=PluPos;

   }

 if(MulPos<tempPos)

   {

    Result='*';

    tempPos=MulPos;

   }

 if(DivPos<tempPos)

   {

    Result='/';

    tempPos=DivPos;

   }

 return Result;

}

int CGaoqingzhiDlg::AnyFirstPos(CString Str)

{

 int SubPos=Str.Find('-')+1;

 int PluPos=Str.Find('+')+1;

 int MulPos=Str.Find('*')+1;

 int DivPos=Str.Find('/')+1;

 int ForPos=Str.Find('^')+1;

 int Pos=200;

 if(SubPos==0) //如果没有-号

   SubPos=200; //将SubPos设置成一个不可能的值

 if(PluPos==0) //如果没有-号

   PluPos=200; //将PluPos设置成一个不可能的值

 if(MulPos==0) //如果没有*号

   MulPos=200; //将MulPos设置成一个不可能的值

 if(DivPos==0) //如果没有/号

   DivPos=200; //将DivPos设置成一个不可能的值

 if(ForPos==0) //如果没有^号

   ForPos=200; //将ForPos设置成一个不可能的值

 if(Pos>SubPos)

   Pos=SubPos;

 if(Pos>PluPos)

   Pos=PluPos;

 if(Pos>MulPos)

   Pos=MulPos;

 if(Pos>DivPos)

   Pos=DivPos;

 if(Pos>ForPos)

   Pos=ForPos;

 return Pos;

}

int CGaoqingzhiDlg::AnyLastPos(CString Str)

{

int SubPos=Str.ReverseFind('-')+1;

 int PluPos=Str.ReverseFind('+')+1;

 int MulPos=Str.ReverseFind('*')+1;

 int DivPos=Str.ReverseFind('/')+1;

 int Pos=SubPos;

 if(Pos<PluPos)

   Pos=PluPos;

 if(Pos<MulPos)

   Pos=MulPos;

 if(Pos<DivPos)

   Pos=DivPos;

 return Pos;

}

相关推荐