基本功能描述
24点游戏是一种常见的数学运算游戏,玩游戏者只需根据系统给出的四张1~9的纸牌算出24即可,而程序主要负责实现随机发牌、结果验算、计算得分和难度设置等功能。
设计的程序要求具有如下功能:
(1)按下“发牌”按钮时开始游戏,桌面上显示4张翻开的扑克牌,并且游戏开始计时,进度条开始前进。
(2)当用户能够将4张牌计算出24时,可以按下“输入算式”按钮,此时游戏计时停止,用户可在编辑框中输入。
(3)输入结束,用户按下“验算”按钮,计算输入的多项式。验算通过,显示“正确”;验算出错,显示“错误”。
(4)如果用户希望继续游戏,则可按下“发牌”按钮;否则按下“结束游戏”按钮。
在运行游戏时,还可以通过难度级别的下拉列表来改变游戏的难度。改变难度可以变化游戏的限时和游戏加分的规则。
运行后的初始界面为:
运行成功后的界面为:
 
 
 
 
 

设计框图

运行
调试出错
调试出错
调试出错
功能调试
功能调试
功能调试
添加进度条
完成
调试通过
编写消息处理代码
 
编写消息处理代码
 
编写消息处理代码
添加列表控件
添加组合框
添 加按钮
添加静态控件
应用程序界面设计
导入扑克牌资源
创建基于对话框的应用程序
原理、功能分析
开始
加载菜单资源

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
软件设计过程
一、应用程序界面设计
首先创建一个名为“24点游戏”的工程。启动VC6.0,依次点击“文件→新建”,在弹出的对话框中选择工程类型为“MFC AppWizard(exe)”,工程名取为“24点游戏”,保存在“D:\赵志刚\24点游戏”目录下,选择基于对话框的应用程序类型,生成与用户交互的应用程序界面。程序界面如图1所示
(图1)
通过对应用程序基本功能的描述,可以知道要实现该程序的功能,在所设计的基于对话框的应用程序中应包括以下资源及控件:
(一)资源
⑴扑克牌资源:由于Windows系统自带的纸牌游戏中存放有扑克牌,故可以将所需的扑克牌资源导入应用程序。首先找到位于WINDOWS目录下的cards.dll文件,然后选择VC IDE中的“文件 | 打开”,文件类型选择Executable Files(.exe;.dll;.ocx),“打开方式” 选择Resource,然后打开cards.dll文件(如下图2所示)。打开cards.dll,选择其中所需的Bitmap,按住鼠标左键不放,将Bitmap直接拖入应用程序的Workspace工作区。本程序选择各种花色从A~9以及用于程序运行后初始显示为背面的纸牌总计37张牌。将所需纸牌全部导入应用程序后,更改其属性,将ID设置为从1~37这些整数值。
             
                  图(2)                                                  图(3)
⑵菜单资源:依次点击“插入→资源”,在弹出的对话框中双击“Menu”项(如图3所示),即实现了向应用程序中加载菜单资源。
(二)控件
(1)静态控件:共9个,其中4个用于显示随机产生的4张扑克牌,另外5个分别用于显示提示文字“耗时标识:”、“难度级别:”、“当前得分:”、“历史记录:”以及累计游戏得分值。具体为:
     ①耗时标识:提示用户计时时间。
     ②难度级别:提示用户当前选择的难度级别。
     ③当前得分:提示用户累计总得分信息。
④历史记录:提示用户有关游戏次数及正误信息。
⑤显示累计游戏得分值,初始设置为0
(2)按钮:共4个,分别是:
①“发牌”按钮:点击此按钮,随机产生4张扑克牌并在4个静态控件上显示,同时启动计时器,进度条开始计时。游戏开始。
②“输入算式”按钮:当用户能够将4张牌计算出24时,点击此按钮即可在编辑框中输入计算式,同时停止游戏计时,进度条停止前进。
③“验算”按钮:点击此按钮,应用程序即对用户输入的计算式进行检验,如果判断用户输入的计算式恰为所发牌的点数,则对输入算式进行验算,同时将计算结果以消息框的形式告知用户,并在历史记录列表框中加以显示。若计算结果正确,程序还根据难度级别在“当前得分:”中加分;若输入算式不合乎要求,则告知用户一个错误消息。最后,为防止游戏者不断点击此按钮以增加得分,当用户一次点击后即被禁止,呈灰色显示。
④“结束游戏”按钮:点击此按钮则游戏结束,退出应用程序。
3)组合框:共1个,此框中设置有“热身运动”和“智力比拼”两个难度级别以供游戏者选择,不同的难度级别在一次游戏得分和耗时标识进度条计时快慢上有所不同。游戏者点击不同的选项即可设定不同的难度级别。
(4)列表控件:共1个,用于记录游戏者总的游戏次数以及相关的对错信息。
(5)编辑框:共1个,用于接收游戏者输入的计算式。                                
(6)进度条:共1个,游戏者单击发牌按钮后,计时器启动,耗时标识进度条同时开始计时,游戏者必须在耗时标识进度条计时终止前思考出计算式,然后单击“输入算式”按钮,此时耗时标识进度条停止计时。否则,耗时标识进度条计时终止,应用程序以消息框的形式报告"真遗憾,时间到了!"。
添加这些控件后,再设置其属性,如ID及Caption等。各控件的相关设置信息列表如下:

控件对象
ID
Caption
显示纸牌的静态控件1
IDC_STATIC1
/
显示纸牌的静态控件2
IDC_STATIC2
/
显示纸牌的静态控件3
IDC_STATIC3
/
显示纸牌的静态控件4
IDC_STATIC4
/
耗时标识提示静态控件
IDC_STATIC
耗时标识:
难度级别提示静态控件
IDC_STATIC5
难度级别:
当前得分提示静态控件
IDC_STATIC6
当前得分:
显示当前得分静态控件
IDC_STATIC7
/
历史记录提示静态控件
IDC_STATIC8
历史记录
发牌按钮
IDC_BUTTON1
发牌
输入算式按钮
IDC_BUTTON2
输入算式
验算按钮
IDC_BUTTON3
验算
结束游戏按钮
IDC_BUTTON4
结束游戏
进度条
IDC_PROGRESS1
/
输入算式编辑框
IDC_EDIT1
/
显示历史记录列表控件
IDC_COMBO1
/
难度级别选择组合框
IDC_LIST1
/

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
添加控件以及设置属性等完成后,应用程序的界面如下图4所示
(图4)
(注:由于用于显示随机产生的4张牌及当前得分的静态控件其Caption并未设置任何内容,故在界面中并未显示。)
二、编写应用程序代码
(一)为添加的各个控件定义成员变量
在进行程序的代码编写过程之前需要为某些控件连接变量。定义成员变量可以在“建立类向导”中完成,其操作步骤为:在欲添加成员变量的控件上右击,点击弹出的快捷菜单中的“建立类向导”项,在随后弹出的对话框中选择“Member Variables”选项卡,单击欲添加变量的控件ID标识,接着点击“Add Variable”按钮,在弹出的对话框中设定“Member variable name”、“Category”及“Variable type”,然后点击OK按钮,则为该控件添加了一个成员变量。其他控件成员变量的添加可以仿此完成。其演示过程如下图5~7所示:
 
