收藏 分销(赏)

综合实例_猜纸牌游戏.doc

上传人:pc****0 文档编号:7173696 上传时间:2024-12-27 格式:DOC 页数:17 大小:176.50KB 下载积分:10 金币
下载 相关 举报
综合实例_猜纸牌游戏.doc_第1页
第1页 / 共17页
综合实例_猜纸牌游戏.doc_第2页
第2页 / 共17页


点击查看更多>>
资源描述
综合实例——猜纸牌游戏 问题描述: 该游戏使用52张扑克牌,黑桃、红桃、方片和梅花各13张(A、2,3,4,…,10,J,Q,K)。游戏规则为:计算机随机抽取8张纸牌,以背面显示在屏幕上。使用者可使用鼠标左键单击翻看某张纸牌(最多翻看8张次,看下张牌时以前翻开的牌会自动翻回去)。从翻开第一张牌时开始计时,10秒钟后自动弹出一个对话框,其中显示下列问题之一,并可接受使用者的回答: 这八张牌中有几张是红桃(黑桃,方块,梅花)? 这八张牌中红桃(黑桃,方块,梅花)的点数(A=1,J=Q=K=0)之和是多少? 这八张牌中红桃(黑桃,方块,梅花)的大牌(J,Q,K,A)共几张? 这八张牌中共有几张大牌(J,Q,K,A)? 如果回答正确,则在总分上加10分;否则扣10分。此时游戏会将所有纸牌翻到正面,供使用者复查。 再单击鼠标左键则重新发牌开始新的一局。 编程要求: (1)扑克牌显示正确,比例恰当。所有牌的背面应有统一的花纹,牌面可使用简化方法显示,即在牌中央显示一个表示花色的图案(黑桃、红桃、梅花和方片,应使用位图资源),牌面左上角显示点数(2~10,J,Q,K,A)。黑桃和梅花用黑色,红桃和方片用红色。在屏幕上分两行共显示8张纸牌,每行4张。 (2)在适当位置显示提示信息,包括已进行的局数、当前得分、当前剩余时间和已翻开的纸牌张数。 (3)用鼠标左键单击某张纸牌可将其翻转(正面变反面或反面变正面)。在一局中最多可翻开8张牌。 (4)第一次单击鼠标左键时开始计时,10秒钟后自动弹出一对话框用于提问和接受使用者的回答。要求对话框设计美观大方,尺寸合理。对话框下方有一个编辑控件(设置为数值属性),用于输入用户的回答。 (5)对话框上能正确显示问题,而具体显示哪个题目,题目中是什么花色或什么大牌均应随机确定。 (6)用户回答问题后将所有纸牌翻为正面,用户再次单击鼠标左键后开始新的一局。 要点分析: 本题主要涉及到的知识点有:鼠标消息、对话框、定时器消息、位图显示、随机函数的使用,同时还有数值和字符串之间的转换,位图显示位置的计算以及较多的逻辑判断工作,涉及的内容较多,难度较大。 该题的难点在于纸牌的显示、纸牌产生的随机性以及提问问题的产生和判断等。 纸牌的背面可以用一个位图显示,而显示正面较为复杂,因为有52张不同的牌,如果使用52个不同的位图表示,工作量就太大了。这里把显示纸牌的正面分成两个部分,首先用四个位图表示四种不同花色的纸牌,然后用A、2~10、J、Q、K在位图的左上角显示表示不同的点,从而显示出一个完整的纸牌正面。 这里给出的随机产生纸牌的算法非常简单,即用0~51这52个整数来表示纸牌,也就是说,0~12表示梅花A~K、13~25表示方块A~K,26~38表示红桃A~K,39~51表示黑桃A~K。这样,表示纸牌的整数对13取模就得到纸牌的花色(0~3分别表示梅花、方块、红桃和黑桃),除以13得到的余数就是纸牌的点数。 问题和答案通过一个对话框表示出来,而相关的操作则都在定时器消息处理函数中进行。问题的产生涉及到两个随机数,一个产生问题的类型,一个产生问题中纸牌的花色,而相关问题的正确答案在纸牌产生时就已经计算出来,就等着根据不同的问题和答题分蘖节 的答案进行判断了。   解题步骤: (1)首先用AppWizard生成一个名为PuzzleCard的SD1程序框架,各选项均可用缺省设置。 (2)使用Developer Studio菜单的Insert / Resource…选项调出Insert Source对话框,为项目添加5个位图资源,分别表示纸牌的背面和四种花色纸牌的正面。相应位图的资源ID分别为IDB_BACK、IDB_CLUB、IDB_DIAMOND、IDB_HEART和IDB_SPADE。 (3)使用Developer Studio菜单的Insert / Resource…选项调出Insert Source对话框,为项目添加一个对话框模板资源。 (4)修改对话框模板的标识符ID为IDD-QUESTION,适当调整其大小,并在其上添加两个静态文本控件,其中表示问题的文本近代件ID改为IDC_Question, Caption改为空;另一个静态文本控件的Caption改“答案”。添加一个编辑控件,ID改为IDC_Answer。 (5)利用ClassWizard自动建立对话框类。用Ctrl+W键可直接调出ClassWizard,也可以通过Developer Studio菜单的View/ClassWizard…选项调出。进入ClassWizard后,它会发现已建立的对话框模板资源,并弹出一个对话框询问是否要为该对话框模板建立类。按下“OK”按钮,会弹出New Class对话框,在Name栏填写对话框类的名称CQuestion后按“OK”按钮即可为对话框创建出一个对应的类。 (6)利用ClassWizard为对话框类添加与各控件对应的数据成员。选择MemberVariables选项卡,确保Class Name项为对话框CQuestion类,然后在选项卡下方的窗口中选择各近代件的ID并按下“Add Variable…”按钮,为其添加对应成员变量,如下表4所示。   表4  对话框类中与各控件对应的成员变量 Control IDs Variable Type Member variable name IDC_Answer int m_nAnser IDC_Question CString m_strQuestion (7)为视图类添加一个新的成员函数Initial ( ),无返回值和参数。 (8)用ClassWizard在视图类中建立定时器处理函数OnTimer ( )。 (9)用ClassWizard在视图类中建立鼠标左键消息处理函数OnLButtonDown ( )。 (10)完成以上工作后,即可修改程序框架,添加必要的代码。 源程序清单: 为简化编程,本题的所有数据都在视图类中声明,代码也都在视图中编写,无需对其他类进行操作。 在视图类的头文件中加入以下变量定义: class CPuzzleCardView: public CView { //此处略去若干行由系统生成的代码 public:   bool m_bStart;   bool m_bFirstClick;//第一次翻纸牌   int m_nBigNum[4];//各花色大牌数   int m_nTotalPoint[4];//各花色点数和   int m_nCardCount[4];//各花色牌数   int m_nTotalBigNum;//大牌数   CString m_strInfor;//游戏状态   int m_nGameNum;//局数   int m_nMark;//得分   int m_nRemTime;//剩余时间   int m_nCardNum;//翻过纸牌的数目   CRect m_rectInfo;//游戏状态显示我间   int m_nCard[8];//用整数0~51表示52张牌   bool m_bCardFace[8];//桌面纸牌是否显示正面   CBitmap m_bmCardFace[4], m_bmCardBack;//纸牌的位图   int m_nCard, m_nCardh;//纸牌位图的尺寸 }; 在视图类cpp文件的最前面添加以下代码: #include〃Question. h〃 在视图类构造函数中添加以下初始化代码: CPuzzleCardView :: CPuzzleCardView ( ) {  //载入纸牌的位图资源   m_bmCardFace[0]. LoadBitmap (IDB_CLUB);   m_bmCardFace[1]. LoadBitmap (IDB_DIAMOND);   m_bmCardFace[2]. LoadBitmap (IDB_HEART);   m_bmCardFace[3]. LoadBitmap (IDB_SPADE);   m_bmCardBack. LoadBitmap (IDB_BACK);  //计算纸牌位图的高和宽   BITMAP bmCard;   m_bmCardBack. GetBitmap (&bmCard);   m_nCardw = bmCard. bmWidth;   m_nCardh = bmCard. bmHeight;   m_rectInfo = CRect (49, 454, 797, 500);   m_nGameNum = 1;            //局数   m_nMark = 100;              //得分   Initial ( ); }   在视图类的OnDraw( )成员函数中添加以下代码: void CPuzzleCardView :: OnDraw (CDC * pDC) {   CPuzzleCardDoc * pDoc = GetDocument ( );   ASSERT_VALID (pDoc);   CDC memDC[8];   CBitmap * pOldDC;   for (int i=0; i<8; i++) {   int nTopLeftx, nTopLefty;        //纸牌左上角坐标   CString strNum;   nTopLeftx = 50 + i% 4 * (m_nCardw + 20);   nTopLefty = 50 + i/4 * (m_nCardh + 20);   memDC[i]. CreateCompatibleDC (NULL);   if (m_bCardFace [i])   { //显示正面      pOldDC = memDC [i]. SelectObject (&m_bmCardFace [m_nCard [i] / 13]);      switch (m_nCard [i] % 13)      {      case 0:          strNum = 〃A〃;          break;      case 10:          strNum = 〃J〃;          break;      case 11:          strNum = 〃Q〃;          break;      case 12:          strNum = 〃K〃;          break;      default:          strNum. Format (〃%d〃, m_nCard [i] % 13 + 1);      }    }   //显示背面    else pOldDC = memDC [i]. SelectObject (&m_bmCardBack);    pDC - > BitBlt (nTopLeftx, nTopLefty, m_nCardw, m_nCardh, &memDC [i], 0, 0, SRCCOP  Y);          memDC [i]. SelectObject (pOldDC);          pDC - > TextOut (nTopLeftx + 10),              nTopLefty + 10, strNum);            //显示纸牌点数           }           CString strInfo;          strInfo. Format (〃局数: % d得分: % d剩余时间: % d已翻开纸牌数: % d〃,               m_nGame.Num, m_nMark, m_nRemTime, m_nCardNum);          pC - > TextOut (50, 460, strInfo);       //显示游戏状态       }   鼠标、定时器消息处理函数的代码如下: void CPuzzleCardView :: OnLButtonDown (UINT nFlags, CPoint point) {   int nTopLeftx, nTopLefty;         //纸牌左上角坐标   int nCardFace = -1;   CRect rectCard;                 //当前点中的纸牌   CRect rectCardFace;             //前一次翻开的纸牌   int i = 0;   if (m_bStart)   {     if (m_nCardNum > 7)         return;     if (m_bFirstClick)     {  //第一次翻开,开始计时         SetTimer (1, 1000, NULL);         m_bFirstClick = false;     }     while (i < 8) //找出前一次翻开的纸牌     {       if (m_bCardFace [i])       {         nCardFace = i;         nTopLeftx = 50 +i % 4 * (m_nCardw + 20);         nTopLefty = 50 + i / 4 * (m_nCardh + 20);         rectCardFace = CRect (nTopLeftx, nTopLefty, nTopLeftx + m_nCardw, nTopLefty + m_nCardh);             break;            }            i + +;         }         for (i=0; i<8; i + +)         //找出当前点中的纸牌翻开         {            nTopLeftx = 50 +i % 4 * (m_nCardw + 20);            nTopLeftx = 50 + i / 4 * (m_nCardh + 20);            rectCard = CRect (nTopLeftx, nTopLefty, nTopLeftx + m_nCardw, nTopLefty + m_nCardh);            if (rectCard. PtInRect (point))            {               if (nCardFace ! = -1)               {                  m_bCardFace [nCardFace] = false;                  InvalidateRect (rectCardFace);               }               m_bCardFace [i] = true;               m_nCardNum + +;               InvalidateRect (rectCard);               InvalidateRect (& m_rectInfo);               break;            }          }        }        else        {   //重新开始             Initial ( );             m_nGameNum + +;             Invalidate ( );        }        CView :: OnLButtonDown (nFlags, point)      }      void CPuzzleCardView :: OnTimer (UINT nIDEvent)      {         m_nRemTime - -;         InvalidateRect (& m_rectInfo);         if (m_nRemTime = = 0)           //时间到,开始提问         {             KillTimer (1);             for (int i=0; i<8; i + +)                 m_bCardFace [i] = false;    //所有纸牌翻回背面             Invalidae ( );             CQuestion dlgQuestion;             int nCardType;             int nQuestionType;             int nAnswer;             CString strCardType;             srand ((unsigned) time (NULL));             nCardType = rand ( ) % 4;       //随机产生纸牌花色             switch (nCardType)             {             case 0:                 strCardType = 〃梅花〃;                 break;             case 1:                 strCardType = 〃方块〃;                 break;             case 2:                 strCardType = 〃红桃〃;                 break;             case 3:                 strCardType = 〃黑桃〃;             }             nQuestionType = rand ( ) % 4;          //随机产生问题             switch (nQuestionType)             {//根据问题类型构造问题字符串,得到正确答案             case 0:                 digQuestion. m_strQuestion. Format                      (〃问题:这八张牌中有几张是% s ?〃, strCardType);                 nAnaswer = m_nCardCount [nCardType];                 break;             case 1:                 dlgQuestion. m_strQuestion. Format                     (〃问题:这八张牌中% s的点数(A=1, J=Q=k=0)之和是多少?〃,                     strCardType);                 nAnswer = m_nTotalPoint [nCardType];                 break;             case 2:                 dlgQuestion. m_strQuestion. Format                    (〃问题:这八张牌中% s大牌(J, Q, K, A)共几张?〃, strCardType);                 nAnswer = m_nBigNum [nCardType];                 break;             case 3:                 dlgQuestion. m_strQuestion. Format                    (〃问题:这八张牌中共有几张大牌(J, Q, K, A)?〃);                 nAnswer = m_nTotalBigNum;             }             if (dlgQuestion. DoModal ( ) = = IDOK)             {                if (dlgQuestion. m_nAnswer = = nAnswer)                {                    m_nMark + = 10;                }                else                {                    m_nMark - = 10;                }            }           for (i=0; i<8; i + +)//所有纸牌翻开                 m_bCardFace [i] = true;            m_bStart = false;            Invalidate ( );          }          CView :: OnTimer (nIDEvent);      } 初始化函数代码如下: void CPuzzleCardView :: Initial ( ) {   srand ( (unsigned) time (NULL) );   for (int i=0; i < 4; i + +)   {     m_nCardCount [i] = 0;     m_nTotalPoint [i] = 0;         m_nBigNum[i]=0;   }   m_nTotalBigNum = 0;   m_nRemTime = 10;//初始时间10s   m_nCardNum = 0;   m_bFirstClick = true;   m_bStart = true;   for (i =0; i < 8; i + + )   {/ /随机产生8张纸牌,计算问题答案      m_bCardFace [i] = false;      m_nCard [i] = rand ( ) % 52;      int nType = m_nCard [i] / 13;      int nPoint = m_nCard [i] % 13 + 1;      m_nCardCount [nType] + +;      if (nPoint > 10)      {         nPoint = 0;         m_nBigNum [nType] + +;         m_nTotalBigNum + +;      }      if (nPoint = = 1)      {         m_nBigNum [nType] + +;         m_nTotalBigNum + +;      }      m_nTotalPoint [nType] + = nPoint;    } } 输入输出: 游戏开始时显示8张纸牌的背面,用户可以使用鼠标左键翻看点中的纸牌,同时以前翻开的牌自动翻回去,如下图1、2、3所示。每次游戏最多可以翻看8张次;系统在用户翻开第一张牌后开始计时,10秒钟后自动弹出一个对话框,其中显示一个问题。若使用者回答正确,则在总分上加10分;否则扣10分。此时游戏会将所有纸牌翻到正面,供使用者查看。   图1  翻开一张牌   图2  提问对话框 图3  最终结果图   小结: 本题的题解多处使用到随机函数,附带介绍了使用整型数表示其他信息的方法。同时,通过显示纸牌的正面,也可以了解显示较为复杂的图案的方法。
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 百科休闲 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服