24点游戏是经典的纸牌益智游戏。
常见游戏规则: 从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
一:基本要求: 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式,用擅长的语言(C/C++/Java或其他均可)实现程序解决问题。
1.程序风格良好(使用自定义注释模板)
2.列出表达式无重复。
二:提高要求:
1.用户初始生命值为一给定值(比如3),初始分数为0。
2.随机生成4个代表扑克牌牌面的数字或字母。
3.由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。
a. 程序风格良好(使用自定义注释模板)
b.使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。
c.所有成绩均可记录在TopList.txt文件中。
三:算法设计
a.定义一个结构体,来存放两个数字和符号。
b.产生4个随机数进行运算,将能得出24的4个数和表达式放在数组f[i]里,将4个随机数输出,作为数据供用户计算。
c.用户输入表达式,用栈来实现。
d.判断表达式是否正确,判断结果是否为24。
e.正确则分数加一,错误则生命减一。
f.生命值小于0,则游戏结束。将分数存入Toplist.txt文件中。
四:流程图
五:源程序
#include <iostream.h>
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MaxSize 1000
int card[MaxSize],flag;
struct
{
int op1[MaxSize];//第一个数
int op2[MaxSize];//第二个数
int value[MaxSize];//两个数做运算的结果
char op[MaxSize];//加减乘除
}solu;
void Init(int n) //随机产生n个随机数
{
int i;
for (i=1;i<=n;++i)
card[i]=rand()%13+1;
}
void work(int f[],int k,int n)//判断 产生的随机数是否能通过加减乘除等于24
{
int i,j,temp[MaxSize],t;
if (k==n)
{
if (f[1]==24) flag=1; //当得到的结果为24时退出
}
else
{
for (i=1;i<=n-k+1;++i) //控制外部循环
for (j=i+1;j<=n-k+1;++j)
{
if (flag==0)
{
int p;t=1;
for (p=1;p<=n-k+1;++p)
if (p!=j&&p!=i)
{
temp[t]=f[p];
++t;
}
}
if (flag==0)//两个数进行加法运算
{
temp[t]=f[i]+f[j];
solu.op1[k]=f[i];solu.op2[k]=f[j];
solu.op[k]='+';solu.value[k]=temp[t];
work(temp,k+1,n);
}
if (flag==0)//两个数进行减法运算
{
temp[t]=f[i]-f[j];
solu.op1[k]=f[i];solu.op2[k]=f[j];
solu.op[k]='-';solu.value[k]=temp[t];
work(temp,k+1,n);
}
if (flag==0)
{
temp[t]=f[j]-f[i];
solu.op1[k]=f[j];solu.op2[k]=f[i];
solu.op[k]='-';solu.value[k]=temp[t];
work(temp,k+1,n);
}
if (flag==0) //两个数进行乘法运算
{
temp[t]=f[i]*f[j];
solu.op1[k]=f[i];solu.op2[k]=f[j];
solu.op[k]='*';solu.value[k]=temp[t];
work(temp,k+1,n);
}
if (f[j]!=0&&f[i]%f[j]==0&&flag==0) //两个数进行除法运算
{
temp[t]=f[i]/f[j];
solu.op1[k]=f[i];solu.op2[k]=f[j];
solu.op[k]='/';solu.value[k]=temp[t];
work(temp,k+1,n);
}
if (f[i]!=0&&f[j]%f[i]==0&&flag==0)
{
temp[t]=f[j]/f[i];
solu.op1[k]=f[j];solu.op2[k]=f[i];
solu.op[k]='/';solu.value[k]=temp[t];
work(temp,k+1,n);
}
}
}
}
void print(int n) //将得出24的步骤列举出来
{
for (int i=1;i<=n-1;++i)
{
if (solu.op2[i]<0) cout<<"第"<<i<<"步 : "<<solu.op1[i]<<solu.op[i]<<'('<<solu.op2[i]<<")="<<solu.value[i]<<endl;
else cout<<"第"<<i<<"步 : "<<solu.op1[i]<<solu.op[i]<<solu.op2[i]<<'='<<solu.value[i]<<endl;
}
}
bool IsOperator(char ops)
{
if(ops == '+' || ops == '-' || ops == '*' || ops == '/' || ops == '^' || ops == '(' || ops == ')')
return(true);
else
return(false);
}
bool IsOperand(char ch)
{
if ((ch >= '0') && (ch <= '13'))
return true;
else
return false;
}
int isok(char exp[])//判断输入的符号是否错误
{
char check;
int error=0;
int lb=0;
int rb=0;
for(int m=0;m < strlen(exp); m++)
{
check = exp[m];
if(IsOperand(check))
{
}
else if(IsOperator(check))
{
if(check == ')')
{
rb++;
if(IsOperator(exp[m+1]) && (exp[m+1]=='+' || exp[m+1]=='-' || exp[m+1]=='*'
|| exp[m+1]=='/' || exp[m+1]=='^' || exp[m+1]==')')) //将表达式的符号存起来
{
m++;
if(exp[m] == ')') //遇见右括号 rb++
rb++;
}
else if(IsOperator(exp[m+1]))
error++;
}
else if(check == '(')//遇见左括号 lb++
{
lb++;
if(IsOperator(exp[m+1]) && exp[m+1] =='(')
{
m++;
lb++;
}
else if(IsOperator(exp[m+1]))
error++;
}
else
{
if(IsOperator(exp[m+1]) && exp[m+1] == '(')
{
m++;
lb++;
}
else if(IsOperator(exp[m+1]))
error++;
}
}
else
error++;
}
if(error == 0 && lb==rb) // 当错误为零,左括号数等于右括号数
return(1); //返回为1
else
return(0);
}
void trans(char *exp,char postexp[])
{
struct
{
char data[MaxSize];
int top;
}op;
int i=0;
op.top=-1;
while (*exp!='\0')
{
switch(*exp)
{
case '(':
++op.top;
op.data[op.top]=*exp;
++exp;
break;
case ')':
while (op.data[op.top]!='(')
{
postexp[i++]=op.data[op.top];
--op.top;
}
--op.top;
++exp;
break;
case '+':
case '-':
while (op.top!=-1 && op.data[op.top]!='(')
{
postexp[i++]=op.data[op.top];
--op.top;
}
++op.top;
op.data[op.top]=*exp;
++exp;
break;
case '*':
case '/':
while (op.data[op.top]=='*'||op.data[op.top]=='/')
{
postexp[i++]=op.data[op.top];
--op.top;
}
++op.top;
op.data[op.top]=*exp;
++exp;
break;
case ' ':
++exp;
break;
default:
while (*exp>='0' && *exp<='13')
{
postexp[i++]=*exp;
++exp;
}
postexp[i++]='#';
}
}
while (op.top!=-1)
{
postexp[i++]=op.data[op.top];
--op.top;
}
postexp[i]='\0';
}
float cal(char *postexp)
{
struct
{
float data[MaxSize];
int top;
}st;
float d,a,b,c;
st.top=-1;
while (*postexp!='\0')
{
switch (*postexp)
{
case '+':
a=st.data[st.top];
--st.top;
b=st.data[st.top];
--st.top;
c=a+b;
++st.top;
st.data[st.top]=c;
break;
case '-':
a=st.data[st.top];
--st.top;
b=st.data[st.top];
--st.top;
c=b-a;
++st.top;
st.data[st.top]=c;
break;
case '*':
a=st.data[st.top];
--st.top;
b=st.data[st.top];
--st.top;
c=a*b;
++st.top;
st.data[st.top]=c;
break;
case '/':
a=st.data[st.top];
--st.top;
b=st.data[st.top];
--st.top;
if (a!=0)
{
c=b/a;
++st.top;
st.data[st.top]=c;
}
else
{
cout<<"除零错误!!"<<endl;
exit(0);
}
break;
default:
d=0;
while (*postexp>='0' && *postexp<='13')
{
d=10*d+*postexp-'0';
++postexp;
}
++st.top;
st.data[st.top]=d;
break;
}
++postexp;
}
return (st.data[st.top]);
}
int NumMatch(char *postexp)//用户输入表达式
{
int f[5]={0,0,0,0,0},i=1; //初始值为零
while (*postexp!='\0')
{
switch (*postexp)
{
case '#':
++postexp;
++i;
break;
case '+':
case '-':
case '*':
case '/':
++postexp;
break;
default:
if (i>=5) return 0;
f[i]=f[i]*10+*postexp-'0';
++postexp;
break;
}
}
for (i=1;i<=4;++i)
for (int j=i+1;j<=4;++j)
{
if (f[i]>f[j])
{
int temp=f[i];
f[i]=f[j];
f[j]=temp;
}
if (card[i]>card[j])
{
int temp=card[i];
card[i]=card[j];
card[j]=temp;
}
}
for (i=1;i<=4;++i) //将输入的表达式与已经计算好的表达式作比较 若相同表达式正确
if (f[i]!=card[i]) return 0;
return 1;
}
int main()
{
char exp[MaxSize],postexp[MaxSize],temp[MaxSize];
int cardnum=4,HardLevel=2,Score=0,tt=1,life=3;//扑克牌的数量为4 分数为0 生命为3
system("cls");//清屏
cout<<"游戏正式开始"<<endl<<endl;
while(tt!=0) //生命中为0时游戏结束
{
srand(time(NULL));
while (Score>=0)
{
flag=0;
Init(cardnum);
work(card,1,cardnum);
while (flag==0)
{
Init(cardnum);
work(card,1,cardnum);
}
cout<<"产生的随机数如下"<<endl;
for (int i=1;i<=cardnum;++i) cout<<card[i]<<" ";
cout<<endl<<endl;
cout<<"请输入表达式"<<endl;
cin.getline(temp,MaxSize);
int j=0;
for (i=0;i < strlen(temp);++i)
if (temp[i]!=' ')
{
exp[j]=temp[i];
++j;
}
exp[j]='\0';
cout<<endl<<endl<<endl;
if (isok(exp))
{
trans(exp,postexp);
if (cal(postexp)==24&&NumMatch(postexp))
{
cout<<"太棒了,完全正确!"<<endl;
++Score;
}
else
{
cout<<"很遗憾,您的回答错误。"<<endl<<"这里有一种可行的算法:"<<endl;
print(cardnum);
--life;
}
}
cout<<endl<<"您现在的得分为 "<<Score<<endl;
cout<<endl<<"您现在的生命为 "<<life<<endl;
cout<<endl<<"开始下一局 "<<endl;
if (life<0)
{
system("cls");
cout<<"游戏结束"<<endl<<"你的成绩保存在TopList.txt文件里"<<endl;
tt=0;
break;
}
}
}
char *p="Toplist.txt"; //将你的成绩保存在TopList.txt文件里
FILE *fp;
fp=fopen("TopList.txt","a");
fprintf(fp,"%d\n",Score);
fclose(fp);
return 0;
}
六:调试测试
游戏开始
回答正确
回答错误
游戏结束
七:心得体会
1.通过这次的学习实践,了解了结构体的使用和其他基本功能的巩固,加深了我对C语言更深层的理解。
2.了解了数据结构栈的使用
3.了解了fopen()函数,文件使用方式由r,w,a,t,b,+六个字符拼成。