图(5)                                            图(6)
图(7)
比较图5和图7,可以看到,在图7中已经为编辑框控件添加了一个成员变量m_edit,其类型为CString类。
重复此过程,为所有需要添加变量的控件连接变量,结果如下表所示:
控件对象
变量名
类型
IDC_STATIC1
m_bmp1
CStatic
IDC_STATIC2
m_bmp2
CStatic
IDC_STATIC3
m_bmp3
CStatic
IDC_STATIC4
m_bmp4
CStatic
IDC_COMBO1
m_cb
CComboBox
IDC_EDIT1
m_edit
CString
(二)为按钮及组合框控件添加消息响应函数
由于按钮及组合框控件均能发送消息,故应用程序中应有对此消息的响应函数,以处理这些消息并实现相应的功能。此程序中为这些控件添加的方法如下表所示:
控件对象
方法
IDC_BUTTON1
OnButton1()
IDC_BUTTON2
OnButton2()
IDC_BUTTON3
OnButton3()
IDC_BUTTON4
OnButton4()
IDC_LIST1
OnSelchangeCombo1()
(三)方法的实现
A.应用程序启动时会自动显示4张背面的纸牌,并且难度级别默认为“热身运动”(可以选择“热身运动”或“智力比拼”),当前得分为0,列表控件无历史记录,由此则需要在构造函数CMy24Dlg(CWnd* pParent /*=NULL*/)及初始化函数OnInitDialog( )中添加如下代码:
 
//定义一个结构体变量lvItem
LV_ITEM  lvItem;
CMy24Dlg::CMy24Dlg(CWnd* pParent /*=NULL*/)
{
…………………………………………………………………………
//设置列表控件列属性                                            
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
lvItem.state = 0;     
lvItem.stateMask = 0; 
lvItem.iImage = 0;
…………………………………………………………………………
}
 
BOOL CMy24Dlg::OnInitDialog()
{
……………………………………………………………………
//初始化组合框
m_cb.InsertString(0,"智力比拼");        //为组合框添加子项
m_cb.InsertString(1,"热身运动");        //为组合框添加子项
m_cb.SetCurSel(1);                    //默认为“热身运动”
SetDlgItemText(IDC_STATIC7,"0");    //开始时得分为0
 
//设置列表控件风格
LV_COLUMN  lvColumn;           //定义一个结构体变量lvColumn                                      
lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvColumn.fmt = LVCFMT_CENTER;
lvColumn.cx = 52;
//设置列表控件列标题
lvColumn.iSubItem = 0;
lvColumn.pszText = "题数";
((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(0, &lvColumn);
lvColumn.iSubItem = 1;
lvColumn.pszText = "对错";
((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(1, &lvColumn);   //通过强制类型转换以获得列表控件的指针,并对它进行相关操作
 
//设置初始发牌显示为背面的纸牌
m_bmp1.ModifyStyle(0,SS_BITMAP);
HBITMAP hBmp1; hBmp1=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(37));
m_bmp1.SetBitmap(hBmp1);
 
m_bmp2.ModifyStyle(0,SS_BITMAP);
HBITMAP hBmp2; hBmp2=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(37));
m_bmp2.SetBitmap(hBmp2);
 
m_bmp3.ModifyStyle(0,SS_BITMAP);
HBITMAP hBmp3; hBmp3=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(37));
m_bmp3.SetBitmap(hBmp3);
 
m_bmp4.ModifyStyle(0,SS_BITMAP);
HBITMAP hBmp4; hBmp4=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(37));
m_bmp4.SetBitmap(hBmp4);
 
//设置进度条的初始位置为0,范围为0~100
CProgressCtrl *pProg=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);
pProg->SetRange(0,100);
pProg->SetPos(0);
……………………………………………………………………
}
B.当发牌时,进度条开始计时。当输入算式时进度条停止计时。需要设置进度条的范围和当前位置。范围表示整个操作的持续时间,当前位置表示当前进行到的位置。进度条根据当前位置来判断进行的百分比并显示进度。进度条的初始化在初始化函数OnInitDialog( )中完成,添加的代码如前所示。进度条的停止计时控制在OnButton1( )消息响应中完成。按下按钮1时,系统要随机发出4张牌,进度条同时开始计时,编辑框中前一次输入的内容被清除。给按钮IDC_BUTTON1添加代码,OnButton1( )方法的实现代码如下:
 
int suiji[4];
void CMy24Dlg::OnButton1()
{
// TODO: Add your control notification handler code here
GetDlgItem(IDC_BUTTON3)->EnableWindow(1);      //重新发牌时激活验算按钮3
CString s("");                                    //清除前一次输入的内容
m_edit=s;
UpdateData(FALSE);
 
//产生1~36之间的四个随机数,并存放在一个整型数组中
srand( (unsigned)time( NULL ) );//产生四个随机数
for (int i=0;i<4;i++)
suiji[i]=1+rand()%36;
   
m_bmp1.ModifyStyle(0,SS_BITMAP);               //显示第一张牌
HBITMAP hBmp1=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[0]));
m_bmp1.SetBitmap(hBmp1);
 
m_bmp2.ModifyStyle(0,SS_BITMAP);               //显示第二张牌
HBITMAP hBmp2=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[1]));
m_bmp2.SetBitmap(hBmp2);
 
m_bmp3.ModifyStyle(0,SS_BITMAP);               //显示第三张牌
HBITMAP hBmp3=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[2]));
m_bmp3.SetBitmap(hBmp3);
 
m_bmp4.ModifyStyle(0,SS_BITMAP);               //显示第四张牌
 
HBITMAP hBmp4=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[3]));
m_bmp4.SetBitmap(hBmp4);
 
CProgressCtrl *pProg=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);   //进度条开始计时pProg->SetPos(0);
SetTimer(1000,100,NULL);                        //步进时间设置为0.1秒
 
}
C.按下按钮2时进度条停止计时,游戏者在编辑框中输入计算式。为按钮IDC_BUTTON2添加代码,OnButton2( )方法的实现代码如下:
 
