收藏 分享(赏)

24点游戏程序设计.doc

上传人:sjmd695 文档编号:6759210 上传时间:2019-04-22 格式:DOC 页数:14 大小:252.50KB
下载 相关 举报
24点游戏程序设计.doc_第1页
第1页 / 共14页
24点游戏程序设计.doc_第2页
第2页 / 共14页
24点游戏程序设计.doc_第3页
第3页 / 共14页
24点游戏程序设计.doc_第4页
第4页 / 共14页
24点游戏程序设计.doc_第5页
第5页 / 共14页
点击查看更多>>
资源描述

1、杭州电子科技大学2012 年 6 月短学期姓名: 学号: 班级: 专业: 学院: 课题: 指导老师: 完成时间: 一、程序功能及规则设定本题目将设计一个 24 点游戏。程序主要负责实现随机发牌、设置牌面、表达式验算、计算机给出解答、结果统计等功能。系统可随机给出 4 个数,也可由用户自行输入四张牌的值。用户输入表达式,先判断表达式是否正确,如果正确,计算是否 24,不正确的话,给出可能的正确表达式。用户可放弃输入,由系统直接给出可能的答案24 点游戏是一种常见的纸牌游戏,就是利用加减乘除以及括号将给出的四张牌组成一个值为 24 的表达式,玩法十分简单,是一个消遣的好方法。本程序对传统 24 点

2、作了一定的改变,用户不必自己手动输入表达式,程序提供相应的按钮,通过点击按钮键入表达式,方便用户操作。二、程序实现思路通过一定的功能分析,将程序基本化为:随机发牌,设置牌面,退出游戏,表达式键入,表达式验证,系统给出答案,判断是否无解这 7 个功能模块。2.1 随机发牌: 产生 4 个随机数 rand() ,将 4 个数保存下来,对相应的按钮及图片做出对应的处理,即显示相对应的扑克牌、修改数字按钮上显示的数字、设置按钮的可用性等。这些处理写在主窗口的私有成员函数中,名为 startupCard() , 其中调用较多的 API 函数,如载入图片 loadImage() 、设置按钮内容 SetDl

3、gItemText()等。2.2 设置牌面: 用户自己设置扑克牌牌面(此时跳出一个设置窗口) ,获取用户输入的数字,其余操作与随机发牌操作相同,调用 startupCard()完成。2.3 退出游戏: 弹出关闭提示窗口,询问用户事故否确认退出。点击确定,则退出;点击取消,则返回,继续游戏。2.4 表达式键入: 设置 4 个数组、加、减、乘、除、左括号、右括号、清除、完成等按钮,并且一定时期某些按钮可用,某些按钮不可用。其规则如下:1)程序开始时,只有数字及左括号可用;2)当按下数字按钮时,加减乘除按钮可用,若前面输入过左括号,则右括号可用;3)当按下左括号时,只有未使用的数字可用;4)当按下加

4、减乘除时,未使用的数字及左括号可用;5)当按下右括号时,未使用的数字、加减乘除、右括号可用;6)当按下数字或右括号按钮,且数字都已经使用,左右括号匹配,此时完成按钮可用;7)清除按钮用于清除已键入的表达式。关于按钮可用性设置利用 EnableWindow()函数来实现。2.5 表达式验证: 即计算用户输入的表达式,首先获取表达式 GetDlgItemText() ,根据加减乘除运算法则,使用 C+ STL 库所提供的栈,进行表达式计算,验证用户输入的是否等于 24。算法思路:(1) 运算符的优先级处理。为根据运算符的优先级对表达式进行运算,引入优先级最低的运算符“;”,该运算符不参加实际的运算

5、,只出现在表达式的开始和最后,仅起到保证表达式的其他运算符运算完为止的作用。由此,规定运算符从低到高的优先级依次为:0 级:; ,1 级:) ,2 级:+和-, 3 级:*和/ , 4级:(。(2) 运算过程中的运算符和运算数的操作处理。在从左到右依次读入表达式字符串中字符的过程中,若遇到连续若干个数码字符就转换为数值,并将其入运算数栈;若遇到运算符,当该运算符的优先级高于运算符栈顶的运算符时,将该运算符入运算符栈,否则弹出运算数栈顶的两个元素依次作为右边和左边的运算数,弹出运算符栈顶的元素作为运算符进行运算,将结果入栈到运算数栈。但要注意以下情况: 读入的运算符) 不入运算符栈; 当运算符栈

