1、24点游戏是一种常见的纸牌游戏,就是利用加减乘除以及括号将给出的四张牌组成一个值为24的表达式,玩法十分简单,是一个消遣的好方法。本程序对传统24点作了一定的改变,用户不必自己手动输入表达式,程序提供相应的按钮,通过点击按钮键入表达式,方便用户操作。二、程序实现思路 通过一定的功能分析,将程序基本化为:随机发牌,设置牌面,退出游戏,表达式键入,表达式验证,系统给出答案,判断是否无解这7个功能模块。1 2 2.1 随机发牌: 产生4个随机数rand(),将4个数保存下来,对相应的按钮及图片做出对应的处理,即显示相对应的扑克牌、修改数字按钮上显示的数字、设置按钮的可用性等。这些处理写在主窗口的私有
2、成员函数中,名为startupCard(), 其中调用较多的API函数,如载入图片loadImage()、设置按钮内容SetDlgItemText()等。2.2 设置牌面: 用户自己设置扑克牌牌面(此时跳出一个设置窗口),获取用户输入的数字,其余操作与随机发牌操作相同,调用startupCard()完成。2.3 退出游戏: 弹出关闭提示窗口,询问用户事故否确认退出。点击确定,则退出;点击取消,则返回,继续游戏。2.4 表达式键入: 设置4个数组、加、减、乘、除、左括号、右括号、清除、完成等按钮,并且一定时期某些按钮可用,某些按钮不可用。其规则如下:1)程序开始时,只有数字及左括号可用;2)当按
3、下数字按钮时,加减乘除按钮可用,若前面输入过左括号,则右括号可用;3)当按下左括号时,只有未使用的数字可用;4)当按下加减乘除时,未使用的数字及左括号可用;5)当按下右括号时,未使用的数字、加减乘除、右括号可用;6)当按下数字或右括号按钮,且数字都已经使用,左右括号匹配,此时完成按钮可用;7)清除按钮用于清除已键入的表达式。关于按钮可用性设置利用EnableWindow()函数来实现。2.5 表达式验证: 即计算用户输入的表达式,首先获取表达式GetDlgItemText(),根据加减乘除运算法则,使用C+ STL库所提供的栈,进行表达式计算,验证用户输入的是否等于24。算法思路:(1) 运算
4、符的优先级处理。为根据运算符的优先级对表达式进行运算,引入优先级最低的运算符“;”,该运算符不参加实际的运算,只出现在表达式的开始和最后,仅起到保证表达式的其他运算符运算完为止的作用。由此,规定运算符从低到高的优先级依次为:0级:;,1级:),2级:+和-, 3级:*和/, 4级:(。(2) 运算过程中的运算符和运算数的操作处理。在从左到右依次读入表达式字符串中字符的过程中,若遇到连续若干个数码字符就转换为数值,并将其入运算数栈;若遇到运算符,当该运算符的优先级高于运算符栈顶的运算符时,将该运算符入运算符栈,否则弹出运算数栈顶的两个元素依次作为右边和左边的运算数,弹出运算符栈顶的元素作为运算符
5、进行运算,将结果入栈到运算数栈。但要注意以下情况: 读入的运算符)不入运算符栈; 当运算符栈顶是运算符(时,读入的运算符除)外均入栈; 当读入的运算符是)而运算符栈顶是(时,运算符栈退栈; 当读入的是运算数或是运算符而入栈了或是运算符)而运算符栈顶是(时,继续读入下一字符,否则不能读入下一字符。(3) 比较运算符的优先级算法。根据存于一维数组中的运算符极其优先级,对运算符栈顶的运算符与读入的运算符比较其优先级,返回响应的信息。(4) 核心算法:完成表达式的求值并输出响应的操作及运算符栈和运算数栈的变化状态。对依次从表达式字符串读入的字符,若是数码字符,则将连续的若干个数码字符转换成数值后,入栈
6、到运算数栈;否则,若是运算符且不是):则当该运算符的优先级比运算符栈顶的运算符优先级高或运算符栈顶的运算符是(时,该运算符入运算符栈,继续读入后续字符;否则,若是运算符且是),而运算符栈顶是(时,运算符栈退栈,继续读入后续字符;否则,弹出运算数栈顶的两个元素依次作为右边和左边的运算数,弹出运算符栈顶的元素作为运算符进行运算,将结果入栈到运算数栈,此时,如果当前运算符的优先级高于运算符栈顶元素的优先级,则当前运算符入运算符栈,继续读入后续字符,如果表达式已读完而且运算符栈已空,则继续读入后续字符。以上各种情况处理完后,均输出响应的操作及运算符栈和运算数栈的变化状态。最后返回表达式的运算结果运算数
7、栈中唯一的一个数据。2.6 系统给出答案: 使用递归的方式,达到穷举的效果求24点的解 算法思路:首先,从宏观上说,这种问题都是遍历穷举。再看看运算符,其中+,* 都是没有顺序的。即(a*b=b*a), 但是 -、/ 是有顺序的。那么假设都有顺序的。那么就可以统一处理了(最多效率低点,先解决问题。再考虑优化)。那么遍历所有a,b,c,d 以及 三次运算 。即A(4,4) *4*4*4 就是该算法的复杂度。微观上,由于中间有除法,那么不能用int类型来储存数据了。需要用double或者float.每次运算都只有两个数运算。2.7 判断是否无解: 同样系统计算答案,判断有没有解三、程序流程图四、程
8、序调试3 4 4.1 图片显示:图片导入难以实现,不断修改、查阅信息、修改完成。4.2 表达式求值算法:计算结构有误。原因为运算符优先级设置不正确,如加号和减号的优先级相同,乘号和除号的优先级相同。4.3 按钮可用性设定:不可连续输入括号,如:(6+6)+6)+6,是正确的解,但是无法输入,修改了按钮可用性设定的规则:当按下左括号时,左括号仍可用,并且,四个数字都使用了以后,系统自动完成括号匹配的工作。4.4 有待改进的地方:程序经常出现闪屏现象,可以增加定时、难度级别设置的功能。五、部分截图5.1主界面:5.2设置牌面: 5.3退出游戏:六、部分关键代码(完整请见poin24工程)/*计算表
9、达式*/int calculate(CString &expression) string str= expression.GetBuffer(0);/将CString转换成string类型 str+=; /添加分号,作为表达式结束 stack Sign; /运算符栈int Num; /数字栈 Sign.push(); /分号压入栈底 int pos = 0; /从0号为开始读取表达式 char current = str0, topSign; /当前字符 while(Sign.top() != | current !) int num = apartNum(str,pos); /拆分数字与字
10、符 if(num != -1) /读取出数字,添加到数字栈中 Num.push(num); else /读取出运算符 current = strpos; pos+; /继续下次循环 topSign = Sign.top();/得到当前栈顶的运算符 if(current = ) & topSign=()/当前读到右括号,栈顶为左括号 Sign.pop(); /直接弹出左括号 else if(current ! cmpPriority(current, topSign) | topSign = ) Sign.push(current); /将当前运算符压栈 else int a,b,c; a =
11、Num.top(); /得到数字栈栈顶元素 Num.pop(); b = Num.top(); /得到第二个数字 topSign = Sign.top(); /弹出运算符 if(topSign = +) c = a + b; /加法 else if(topSign = -) c = b - a; /减法*) c = a * b; /乘法/) c = b / a; /除法 else return -1; Num.push(c); /将新的数存入数字栈中 /得到符号栈栈顶运算符 pos-; /向前退一个,继续操作当前的运算符 current = strpos; /下一轮的当前字符 return N
12、um.top();/*系统计算24点的解*/bool search(int n, int* number, string* expression) if (n = 1) if ( fabs(number0 - 24) PRECISION ) /精度范围内,表达式正确 /cout expression0 endl; /输出表达式 return true; else return false;/穷举法,递归调用求表达式 for (int i = 0; i n; i+) for (int j = i + 1; j j+) double a, b; string expa, expb; a = numberi; b = numberj; numberj = numbern - 1; expa = expressioni; expb = expressionj; expressionj = expressionn - 1; expressioni = + expa + + expb + /加法 numberi = a + b; if ( search(n - 1, number, expression) ) return true; numberi = a - b; + ex
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1