提前bb:采用的ide是vc++ 6.0 ,并且是通过24点游戏.cpp包含Judge.h、compute.h、menu.h3个文件
一、题目分析
24点游戏是经典的纸牌益智游戏。
游戏规则:
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
要求(全部实现):
1.随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式。
2.程序风格良好(使用自定义注释模板)。
3.列出表达式无重复。
4.用户初始生命值为一给定值(比如3),初始分数44 CC为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4 个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。
5.使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。
6.所有成绩均可记录在TopList.txt文件中。
二、算法分析
难难点在于表达式的计算,其实就是后缀表达式的计算~具体过程可见代码或者其他教程。
计时可以用time_t类型的变量,设定一个time_begin,然后用当前已运行的时间减去起始时间,超过规定的时间则执行其他操作(此处我设定的是3s,觉得时间短了的可以改)。
三、流程图
四、代码实现
【24点游戏.cpp】
//版本:1.1
//主要功能:系统随机生成四个数字,游戏玩家输入由四个数字组成的四则运算表达式,使计算结果得24
//系统会检查玩家输入的四则运算表达式是否正确。并给出提示。同时系统会给出所有的表达式使得这四个
//数字的运算结果为24
#include<iostream>
#include"menu.h"
#include"compute.h"
#include"Judge.h"
#include<math.h>
using namespace std;
int main()
{
int option;
int flag;
char a;
Menu();
do
{
cout<<"请输入你的选项:";
cin>>option;
if(option>=1&&option<=3)
{
flag=1;
break;
}
else
{
flag=0;
cout<<"你的输入有误,请重新输入!"<<endl;
}
}while(flag==0);
while(flag==1)
{
switch(option)
{
case 1: Compute();JudgeAnswer();lefts();break;
case 2: GameRule(); break;
case 3: exit(0); break;
default: break;
}
cout<<"是否要继续(y or n):";
cin>>a;
if(a=='y')
{
flag=1;
system("cls");
Menu();
cout<<"请输入你的选项:";
cin>>option;
}
else
exit(0);
}
}
【Judge.h】
//Judge.h
//中缀表达式的计算
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <conio.h>
#include <fstream>
#define SIZE 40
#define MaxSize 32
using namespace std;
int life=3; //生命值
int point=0; //得分
//定义结点,存放字符
struct node
{
char *base;
char *top; //头指针
int size;
}m;
//数值结点定义
struct list
{
float *base;
float *top;
int size;
}n;
//将数值放入栈中的算法
void ValuePush(list& S,float e)
{
*S.top++=e;
}
//将运算符放入栈中
void CharPush(node& S,char e)
{
*S.top++=e;
}
//数值出栈
float ValuePop(list& S)
{
if(S.base==S.top) cout<<"整数栈为空,不能输出";
float x= *(--S.top);
return x;
}
//字符出栈
char CharPop(node& S)
{
if(S.base==S.top) cout<<"字符栈为空,不能输出";
char x= *(--S.top);
return x;
}
//初始化字符栈
void InitCharStack(node& S)
{
S.base=(char *)malloc(SIZE *sizeof(char)); //建立一个节
if(!S.base)
{
cout<<"errer abc"<<endl;
exit(1);
}
S.top=S.base;
S.size=20;
}
//初始化数值栈
void InitValueStack(list& S)
{
S.base=(float *)malloc(SIZE *sizeof(float)); //建立一个节点
if(!S.base)
{
cout<<"errer efg"<<endl;
exit(1);
}
S.top=S.base;
S.size=20;
}
//解决比较优先级的时候如何处理运算符的值的大小,进而进入下一步的运算
int Prior(char c)
{
//cout<<"要求栈内优先数的字符为"<<c<<endl;
int r;
switch(c)
{
case ';':r=0;break;
case '(':r=1;break;
case '*':
case '/':r=5;break;
case '+':
case '-':r=3;break;
case ')':r=8;break;
default:cout<<"errer asdf"<<endl;
}
return r;
}
int Prior2(char c)
{
int w;
//cout<<"要求栈内优先数的字符为"<<c<<endl;
switch(c)
{
case ';':w=0;break;
case '(':w=8;break;
case '*':
case '/':w=4;break;
case '+':
case '-':w=2;break;
case ')':w=1;break;
default:cout<<"errer sfd"<<endl;
}
return w;
}
float Compute(char* str)
{
int i=0;
float x;
CharPush(m,';'); //初始化字符栈,中只有一个元素';',整数栈为空栈
while(str[i]&&i<SIZE-1) //处理中缀表达式循环
{
x=0;
if(str[i]==' ')
{
i++;
continue;
}
while(str[i]>=48&&str[i]<=57) //1到10的ASCII码值
{
x=x*10+str[i]-48; //从屏幕上获取的都是以字符的形式展现出来的,所以要ASCILL码值都要减去48 ,这样才能输入多位数
i++;
}
if(x!=0) ValuePush(n,x); //如果x的值不等于 0那么就进整数栈
else
{
int a=Prior2(str[i]); //处理栈外字符
int b=Prior(*(m.top-1)); //处理栈内字符,成员变量是字符栈中的栈顶元素
if(a>b) //栈外运算符优先级高于栈内运算符优先级
{
CharPush(m,str[i]);i++;} //将其插入到字符栈中
else
switch(CharPop(m)) //优先级相反,括号里面的参数变量是字符栈内的首元素
{
case '+':x=ValuePop(n)+ValuePop(n); //从整数栈中抛出两个数值,进行以上的运算
ValuePush(n,x); break;
case '-':x=ValuePop(n);
x=ValuePop(n)-x;
ValuePush(n,x);break;
case '*':x=ValuePop(n)*ValuePop(n);
ValuePush(n,x);break;
case '/':x=ValuePop(n);
if(x!=0.0)
{
x=ValuePop(n)/x;
ValuePush(n,x);
}
else {cout<<"零不能做除数"<<endl;i=SIZE-1;}
break;
case '(':i++;break;
case ';':i=SIZE-1;break;
default:cout<<"====输入有误===="<<endl;
}
}
}
x=ValuePop(n);
return x;
}
void JudgeAnswer()
{
ofstream f;
f.open("TopList.txt",ios::app);
if(!f){
cout<<"打开文件失败!"<<endl;
exit(0);
}
char str[32];
char a[SIZE];
InitCharStack(m); //字符栈初始化
InitValueStack(n); //数值栈初始化
f<<"-------------------"<<endl;
f<<"这是新的一轮的记录"<<endl;
cout<<"输入24点表达式,以;结束:"<<endl;
cout<<"你一共有三秒的时间思考,超过时间视为失败"<<endl;
time_t timeBegin=time(0);
int n=0;
float z=0;
while(true){
if(kbhit()){
cin>>str;
z=Compute(str);
break;
}
//输出倒计时
else if(time(0)-timeBegin>=3){
cout<<"时间到!你没有输入表达式!"<<endl;
n=0;
break;
}
}
cout<<"你的表达式的结果为:"<<z<<endl;
if(24==(int)z)
{
point++;
f<<"当前得分为:"<<point<<endl;
cout<<"你的回答是正确的!"<<endl;
cout<<"目前你的分数为:"<<point<<endl;
cout<<"目前你的生命值为:"<<life<<endl;
}
else
{
life--;
cout<<"你的回答是错误的!"<<endl;
f<<"当前得分为:"<<point<<endl;
cout<<"目前你的分数为:"<<point<<endl;
cout<<"目前你的生命值为:"<<life<<endl;
if(life==0)
{
f<<"-------------------"<<endl;
f.close;
cout<<"没有生命值!游戏结束!"<<endl;
exit(0);
}
}
}
【compute.h】
//compute.h 计算24点的表达式
#include<iostream>
#include<string>
#include<time.h>
#include<math.h>
const double LING = 1E-6;
const int VALUE=24;
const int COUNT=4;
double number[COUNT];
string expression[COUNT];
string ShowAnswers[50];
int FINDNUM=0;
bool Judge=false;
int NUM=0;
using namespace std;
void Find(int n) //n为运算数的个数,当n为1时,达到递归的终止条件,此时第一位保存的就是运算结果
{
if(n==1) //n为1时,给出相应的处理
{
if(fabs(number[0]-VALUE)<=LING) //判断数值是否是24
{
ShowAnswers[FINDNUM]=expression[0];
Judge=true; //结果标识
NUM++;FINDNUM++;
}
}
for(int i=0;i<n;i++) //递归循环开始,使用穷尽的方法
{
for(int j=i+1;j<n;j++)
{
double a,b;
string expressiona,expressionb;//表示计算的表达式
a=number[i]; //把两个随机数赋给a和b,随机数放在了数组中
b=number[j];
number[j]=number[n-1];//将后面的数转移到选中的数,此时数组中的值的数量在减少
expressiona=expression[i];
expressionb=expression[j];
expression[j]=expression[n-1];
//对取出的数分别做+ - * / 运算,并将运算结果放入的原数组中,再次进行Find()运算
expression[i]='('+expressiona+'+'+expressionb+')';
number[i]=a+b;
Find(n-1);
expression[i]='('+expressiona+'-'+expressionb+')';
number[i]=a-b;
Find(n-1);
expression[i]='('+expressionb+'-'+expressiona+')';
number[i]=b-a;
Find(n-1);
expression[i]='('+expressiona+'*'+expressionb+')';
number[i]=a*b;
Find(n-1);
//讨论除数为0的状况
if(b!=0)
{
expression[i]='('+expressiona+'/'+expressionb+')';
number[i]=a/b;
Find(n-1);
}
if(a!=0)
{
expression[i]='('+expressionb+'/'+expressiona+')';
number[i]=b/a;
Find(n-1);
}
number[i]=a;
number[j]=b;
expression[i]=expressiona;
expression[j]=expressionb;
}
}
}
void Compute()
{
srand(time(0));
for(int i=0;i<COUNT;i++)
{
char ch[20];
number[i]=rand()%13+1;
itoa(number[i],ch,10);
expression[i]=ch;
}
cout<<"系统自动为你生成的游戏数字是:"<<endl;
for(int j=0;j<COUNT;j++)
{
if(number[j]==1) cout<<"A"<<" ";
else if(number[j]==11) cout<<"J"<<" ";
else if(number[j]==12) cout<<"Q"<<" ";
else if(number[j]==13) cout<<"K"<<" ";
else cout<<number[j]<<" ";
}
cout<<endl;
}
void lefts()
{
char a;
cout<<"是否想看见全部解答?(y or n):";
cin>>a;
Find(COUNT);
if(a=='y')
{
if(Judge==true)
{
cout<<"\n以下是全部可能:"<<endl;
cout<<"总共的方法有:"<<NUM<<endl;
for(int i=0;i<NUM;i++)
{
cout<<ShowAnswers[i]<<endl;
}
}
else
cout<<"抱歉,该组数字无正确的解!"<<endl;
}
else
{};
}
【menu.h】
//Menu.h
#include<iostream>
using namespace std;
void Menu(void)
{
cout<<"**********欢迎使用24点游戏程序**********\n";
cout<<" 1.开始游戏\n";
cout<<" 2.游戏规则\n";
cout<<" 3.退出游戏\n";
cout<<"****************************************\n";
}
void GameRule()
{
cout<<"游戏说明如下:"<<endl;
cout<<" 24点游戏是一种使用扑克牌来进行的益智类游戏,"<<endl;
cout<<"由于本程序在控制台下完成,故使用具体的数字代替扑"<<endl;
cout<<"克牌.游戏内容是:从一副扑克牌中抽去大小王剩下52张"<<endl;
cout<<",任意抽取4张牌,把牌面上的数(A代表1)运用加、减"<<endl;
cout<<"、乘、除和括号进行运算得出24。每张牌都必须使用一"<<endl;
cout<<"次,但不能重复使用。"<<endl;
}
五、运行结果
(调试截图略)
六、经验归纳
通过编写程序发现我在编程过程中细心程度不够,会出现小错误,在以后的学习过程中应该养成好的编程习惯。还有从最初的一个简单的程序,通过自己的努力慢慢调试完善修改,得到最后成果,虽然还有不足,但是这个过程我享受到了收获的感觉,是喜悦的。还有自己的知识还欠缺太多,希望自己加油努力学习更多的知识。