6、顶是运算符(时,读入的运算符除) 外均入栈; 当读入的运算符是) 而运算符栈顶是(时,运算符栈退栈; 当读入的是运算数或是运算符而入栈了或是运算符) 而运算符栈顶是(时,继续读入下一字符,否则不能读入下一字符。(3) 比较运算符的优先级算法。根据存于一维数组中的运算符极其优先级,对运算符栈顶的运算符与读入的运算符比较其优先级,返回响应的信息。(4) 核心算法:完成表达式的求值并输出响应的操作及运算符栈和运算数栈的变化状态。对依次从表达式字符串读入的字符,若是数码字符,则将连续的若干个数码字符转换成数值后,入栈到运算数栈;否则,若是运算符且不是) :则当该运算符的优先级比运算符栈顶的运算符优先级

7、高或运算符栈顶的运算符是(时,该运算符入运算符栈,继续读入后续字符;否则,若是运算符且是) ,而运算符栈顶是(时,运算符栈退栈,继续读入后续字符;否则,弹出运算数栈顶的两个元素依次作为右边和左边的运算数,弹出运算符栈顶的元素作为运算符进行运算,将结果入栈到运算数栈,此时,如果当前运算符的优先级高于运算符栈顶元素的优先级,则当前运算符入运算符栈,继续读入后续字符,如果表达式已读完而且运算符栈已空,则继续读入后续字符。以上各种情况处理完后,均输出响应的操作及运算符栈和运算数栈的变化状态。最后返回表达式的运算结果运算数栈中唯一的一个数据。2.6 系统给出答案: 使用递归的方式,达到穷举的效果求 24

8、 点的解算法思路:首先,从宏观上说,这种问题都是遍历穷举。再看看运算符,其中+,* 都是没有顺序的。即(a*b=b*a), 但是 -、/ 是有顺序的。那么假设都有顺序的。那么就可以统一处理了(最多效率低点,先解决问题。再考虑优化) 。那么遍历所有 a,b,c,d以及 三次运算 。即 A(4,4) *4*4*4 就是该算法的复杂度。微观上,由于中间有除法,那么不能用 int 类型来储存数据了。需要用 double 或者float.每次运算都只有两个数运算。2.7 判断是否无解: 同样系统计算答案,判断有没有解三、程序流程图开始开始游戏 设置牌面 结束游戏结束随机产生 1-13 范围内的 4 个数

9、玩家输入 1-13 范围内的 4 个数初始化界面,包括按钮、图片等等待玩家输入表达式 放弃玩家认为有解玩家认为无解判断表达式是否正确等待用户输入表达式是否提示正确判断是否无解提示正确是 提示错误否重新开始显示结果四、程序调试4.1 图片显示:图片导入难以实现,不断修改、查阅信息、修改完成。4.2 表达式求值算法:计算结构有误。原因为运算符优先级设置不正确,如加号和减号的优先级相同,乘号和除号的优先级相同。4.3 按钮可用性设定:不可连续输入括号,如:(6+6)+6)+6,是正确的解,但是无法输入,修改了按钮可用性设定的规则:当按下左括号时,左括号仍可用,并且,四个数字都使用了以后,系统自动完成