void CMy24Dlg::OnButton2()
{
       // TODO: Add your control notification handler code here     
       KillTimer(1000);
}
D.按下按钮3时,应用程序判断游戏者输入是否符合要求,若计算式所得结果正确,则加分并修改历史记录,否则,以消息框的形式告知游戏者“错误”并修改历史记录。若输入操作数不符合要求,则弹出"操作数个数不符"消息框;若输入的操作数不是所发牌的点数,则弹出"输入数据与所发牌不一致,游戏结束!"消息框。最后两者都对历史记录进行修改。为按钮IDC_BUTTON3添加代码,OnButton3( )方法的实现代码如下:
 
首先添加头文件:
#include <ctype.h>
#include <string.h>
#include "stdio.h"
然后添加方法的实现代码:
typedef struct                                            //表达式处理函数
{
 int top;
 double array[50];
}NumStack;
 
typedef struct
{
 int top;char array[50];
}OpStack;
 
int Cint(char mychar)
{
 return (mychar-48);
}
 
void PushNum(NumStack *numstack,double num)
{
 numstack->top++;
 numstack->array[numstack->top-1]=num;
}
 
void PopNum(NumStack *numstack,double *num)
{
 *num=numstack->array[numstack->top-1];
 numstack->top--;
}
 
void PushOp(OpStack *opstack,char op)
{
 opstack->top++;
 opstack->array[opstack->top-1]=op;
}
 
void PopOp(OpStack *opstack,char *op)
{
 *op=opstack->array[opstack->top-1];
 opstack->top--;
}
 
double Calc(double a,double b,char c)
{
 double result;
 switch(c)
 {
 case '+': result=a+b;break;
 case '-': result=a-b;break;
 case '*': result=a*b;break;
 case '/': result=a/b;break;
 }
 return result;
}
 
char Priority(char y,char x)
{
 char priority='<';
 switch(x)
 {
   case '+':
   case '-': if(y=='(' || y=='#')priority='>';break;
   case '*':
   case '/': if(y=='(' || y=='#'|| y=='+' || y=='-')priority='>';break;
   case '(': priority='>';break;
   case ')': if(y=='(')priority='=';break;
   case '#': if(y=='#')priority='=';break;
   default:   priority='E';
 }
 return priority;
}
void Process(NumStack *numstack,OpStack *opstack,char x)
{
double a,b;
char c;
static double tempnum=0.00000000;
static int len=10;
static int dot=0,flags=0;
if(isdigit(x) || x=='.')
 
{
 if(x=='.') dot=1;
 else
 {
   if(dot==0) tempnum=tempnum*10+Cint(x);
   else
   {
    tempnum=tempnum+(double)Cint(x)/len;
    len*=10;
   }
 }
 }
 
 else
 {
 if(flags==0&& x!='(') 
{
PushNum(numstack,tempnum);
tempnum=0.00000000;
len=10;dot=0;
}
 switch(Priority(opstack->array[opstack->top-1],x))
 {
   case '>': PushOp(opstack,x);flags=0;break;
   case '<': PopOp(opstack,&c);
              PopNum(numstack,&b);
           PopNum(numstack,&a);
           PushNum(numstack,Calc(a,b,c));flags=1;
           Process(numstack,opstack,x);break;
   case '=': PopOp(opstack,&c);flags=1;break;
   }
 }
}
 
int checkequ(int s[],int m[])       //判断编辑框中输入的数字是否为所发牌的点数
{
int a=0,b=0;
    for(int k=0;k<4;k++)
   {int qiuyu=s[k]%9;
     if(qiuyu==0) s[k]=9;
    else   s[k]%=9;
    }
for(int t=0;t<4;t++)//判断编辑框输入的每个数字能否都在随机数中找到与之相同的项 if(s[t]==m[0]||s[t]==m[1]||s[t]==m[2]||s[t]==m[3])
    a+=1;                                
 
for(int j=0;j<4;j++)//判断随机数中的每个数字能否都与编辑框输入的数据相匹配
    if(m[j]==s[0]||m[j]==s[1]||m[j]==s[2]||m[j]==s[3])
    b+=1;                                
 
if((a==4)&&(b==4))//对判断结果的处理,若一致则返回1值,否则返回0值
  return 1;
else
return 0;
}
 
 
CString input;    //定义一个字符串类
int proceed(LPCTSTR L)//验算输入计算式,若结果等于24则返回真值,否则为假,并提示
{
   NumStack numstack;OpStack opstack;int i=0;
   numstack.top=0;opstack.top=0;
   PushOp(&opstack,'#');
  for(i=0;i<strlen(L);i++)
     Process(&numstack,&opstack,L[i]);
if(numstack.array[numstack.top-1]==24)
      { AfxMessageBox("正确");input="正确";return 1;}
else
{AfxMessageBox("错误");input="错误";return 0;}
}
 
