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