10、括号匹配的工作。4.4 有待改进的地方:程序经常出现闪屏现象,可以增加定时、难度级别设置的功能。五、部分截图5.1 主界面:5.2 设置牌面:5.3 退出游戏:六、部分关键代码(完整请见 poin24 工程)/*计算表达式*/int calculate(CString /将 CString 转换成 string 类型str+=“;“; /添加分号,作为表达式结束stack Sign;/运算符栈stack Num; /数字栈Sign.push(;); /分号压入栈底int pos = 0; /从 0 号为开始读取表达式char current = str0, topSign; /当前字符whil

11、e(Sign.top() != ; | current != ;)int num = apartNum(str,pos);/拆分数字与字符if(num != -1) /读取出数字,添加到数字栈中Num.push(num);else /读取出运算符current = strpos; /当前字符pos+; /继续下次循环topSign = Sign.top();/得到当前栈顶的运算符if(current = ) /直接弹出左括号else if(current != ) /将当前运算符压栈elseint a,b,c;a = Num.top(); /得到数字栈栈顶元素Num.pop();b = Num

12、.top(); /得到第二个数字Num.pop();topSign = Sign.top(); /弹出运算符Sign.pop();if(topSign = +) c = a + b; /加法else if(topSign = -) c = b - a; /减法else if(topSign = *) c = a * b; /乘法else if(topSign = /) c = b / a; /除法else return -1;Num.push(c); /将新的数存入数字栈中topSign = Sign.top(); /得到符号栈栈顶运算符pos-;/向前退一个,继续操作当前的运算符curren

13、t = strpos; /下一轮的当前字符return Num.top();/*系统计算 24 点的解*/bool search(int n, int* number, string* expression) if (n = 1) if ( fabs(number0 - 24) GetWindowText(expression);GetDlgItem(IDC_NUMONE)-GetWindowText(num);/获取当前输入的数字expression += num; /将新输入的数字添加到表达式中SetDlgItemText(ID_EXPRESSION, expression);/将新表达式

14、显示到文本框中if(!allVisited()GetDlgItem(IDC_ADD)-EnableWindow(TRUE); GetDlgItem(IDC_SUB)-EnableWindow(TRUE); GetDlgItem(IDC_MUL)-EnableWindow(TRUE); GetDlgItem(IDC_DIV)-EnableWindow(TRUE); elsefor(int i = 0; i EnableWindow(TRUE); /完成按钮可用GetDlgItem(IDC_NUMONE)-EnableWindow(FALSE);/数字按钮不可用GetDlgItem(IDC_NUM

15、TWO)-EnableWindow(FALSE); GetDlgItem(IDC_NUMTHREE)-EnableWindow(FALSE); GetDlgItem(IDC_NUMFOUR)-EnableWindow(FALSE); GetDlgItem(IDC_LEFTBRACKET)-EnableWindow(FALSE); /左括号不可用if(m_leftCnt 0) /前面出现过左括号,则右括号可用GetDlgItem(IDC_RIGHTBRACKET)-EnableWindow(TRUE); /*按下加减乘除键时,表达式相关的按钮的可用性的设置*/void CPoint24Dlg:O

16、nAdd() /加号CString expression, sign; /获取已输入的表达式GetDlgItem(ID_EXPRESSION)-GetWindowText(expression);GetDlgItem(IDC_ADD)-GetWindowText(sign); /获取新输入的运算符expression += sign; /将新输入的运算符添加到表达式中SetDlgItemText(ID_EXPRESSION, expression);/将新表达式显示到文本框中if(!m_visitNum0) / /未使用的数字按钮可用GetDlgItem(IDC_NUMONE)-EnableW

17、indow(TRUE); if(!m_visitNum1)GetDlgItem(IDC_NUMTWO)-EnableWindow(TRUE); if(!m_visitNum2)GetDlgItem(IDC_NUMTHREE)-EnableWindow(TRUE); if(!m_visitNum3)GetDlgItem(IDC_NUMFOUR)-EnableWindow(TRUE); GetDlgItem(IDC_LEFTBRACKET)-EnableWindow(TRUE); /左括号可用GetDlgItem(IDC_RIGHTBRACKET)-EnableWindow(FALSE); /右括

18、号不可用GetDlgItem(IDC_ADD)-EnableWindow(FALSE); /运算符不可用GetDlgItem(IDC_SUB)-EnableWindow(FALSE); GetDlgItem(IDC_MUL)-EnableWindow(FALSE); GetDlgItem(IDC_DIV)-EnableWindow(FALSE); /*按下左括号键时,表达式相关的按钮的可用性的设置*/void CPoint24Dlg:OnLeftbracket() /左括号CString expression, sign;GetDlgItem(ID_EXPRESSION)-GetWindowT

19、ext(expression); /获取已输入的表达式GetDlgItem(IDC_LEFTBRACKET)-GetWindowText(sign); /获取新输入的运算符expression += sign;/将新输入的运算符添加到表达式中SetDlgItemText(ID_EXPRESSION, expression); /将新表达式显示到文本框中m_leftCnt +; /左括号计数器加 1if(!m_visitNum0)GetDlgItem(IDC_NUMONE)-EnableWindow(TRUE);/未使用的数字按钮可用if(!m_visitNum1)GetDlgItem(IDC_

20、NUMTWO)-EnableWindow(TRUE); if(!m_visitNum2)GetDlgItem(IDC_NUMTHREE)-EnableWindow(TRUE); if(!m_visitNum3)GetDlgItem(IDC_NUMFOUR)-EnableWindow(TRUE); GetDlgItem(IDC_LEFTBRACKET)-EnableWindow(TRUE); /左括号可用GetDlgItem(IDC_RIGHTBRACKET)-EnableWindow(FALSE); /右括号不可用GetDlgItem(IDC_ADD)-EnableWindow(FALSE);

21、 /运算符不可用GetDlgItem(IDC_SUB)-EnableWindow(FALSE); GetDlgItem(IDC_MUL)-EnableWindow(FALSE); GetDlgItem(IDC_DIV)-EnableWindow(FALSE); /*按下右括号键时,表达式相关的按钮的可用性的设置*/void CPoint24Dlg:OnRightbracket() /右括号CString expression, sign;GetDlgItem(ID_EXPRESSION)-GetWindowText(expression); /获取已输入的表达式GetDlgItem(IDC_R

22、IGHTBRACKET)-GetWindowText(sign); /获取新输入的运算符expression += sign;/将新输入的运算符添加到表达式中SetDlgItemText(ID_EXPRESSION, expression); /将新表达式显示到文本框中m_leftCnt -;GetDlgItem(IDC_NUMONE)-EnableWindow(FALSE);/数字按钮不可用GetDlgItem(IDC_NUMTWO)-EnableWindow(FALSE); GetDlgItem(IDC_NUMTHREE)-EnableWindow(FALSE); GetDlgItem(I

23、DC_NUMFOUR)-EnableWindow(FALSE); GetDlgItem(IDC_LEFTBRACKET)-EnableWindow(FALSE); /左括号不可用if(m_leftCnt 0)GetDlgItem(IDC_RIGHTBRACKET)-EnableWindow(FALSE); /前面出现过左括号,则有括号可用GetDlgItem(IDC_ADD)-EnableWindow(TRUE); GetDlgItem(IDC_SUB)-EnableWindow(TRUE); GetDlgItem(IDC_MUL)-EnableWindow(TRUE); GetDlgItem

24、(IDC_DIV)-EnableWindow(TRUE); if(allVisited() /完成按钮可用/*开始设置*/void CPoint24Dlg:startupCard() /修改数字按钮上的显示信息m_leftCnt = 0; /左括号计数器为 0SetDlgItemText(ID_EXPRESSION, “); /清空表达式栏GetDlgItem(IDC_NUMONE);SetDlgItemText(IDC_NUMONE, m_buff0); /将数字显示到按钮中SetDlgItemText(IDC_NUMTWO, m_buff1); SetDlgItemText(IDC_NUM

25、THREE, m_buff2); SetDlgItemText(IDC_NUMFOUR, m_buff3);fill(m_visitNum, m_visitNum+4, false); /访问标志初始化为:未访问GetDlgItem(IDC_NUMONE)-EnableWindow(TRUE);/数字按钮可用GetDlgItem(IDC_NUMTWO)-EnableWindow(TRUE); GetDlgItem(IDC_NUMTHREE)-EnableWindow(TRUE); GetDlgItem(IDC_NUMFOUR)-EnableWindow(TRUE); GetDlgItem(ID

26、C_GIVEUP)-EnableWindow(TRUE); /放弃按钮可用GetDlgItem(IDC_NOANSWER)-EnableWindow(TRUE);/无解按钮可用GetDlgItem(IDC_COMPLETE)-EnableWindow(FALSE);GetDlgItem(IDC_LEFTBRACKET)-EnableWindow(TRUE);CPaintDC pDC(this);CRect rect;CBitmap card4,*OldBitMap;CDC *dc,dcMem;dc=GetDC();for(int i = 0; iBitBlt(20+100*i,20,500,1

27、000,BITMAP bm; (dc-StretchBlt( 25+108*i, 20, 105, 175, dcMem.SelectObject(OldBitMap);DeleteObject(dcMem.DeleteDC();/*无解按钮的响应事件*/void CPoint24Dlg:OnNoanswer() / TODO: Add your control notification handler code herem_totalCnt +;string expression4;for(int i = 0; i 13 | temp0 13 | temp1 13 | temp2 13 |

28、temp3 1 )AfxMessageBox(“输入的数字必须在 1-13 之间n 存在非法数字,请重新输入!“);continue;/输入数字不合法,重新输入else break; /数字合法,结束循环elsereturn;setCardNum(setNumberdDlg.getOp();/设置扑克的值/*放弃按钮响应事件*/void CPoint24Dlg:OnGiveup() m_totalCnt +;m_giveupCnt +;string expression4;for(int i = 0; i 4; i+) /把十进制的 x 转换成 String 类型expressioni = m

29、_buffi; if(search(4, m_op, expression) /24 点求解CString str;str.Format(“%s“, expression0.c_str();/格式化str += “ = 24 “;AfxMessageBox(“答案为:“ + str + “n 重新开牌“);elseAfxMessageBox(“此局无解!重新开牌.“);displayCnt(); /显示统计信息startupCard();七、个人总结在本次编程实训中,主要学习了两个算法,一个是算术表达式的求值,另一个是四个数的 24 点求解。中间有许多细节的部分容易被忽略,从而导致进度减慢。在使用 MFC 时,许多 API 函数都比较陌生,边查阅使用方法,边进行程序的编写,尤其在载入图片上,花了比较大的功夫,用了网上提供的很多方法都不适用,最终将图片导入工程、加载、显示,达到了预期的效果。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报