//为响应函数OnButton3()添加代码,判断操作数是否合乎要求,修改当前得分及历史记录
void CMy24Dlg::OnButton3()
{
       // TODO: Add your control notification handler code here
int m=0,i=0, shuju[100];
    CString biaoda;
    UpdateData(TRUE);
biaoda=m_edit;
biaoda=biaoda+"#";
    for(i=0;i<strlen(biaoda);i++)
       if((biaoda[i]>'0')&&(biaoda[i]<'10'))     //将输入字符串中的数字字符转换为整型数
         shuju[m++]=biaoda[i++]-'0';
    if(m!=4)                              //判断输入操作数个数是否合乎要求
        {
        AfxMessageBox("操作数个数不符");
        input="错误";
      GetDlgItem(IDC_BUTTON3)->EnableWindow(0);//个数不匹配,点按钮3后即被禁止
        }
   else
     {
          int r=checkequ(suiji,shuju);
if(r==1)
          {
int flag=proceed(biaoda); 
         if(flag)             //若计算式正确,则根据难度级别加分,修改当前得分记录
               {
          defen+=jiafen;                                      
          CString str;
          str.Format("%d",defen);
         
SetDlgItemText(IDC_STATIC7,str);
               }
          }
       else
        AfxMessageBox("输入数据与所发牌不一致,游戏结束!");
        GetDlgItem(IDC_BUTTON3)->EnableWindow(0);// 防止刷分,点按钮3后即被禁止
   }
 
int  count=0; char s;
count+=1;       //根据程序运行结果修改历史记录
wsprintf(&s,"%d",count);
lvItem.iItem = count-1;
lvItem.iSubItem = 0;
lvItem.pszText = &s;
((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertItem(&lvItem);
((CListCtrl*)GetDlgItem(IDC_LIST1))->SetItemText(count-1, 1,input);
UpdateData(FALSE);
 
}
E.按下按钮4时游戏结束,退出应用程序。为按钮IDC_BUTTON4添加代码,OnButton4( )方法的实现代码如下:
 
void CMy24Dlg::OnButton4()
{
       // TODO: Add your control notification handler code here
       OnOK();
}
F.游戏启动后,在发牌之前,游戏者首先选择难度级别(如果不进行选择的话,则默认为“热身运动”),程序根据游戏者设置的级别来进行计时和加分。因此当游戏者进行选择时,列表框会发出CBN_SELCHANGE消息,其处理函数为OnSelchangeCombo1( ),其实现方法如下:
void CMy24Dlg::OnSelchangeCombo1()  
{
       // TODO: Add your control notification handler code here
       CString msg;
       m_cb.GetLBText(m_cb.GetCurSel(),msg);
       if(strcmp(msg,"智力比拼"))
       {     
sudu=1;jiafen=5;
}
       if(strcmp(msg,"热身运动"))
       {     
sudu=3;jiafen=10;
}
}
(四)添加菜单项及其消息响应代码
(1)添加菜单项
打开Workspace工作区,展开“Menu”文件夹并双击“IDM_MENU1”,在右边窗格中右击有虚线框标识的菜单,在随后弹出的对话框中设置其属性:“标题”中填入“游戏”,选中“弹出”复选框,这样就不必设置其ID。如图8所示
 
图(8)
单击“游戏”菜单项,在弹出的 中右击虚框标识的菜单项,随后设置其属性:
以添加“开始[B]”菜单项为例,设置其ID为“IDM_Begin” ,“标题”填入“开始[&B]”如下图9所示。完成后回车,其界面变为 重复此过程,为菜单添加菜单项“开始”、“退出”、“帮助”以及“关于”。
(2)将菜单资源链接到主对话框
展开“Dialog”文件夹,双击“IDD_MY24_DIALOG”项,在随后弹出的应用程序界面上右击标题栏,在弹出的对话框中设置“菜单:”项为“IDD_MENU1”,则将菜单链接到了主对话框中。如图10所示
图(10)
回车后运行程序,则可以看到已经将菜单成功加入。
(3)为菜单项添加消息响应代码
①“开始”菜单项用于控制发牌和启动计时器,使进度条前进。为其添加消息响应函数及代码如下:
void CMy24Dlg::OnBegin()
{
// TODO: Add your command handler code here
GetDlgItem(IDC_BUTTON3)->EnableWindow(1);
CString s("");
m_edit=s;
UpdateData(FALSE);
  
srand( (unsigned)time( NULL ) );
for (int i=0;i<4;i++)
suiji[i]=1+rand()%36;
   
m_bmp1.ModifyStyle(0,SS_BITMAP);
HBITMAP  hBmp1=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[0]));
m_bmp1.SetBitmap(hBmp1);
 
m_bmp2.ModifyStyle(0,SS_BITMAP);
HBITMAP  hBmp2=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[1]));
m_bmp2.SetBitmap(hBmp2);
 
m_bmp3.ModifyStyle(0,SS_BITMAP);
HBITMAP  hBmp3=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[2]));
m_bmp3.SetBitmap(hBmp3);
 
m_bmp4.ModifyStyle(0,SS_BITMAP);
HBITMAP hBmp4=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[3]));
m_bmp4.SetBitmap(hBmp4);
 
CProgressCtrl *pProg=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);
pProg->SetPos(0);
SetTimer(1000,100,NULL);  
}
②“退出”菜单项用于结束游戏并退出应用程序。为其添加消息响应函数及代码如下:
void CMy24Dlg::OnExit()
{
    // TODO: Add your command handler code here
    OnOK();
}
③“关于”菜单项用于给用户以提示信息。为其添加消息响应函数及代码如下:
void CMy24Dlg::OnAbout()
{
    // TODO: Add your command handler code here
    CAboutDlg dlg;
   dlg.DoModal();
}
至此,整个软件设计过程完成。接下来进入调试过程,对所编写的代码进行调试。若无误,即可进入运行阶段。否则继续重复上述步骤。
 
结论
1. 根据设计要求,所编写的软件实现了全部的功能,完成了设计任务。测试结果附于后。
2. 该设计并没有充分发挥VC++的优势,面向对象程序设计思想贯彻不够彻底。
3. 程序所采用的对表达式进行处理的算法不够完善(因而也称不上是一个好的算法,但是从原理上讲是没有问题的。对此,我参考了各种版本的《数据结构》教材(参考书籍附于后)。基于教材中对“利用堆栈求表达式的值”的介绍,编写了此算法。不过还是存在bug,偶尔也会出现判断失误现象。关于这个问题,我请教了本班同学及高中同学,结果还是不能得到完善的解决。这是本次设计最大的遗憾。
4. 对VC++学习不够深入,未能领会利用MFC进行可视化程序设计的要旨,因此在调试程序的过程中出现了好多现象都难以解释。例如,为列表控件(ListControl)定义一个变量后,程序不能正常运行,不得已只好改用指针,结果程序能够正常运行。对此,我不明白其中的原因。
5. 作为一个交互性很好的应用程序,应该为用户提供更为友好的交互方式,如当游戏者在按下“输入算式”按钮后,为方便操作以及省去游戏者频繁点击鼠标以获得编辑框输入焦点的麻烦,编辑框应自动获得输入焦点。本设计中未实现这一功能,因此应当改进,这样可使游戏操作更为方便。
6. 程序中每次发出的扑克牌中没有10,这是为方便程序设计而有意去掉的。因为算法是利用堆栈来求表达式的值的,而10在进行压栈操作时是作为两个字符进行处理的,这为程序设计带来不便:因为为处理这一张牌需要耗费更多的系统资源。为方便计,略去10号牌,不过一个完善的游戏是应该能处理10的。
7. 本程序的另一个不完善之处是:当用户按下“输入算式”按钮后,计时器停止,进度条停止前进,此后游戏者
可以在任意长的时间内思考计算式,然后输入。对此,应用程序无能为力,不能对游戏者的思考时间进行有效控制。在设计之初,我曾考虑再增加一个进度条对思考时间计时以实现控制,但由于不会合理使用相关方法,结果两个进度条发生冲突,反而连基本的计时功能也实现不了,无奈只有放弃这一尝试。
 
总之,通过对24点游戏的设计,可以熟悉MFC编程,加深对对话框编程的认识和理解,并训练Visual C++在数学计算方面的知识,以及在按钮上设置位图、设置定时器的方法和应用程序的调试,同时对面向对象与可视化程序设计有一定的认识,并提高动手编程的能力。
 
心得体会
经历了这次应用软件设计实践,我感触颇深。此前一直错误的以为做课程设计其实是件很简单的事情,根本不需要兴师动众而且花费那么长的时间,两三天足矣。在此错误认识的引导下,也就没怎么把它当回事,只打算随随便便应付一下,完工交差。但是等到真正亲历后才发现原来自己是多么的愚蠢可笑,自己的想法又是多么的幼稚、荒谬。
做的过程并不顺利,而其中的种种遭遇更是让我反省良久。一路坚持下来,其中的艰辛也许只有经历过才能真正体会。不过,经过一番实践后,当看到自己亲手做的东西就那么真实的摆在眼前,曾经的心血与付出终于有了回报,那份激动与喜悦的心情又岂是三言两语说得清楚的!“如人饮水,冷暖自知”,现在我是真的体会到了。
总的来说,我觉得这次设计实践收获颇丰,于今后的学业、步入社会后参加工作乃至做人做事都是一笔不小的财富!通过这次课程设计,我懂得了实践的重要性、团队合作精神的可贵以及做事前的充足准备与做事过程中的坚持和细心谨慎对于高质高效地完成一项工作的特殊意义。任何事情都有一个循序渐进的过程,知难而进、勇往直前,只有这样才有可能领略险峰的无限风光。治学、做人又何尝不是如此呢?
    先说实践。关于实践,前人曾留有十二字箴言:“实践是检验真理的唯一标准”,经过这次应用软件设计,我所理解的实践已远不只此。人说“爱过才知情深,醉过方知酒浓”,我以为,只有实践才会出真知,没有实践,任何理论、见解都是苍白无力的。眼之所见、心之所想大多数时候并不就是手之所为。在动手尝试之前,我可以算是一个眼高手低的人。课程设计的题目下来了,共有三个可供选择。相较之下我选了做“24点游戏”,本以为这是最简单的,基本上可以不费多大心力即轻松搞定。因此开始的几天里也没怎么刻意着手这件事情。事实却是,等到我真正做了才发现随着问题的不断出现和为此而查阅许多相关的资料,花了那么多的时间与精力,做的过程还是如此的困难重重,并且做出来的东西也并非尽善尽美。方知许多事情并非都如人所想,不实践、不参与是无论如何也不会明白的。实践之重要正在于此!这段小小的经历使我感触很深,也教会我在以后的学习与工作中不要再眼高手低,任何事情都需亲自尝试后再做定断。牢记“眼之所见、心之所想非手之所为也!”
接下来再说着手前的准备。三国时诸葛亮草船借箭有赖“万事俱备,只欠东风”,而我的设计能顺利进行也必须有充足的准备作为后盾。只可惜在一开始的时候由于并不很重视因此也未意识到这一点,导致做的过程中停停找找、找找停停,严重影响了设计进度和效率,并且这种临阵磨枪式的做法也使得准备很不充分,往往是急需要用的东西找也找不到,如某控件类的方法如何使用、其原型或者参数的类型与意义为何等等。这样一来,自然会遇到重重困难。我想,如果在动手之前已经做好了充足准备,必然会少遇到很多麻烦,也不会一度出现举步维艰的情况。当然了,这次还只是一个小小的设计,如果换成是某个大型系统的设计岂不是无法想象?所以这次经历也算是给了我一个教训:千万不要打无准备的仗!早准备方保无虞。
说到了准备,也得说说做事过程中的坚持与细心谨慎。很难想象如果没有坚持到底的勇气和不懈的努力,当一个人面对困难时能迎难而上并一路坚持走下来。当初我选定这个设计课题时正是考虑到它简单、易完成(当然事实并非如此),不过后来做的时候不断出现新的问题,而且有些还是从理论上无法解释的,这时我就在想算了吧,这么难搞,还是换别的做。正好其他同学做的媒体播放器在网上找到了很多原原本本的源代码,因而做起来就不费吹灰之力。当时几乎就在一念之间转了方向,好在随后终于做成功了一部分功能。这点小小的成功让我体会到了自己动手的乐趣与成功后的喜悦,在此激励之下,幸而坚持了下来。回味其中的艰辛,尽享成功的喜悦,纵是雏鹰试翼之作,毕竟自己所为,比之其他同学照搬别人的代码以完成任务却不知到底做了什么、又有什么收获,不是更有意义吗?能够坚持即已成功一半。世上无难事,唯恐少坚持!
此外,在做的过程中不可能是一帆风顺的,必然免不了频繁出错。这一方面是由于输入时的粗心大意造成的,另一方面则是编写的代码本身的问题。对于前者,如果能在操作时做到细心谨慎,当然可以避免。即便免不了输入错误,在调试的过程中也应细心谨慎,惟其如此,方可免去许多麻烦,保证软件设计的质量与效率。由于要不断的调试,而VC6.0对于用户所作的改动会自动保存,因此就可能出现保存了修改后错误的结果,反而将前面做好的调试无误的内容覆盖掉的情况。如果没有时时保持细心谨慎的态度,及时对调试无误的结果加以保存,将可能遭遇前
功尽弃的“灭顶之灾”。不管怎样,时时处处细心谨慎,方保顺利无虞。我想,无论是治学还是工作或是为人,这
样的一种态度都是至关重要的。
由于是初次设计,仅凭自己一人之力是很难完成的,所以大家或借助于网络,或借助于参考书籍、期刊资料等。我也不例外,和几位同学一起研究设计方案及具体实现方法,并跑了好几趟图书馆,查资料,抄笔记,上网搜索资料,终于在大家的通力合作之下完成了这个项目。一起做的过程大家朝着一个共同的目标努力,分工协作,互相交流,提出不同的想法,不断完善,不断进步,一个一个的问题迎刃而解,一个一个的功能不断做出来。最后,集体的劳动终于换来了丰硕的成果(尽管并不完美)。这次经历使我懂得了团队合作精神的可贵。不仅如此,我觉得这次合作的过程真的是很愉快,很让人回味和怀念!我想将来参加工作后这种合作还会有,参与合作,倡导这种合作精神是很可贵和重要的。社会的进步使得人们面临的问题越来越复杂,迫使人们寻求集体的智慧、团队的力量来解决它们。个人的力量终究是有限的,也不可能独立完成所有的事情,每个人都有义务和必要学会与别人沟通、交流,学会合作,参与合作,在合作的过程中培养这样一种意识。对于将来的工作,这也是有重要意义的。
最后,值得一提的是编辑这份电子文稿,也使我学会了使用更多的Word功能。虽然不是本次设计的正题,但毕竟也算是一种收获吧。能够多学一点知识,总算也是一种成就。
设计的过程行将结束,一个个挑灯夜战、激烈讨论的夜晚也已过去。回顾整个过程,更清楚的认识到知识的欠缺,而自己所学的VC++知识只能算是皮毛,还有更多的东西需要我去研究,去掌握。尽管如此,我也不会退缩、停滞不前,因为通过这次设计实践,我已初识VC++的庐山真面目,并初步认识到了利用MFC丰富的类库及强大的功能编写应用软件的过程与方法。这才是最重要的。相信经过此次课程设计,日后将会有所改进。                                                   
 
 
参考文献
参考书籍:
严蔚敏. 《数据结构》( C语言版).北京: 清华大学出版社,1997年
薛超英. 《数据结构》.武汉:华中理工大学出版社,2000年
黄维通.《Visual C++面向对象与可视化程序设计(第2版)》北京:清华大学出版社,2003年
钱能. 《C++程序设计教程》北京:清华大学出版社,1999年
马德骏等.《C语言程序设计教程》北京:科学出版社,2002年
 
网上资料:
http://www.vckbase.com/document/viewdoc/?id=1094#CString转化成char*%20之一
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
附录
调试分析
调试1
 
可以看到游戏开始后,系统发牌有时会出现缺牌及发出背面牌的情况。
分析:由于向应用程序中导入的扑克牌资源其ID编号为1~37这些整数,而用于发牌的随机函数srand( (unsigned)time( NULL ) );for (int i=0;i<4;i++)suiji[i]=1+rand()%38;中是对38求余,则其产生的随机数在1~38之间,故当产生的随机数中有37时会发出一张背面牌,而当随机数中有38时则由于没有与之相对应的纸牌,故而会显示缺牌。
解决:将对38求余改为对36求余。调试无误后的结果为:
 
 
 
调试2
 
--------------------Configuration: 24点游戏 - Win32 Debug--------------------
 
Compiling...
24点游戏Dlg.cpp
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(175) : error C2374: 'hBmp1' : redefinition; multiple initialization
        D:\赵志刚\24点游戏\24点游戏Dlg.cpp(171) : see declaration of 'hBmp1'
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(179) : error C2374: 'hBmp1' : redefinition; multiple initialization
        D:\赵志刚\24点游戏\24点游戏Dlg.cpp(171) : see declaration of 'hBmp1'
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(184) : error C2374: 'hBmp1' : redefinition; multiple initialization
        D:\赵志刚\24点游戏\24点游戏Dlg.cpp(171) : see declaration of 'hBmp1'
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(471) : warning C4018: '<' : signed/unsigned mismatch
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(498) : warning C4018: '<' : signed/unsigned mismatch
Error executing cl.exe.
24点游戏Dlg.obj - 3 error(s), 2 warning(s)
分析:由于在做的时候相同的代码是直接拷贝过来的,而在调试之前忘了修改其位图句柄,故而出现上述错误。
解决:更改各段代码中的位图句柄。调试无误后的结果为:
--------------------Configuration: 24点游戏 - Win32 Debug--------------------
Compiling...
24点游戏Dlg.cpp
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(471) : warning C4018: '<' : signed/unsigned mismatch
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(498) : warning C4018: '<' : signed/unsigned mismatch
 
24点游戏Dlg.obj - 0 error(s), 2 warning(s)
调试3
--------------------Configuration: 24点游戏 - Win32 Debug--------------------
Compiling...
24点游戏Dlg.cpp
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(195) : error C2039: 'InsertColumn' : is not a member of 'CWnd'
 c:\program files\microsoft visual studio\vc98\mfc\include\afxwin.h(1899) : see declaration of 'CWnd'
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(198) : error C2039: 'InsertColumn' : is not a member of 'CWnd'
 c:\program files\microsoft visual studio\vc98\mfc\include\afxwin.h(1899) : see declaration of 'CWnd'
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(471) : warning C4018: '<' : signed/unsigned mismatch
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(498) : warning C4018: '<' : signed/unsigned mismatch
Error executing cl.exe.
24点游戏Dlg.obj - 2 error(s), 2 warning(s)
分析:由于为列表控件连接成员变量后出现了运行无结果显示的现象,故只得改用指针来做。此处利用强制类型转换(CListCtrl*)GetDlgItem(IDC_LIST1)->InsertColumn(0, &lvColumn);不成功,因此报错。
解决:将所有的强制类型转换代码修改为((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(0, &lvColumn);调试无误后的结果为:
--------------------Configuration: 24点游戏 - Win32 Debug--------------------
Compiling...
24点游戏Dlg.cpp
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(471) : warning C4018: '<' : signed/unsigned mismatch
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(498) : warning C4018: '<' : signed/unsigned mismatch
24点游戏Dlg.obj - 0 error(s), 2 warning(s)
调试4
 
可以看到,在重新发牌后编辑框中的算式并没有随之刷新,仍保留了上一次输入的内容。
分析:由于在代码中少添加了UpdateData(FALSE);以刷新屏幕,故而出错。
解决:添加UpdateData(FALSE);即可。调试无误后的运行结果为:
 
 
 
调试5
--------------------Configuration: 24点游戏 - Win32 Debug--------------------
Compiling...
24点游戏Dlg.cpp
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(268) : error C2039: 'SetSel' : is not a member of 'CString'
        c:\program files\microsoft visual studio\vc98\mfc\include\afx.h(368) : see declaration of 'CString'
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(269) : error C2039: 'ReplaceSel' : is not a member of 'CString'
   c:\program files\microsoft visual studio\vc98\mfc\include\afx.h(368) : see declaration of 'CString'
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(473) : warning C4018: '<' : signed/unsigned mismatch
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(500) : warning C4018: '<' : signed/unsigned mismatch
Error executing cl.exe.
24点游戏Dlg.obj - 2 error(s), 2 warning(s)
分析:由于为编辑框连接变量时将其设置成CString类而非CEdit类,故不能使用CEdit类的方法SetSel()和ReplaceSel()导致出错。
解决:利用字符串类,连接编辑框中输入的字符串及作为结束标识的“#”字符。调试无误后的结果为:
--------------------Configuration: 24点游戏 - Win32 Debug--------------------
Compiling...
24点游戏Dlg.cpp
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(473) : warning C4018: '<' : signed/unsigned mismatch
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(500) : warning C4018: '<' : signed/unsigned mismatch
24点游戏Dlg.obj - 0 error(s), 2 warning(s)
调试6
--------------------Configuration: 24点游戏 - Win32 Debug--------------------
Compiling...
24点游戏Dlg.cpp
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(473) : warning C4018: '<' : signed/unsigned mismatch
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(500) : warning C4018: '<' : signed/unsigned mismatch
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(559) : error C2601: 'OnBegin' : local function definitions are illegal
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(600) : error C2601: 'OnExit' : local function definitions are illegal
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(607) : error C2601: 'OnAbout' : local function definitions are illegal
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(615) : error C2601: 'OnButton4' : local function definitions are illegal
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(620) : fatal error C1004: unexpected end of file found
Error executing cl.exe.
24点游戏Dlg.obj - 5 error(s), 2 warning(s)
分析:经过仔细检查,发现是由于少了一个“}”所致。
解决:在指定位置加上“}”即可。调试无误后的结果为:
--------------------Configuration: 24点游戏 - Win32 Debug--------------------
Compiling...
24点游戏Dlg.cpp
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(473) : warning C4018: '<' : signed/unsigned mismatch
D:\赵志刚\24点游戏\24点游戏Dlg.cpp(500) : warning C4018: '<' : signed/unsigned mismatch
 
24点游戏Dlg.obj - 0 error(s), 2 warning(s)
附录2
测试结果
 
                首次运行后的界面                                      第一次发牌后的界面
 
计算正确后的界面                                     计算错误后的界面
 
输入操作数个数不为4时的错误提示                 输入数据不是所发牌点数时的错误提示
 
难度级别默认为“热身运动”                           难度级别选择为“智力比拼”
“当前得分:”记录累计游戏得分,“历史记录”显示游戏次数及对错信息
附录3
关键源代码
(1)       在构造函数CMy24Dlg(CWnd* pParent /*=NULL*/)及初始化函数OnInitDialog( )中添加如下代码:
 
//定义一个结构体变量lvItem
LV_ITEM  lvItem;
CMy24Dlg::CMy24Dlg(CWnd* pParent /*=NULL*/)
{
…………………………………………………………………………
//设置列表控件列属性                                            
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
lvItem.state = 0;     
lvItem.stateMask = 0; 
lvItem.iImage = 0;
…………………………………………………………………………
}
 
BOOL CMy24Dlg::OnInitDialog()
{
……………………………………………………………………
//初始化组合框
m_cb.InsertString(0,"智力比拼");        //为组合框添加子项
m_cb.InsertString(1,"热身运动");        //为组合框添加子项
m_cb.SetCurSel(1);                 //默认为“热身运动”
SetDlgItemText(IDC_STATIC7,"0");    //开始时得分为0
 
//设置列表控件风格
LV_COLUMN  lvColumn;           //定义一个结构体变量lvColumn                                      
lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvColumn.fmt = LVCFMT_CENTER;
lvColumn.cx = 52;
//设置列表控件列标题
lvColumn.iSubItem = 0;
lvColumn.pszText = "题数";
((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(0, &lvColumn);
lvColumn.iSubItem = 1;
lvColumn.pszText = "对错";
((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(1, &lvColumn);   //通过强制类型转换以获得列表控件的指针,并对它进行相关操作
 
//设置初始发牌显示为背面的纸牌
m_bmp1.ModifyStyle(0,SS_BITMAP);
HBITMAP hBmp1; hBmp1=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(37));
m_bmp1.SetBitmap(hBmp1);
 
m_bmp2.ModifyStyle(0,SS_BITMAP);
 
HBITMAP hBmp2; hBmp2=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(37));
m_bmp2.SetBitmap(hBmp2);
 
 
m_bmp3.ModifyStyle(0,SS_BITMAP);
HBITMAP hBmp3; hBmp3=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(37));
m_bmp3.SetBitmap(hBmp3);
 
m_bmp4.ModifyStyle(0,SS_BITMAP);
HBITMAP hBmp4; hBmp4=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(37));
m_bmp4.SetBitmap(hBmp4);
 
//设置进度条的初始位置为0,范围为0~100
CProgressCtrl *pProg=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);
pProg->SetRange(0,100);
pProg->SetPos(0);
……………………………………………………………………
}
 
2)OnButton1( )方法的实现代码
int suiji[4];
void CMy24Dlg::OnButton1()
{
// TODO: Add your control notification handler code here
GetDlgItem(IDC_BUTTON3)->EnableWindow(1);      //重新发牌时激活验算按钮3
CString s("");                                   //清除前一次输入的内容
m_edit=s;
UpdateData(FALSE);
 
//产生1~36之间的四个随机数,并存放在一个整型数组中
srand( (unsigned)time( NULL ) );//产生四个随即数
for (int i=0;i<4;i++)
suiji[i]=1+rand()%36;
   
m_bmp1.ModifyStyle(0,SS_BITMAP);               //显示第一张牌
HBITMAP hBmp1=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[0]));
m_bmp1.SetBitmap(hBmp1);
 
m_bmp2.ModifyStyle(0,SS_BITMAP);               //显示第二张牌
HBITMAP hBmp2=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[1]));
m_bmp2.SetBitmap(hBmp2);
 
m_bmp3.ModifyStyle(0,SS_BITMAP);              //显示第三张牌
HBITMAP hBmp3=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[2]));
m_bmp3.SetBitmap(hBmp3);
 
m_bmp4.ModifyStyle(0,SS_BITMAP);               //显示第四张牌
HBITMAP hBmp4=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[3]));
m_bmp4.SetBitmap(hBmp4);
CProgressCtrl *pProg=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);  //进度条开始记时pProg->SetPos(0);
SetTimer(1000,100,NULL);                        //步进时间设置为0.1秒
}
 
 
3)OnButton2( )方法的实现代码
void CMy24Dlg::OnButton2()
{
         // TODO: Add your control notification handler code here     
         KillTimer(1000);
}
 
4)OnButton3( )方法的实现代码
首先添加头文件:
#include <ctype.h>
#include <string.h>
#include "stdio.h"
然后添加方法的实现代码:
typedef struct                                            //表达式处理函数
{
 int top;
 double array[50];
}NumStack;
 
typedef struct
{
 int top;char array[50];
}OpStack;
 
int Cint(char mychar)
{
 return (mychar-48);
}
 
void PushNum(NumStack *numstack,double num)
{
 numstack->top++;
 numstack->array[numstack->top-1]=num;
}
 
void PopNum(NumStack *numstack,double *num)
{
 *num=numstack->array[numstack->top-1];
 numstack->top--;
}
void PushOp(OpStack *opstack,char op)
{
 opstack->top++;
 opstack->array[opstack->top-1]=op;
}
 
void PopOp(OpStack *opstack,char *op)
 
 
{
 *op=opstack->array[opstack->top-1];
 opstack->top--;
}
 
double Calc(double a,double b,char c)
{
 double result;
 switch(c)
 {
 case '+': result=a+b;break;
 case '-': result=a-b;break;
 case '*': result=a*b;break;
 case '/': result=a/b;break;
 }
 return result;
}
 
char Priority(char y,char x)
{
 char priority='<';
 switch(x)
 {
  case '+':
   case '-': if(y=='(' || y=='#')priority='>';break;
   case '*':
   case '/': if(y=='(' || y=='#'|| y=='+' || y=='-')priority='>';break;
   case '(': priority='>';break;
   case ')': if(y=='(')priority='=';break;
   case '#': if(y=='#')priority='=';break;
   default:   priority='E';
 }
 return priority;
}
void Process(NumStack *numstack,OpStack *opstack,char x)
{
double a,b;
char c;
static double tempnum=0.00000000;
static int len=10;
static int dot=0,flags=0;
if(isdigit(x) || x=='.')
 {
 if(x=='.') dot=1;
 else
 {
   if(dot==0) tempnum=tempnum*10+Cint(x);
   else
  
 
{
    tempnum=tempnum+(double)Cint(x)/len;
    len*=10;
   }
 }
 }
 
 else
 {
 if(flags==0&& x!='(') 
{
PushNum(numstack,tempnum);
tempnum=0.00000000;
len=10;dot=0;
}
 switch(Priority(opstack->array[opstack->top-1],x))
 {
   case '>': PushOp(opstack,x);flags=0;break;
   case '<': PopOp(opstack,&c);
                PopNum(numstack,&b);
           PopNum(numstack,&a);
           PushNum(numstack,Calc(a,b,c));flags=1;
           Process(numstack,opstack,x);break;
   case '=': PopOp(opstack,&c);flags=1;break;
   }
 }
}
 
int checkequ(int s[],int m[])       //判断编辑框中输入的数字是否为所发牌的点数
{
int a=0,b=0;
    for(int k=0;k<4;k++)
    {int qiuyu=s[k]%9;
     if(qiuyu==0) s[k]=9;
     else   s[k]%=9;
     }
for(int t=0;t<4;t++)//判断编辑框输入的每个数字能否都在随机数中找到与之相同的项 if(s[t]==m[0]||s[t]==m[1]||s[t]==m[2]||s[t]==m[3])
    a+=1;                               
for(int j=0;j<4;j++)//判断随机数中每个数字能否都与编辑框输入数据相匹配
    if(m[j]==s[0]||m[j]==s[1]||m[j]==s[2]||m[j]==s[3])
    b+=1;                                
if((a==4)&&(b==4))//对判断结果的处理,若一致则返回1值,否则返回0值
  return 1;
else
return 0;
}
 
CString input;    //定义一个字符串类
int proceed(LPCTSTR L)//验算输入计算式,若结果等于24则返回真值,否则为假,并提示
{
   NumStack numstack;OpStack opstack;int i=0;
   numstack.top=0;opstack.top=0;
   PushOp(&opstack,'#');
  for(i=0;i<strlen(L);i++)
     Process(&numstack,&opstack,L[i]);
if(numstack.array[numstack.top-1]==24)
      { AfxMessageBox("正确");input="正确";return 1;}
else
{AfxMessageBox("错误");input="错误";return 0;}
}
//为响应函数OnButton3()添加代码,判断操作数是否合乎要求,修改当前得分及历史记录
void CMy24Dlg::OnButton3()
{
         // TODO: Add your control notification handler code here
int m=0,i=0, shuju[100];
    CString biaoda;
    UpdateData(TRUE);
biaoda=m_edit;
biaoda=biaoda+"#";
    for(i=0;i<strlen(biaoda);i++)
       if((biaoda[i]>'0')&&(biaoda[i]<'10'))     //将输入字符串中的数字字符转换为整型数
         shuju[m++]=biaoda[i++]-'0';
    if(m!=4)                              //判断输入操作数个数是否合乎要求
          {
          AfxMessageBox("操作数个数不符");
          input="错误";
      GetDlgItem(IDC_BUTTON3)->EnableWindow(0);//个数不匹配,点按钮3后即被禁止
          }
   Else
{
            int r=checkequ(suiji,shuju);
if(r==1)
            {
int flag=proceed(biaoda);   
         if(flag)             //若计算式正确,则根据难度级别加分,修改当前得分记录
                    {
          defen+=jiafen;                                      
          CString str;
          str.Format("%d",defen);
          SetDlgItemText(IDC_STATIC7,str);
                    }
            }
       else
        AfxMessageBox("输入数据与所发牌不一致,游戏结束!");
        GetDlgItem(IDC_BUTTON3)->EnableWindow(0);// 防止刷分,点按钮3后即被禁止
   }
 
int  count=0; char s;
count+=1;       //根据程序运行结果修改历史记录
wsprintf(&s,"%d",count);
lvItem.iItem = count-1;
lvItem.iSubItem = 0;
lvItem.pszText = &s;
((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertItem(&lvItem);
((CListCtrl*)GetDlgItem(IDC_LIST1))->SetItemText(count-1, 1,input);
UpdateData(FALSE);
 
}
5)OnButton4( )方法的实现代码
void CMy24Dlg::OnButton4()
{
         // TODO: Add your control notification handler code here
         OnOK();
}
6)组合框消息处理函数OnSelchangeCombo1( )的实现方法
void CMy24Dlg::OnSelchangeCombo1()  
{
         // TODO: Add your control notification handler code here
         CString msg;
         m_cb.GetLBText(m_cb.GetCurSel(),msg);
         if(strcmp(msg,"智力比拼"))
         {       
sudu=1;jiafen=5;
}
         if(strcmp(msg,"热身运动"))
         {       
sudu=3;jiafen=10;
}
}
(7) “开始”菜单消息响应代码
void CMy24Dlg::OnBegin()
{
// TODO: Add your command handler code here
GetDlgItem(IDC_BUTTON3)->EnableWindow(1);
CString s("");
m_edit=s;
UpdateData(FALSE);
  
srand( (unsigned)time( NULL ) );
for (int i=0;i<4;i++)
suiji[i]=1+rand()%36;
   
m_bmp1.ModifyStyle(0,SS_BITMAP);
HBITMAP  hBmp1=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[0]));
m_bmp1.SetBitmap(hBmp1);
 
m_bmp2.ModifyStyle(0,SS_BITMAP);
HBITMAP  hBmp2=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[1]));
m_bmp2.SetBitmap(hBmp2);
 
m_bmp3.ModifyStyle(0,SS_BITMAP);
HBITMAP  hBmp3=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[2]));
m_bmp3.SetBitmap(hBmp3);
 
m_bmp4.ModifyStyle(0,SS_BITMAP);
HBITMAP hBmp4=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(suiji[3]));
m_bmp4.SetBitmap(hBmp4);
 
CProgressCtrl *pProg=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);
pProg->SetPos(0);
SetTimer(1000,100,NULL);  
}
 
(8) “退出”菜单消息响应代码
void CMy24Dlg::OnExit()
{
     // TODO: Add your command handler code here
     OnOK();
}
9)“关于”菜单消息响应代码
void CMy24Dlg::OnAbout()
{    // TODO: Add your command handler code here
     CAboutDlg dlg;
    dlg.DoModal();
}