经典24点纸牌益智游戏

一、题目要求

24点游戏是经典的纸牌益智游戏

从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。

用户初始生命值为一给定值,初始分数为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。

1.程序风格良好(使用自定义注释模板)

2.使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。

3.所有成绩均可记录在TopList.txt文件中。

二、问题分析

    根据题目,我们可以用一个数组存储随机生成的四张牌。由于用户输入的表达式为前缀表达式,因此我们需要将其转化为后缀表达式进行计算。计算过程可以使用栈实现一个简单的计算器。而计时器的实现,我们可以使用简单方式获取开始时间和结束时间,控制二者之差进行时间控制。

三、调试

1.随机生成四张牌

 

 

 

 

2.表达式输入

四、测试

1.测试计算器功能

2.测试成绩录入文件功能

五、程序代码

#include<stdio.h>
#include<string.h>
#include<time.h> 

#define MAX 100 
#define MCHAR 20

typedef struct CharStack                //字符栈 
{
    char data[MAX];
    int top;
}cStack;
 
typedef struct DoubleStack                //数据栈 
{
    int data[MAX];
    int top;
}dStack;

struct use        //用户的结构体
{
    char id[MCHAR];    //用户名称 
    int HP;        //生命值 
    int score;        //分数 
}user[MAX];

int unum;
void play();
int Isop(char );                //当前扫描元素优先级 
int Inop(char );                //栈顶元素优先级 
void Initc(cStack *);                //初始化字符栈 
int Pushc(cStack *,char);            //字符栈压栈 
char Gettopc(cStack *);                //返回栈顶元素 
char Popc(cStack *);                //出栈 
void Initd(dStack *);                //初始化数据栈              
int Pushd(dStack *,int);    //数据压栈
int Popd(dStack *);        //出栈 
void Trans(char*s1,char*s2);        //转化为后缀表达式 
int Calculate(char *s2);        //后缀表达式求值
void readTopfile();
void writeTopfile();
void grade(int t,int s); 

int main()
{
    readTopfile();
    srand((unsigned)time(NULL)); //随机数
    play();    
    return 0;
}

void play()
{
    int j=unum;
    int t=0,s=0;
    int a[4];
    int i; 
    int fun=0,choice=0;
    int start,end; 
    char s1[MAX];            //用于存储前缀表达式 
    char s2[MAX];            //用于存储转换后的表达式 
    printf("24点游戏欢迎您!\n\n"); 
    printf("请输入您的用户名:");
    scanf("%s",&user[j].id); 
    while(1)   //主界面    
    { 
        printf("请输入相应选项:1开始游戏,2结束游戏\n"); 
        scanf("%d",&fun); 
        printf("您的初始生命值为100,答错或超时减10,每答对1次记10分\n"); 
        while(fun==1) 
        {
            printf("您抽到的四张牌是:"); 
            for(i=0;i<4;i++) 
            { 
                a[i]=rand()%13+1; //获得随机数 
                if(a[i]==1)
                    printf("A ");
                else if(a[i]==11)
                    printf("J ");
                else if(a[i]==12)
                    printf("Q ");
                else if(a[i]==13)
                    printf("K ");
                else
                    printf("%d ",a[i]); 
            } 
            printf("您可以进行以下选择:1.作答  2.跳过\n");
            scanf("%d",&choice);
            while(choice==1)
            { 
                printf("A=1,J=11,Q=12,K=13\n");
                printf("请在60秒内完成作答。");
                printf("请输入表达式:");
                start=clock();
                scanf("%s",s1);
                Trans(s1,s2);                //处理字符串,并转化为后缀表达式,存放在s2中 
                printf("\n计算结果为: %d",Calculate(s2));        //后缀表达式求值
                printf("\n");
                end=clock();
                if(Calculate(s2)!=24)
                {
                    printf("您输入的表达式运算不正确!\n"); 
                    t=t+1;
                    break; 
                }
                else
                {
                    if((end-start)>60000)
                    {
                        printf("您输入的表达式正确,不过很遗憾您已超时!");
                        t=t+1;
                        break; 
                    }
                    else
                    {
                        printf("恭喜你,回答正确!\n");
                        s=s+1;
                        break; 
                    }
                }
            }
            if(t==10)
            {
                printf("您的生命值已为0,游戏结束!");
                printf("您的成绩为:%d",s*10);
                break; 
            }
            else
            { 
                printf("您可以选择:1.继续游戏  2.结束游戏\n") ;
                scanf("%d",&fun);
                if(fun==1)
                    continue;
                else
                {
                    grade(t,s);
                    printf("用户名:%s 生命值:%d 成绩:%d",user[j].id,user[j].HP,user[j].score);
                    break;    
                }
            } 
        }
        break; 
    } 
    printf("\n谢谢使用"); 
}

void grade(int t,int s)
{
    int j=unum;
    user[j].HP=100-t*10;
    user[j].score=s*10;
    unum++;
    writeTopfile();
}

void  readTopfile()
{
   FILE *fp;        //声明文件
   int i=0;            //定义变量
   fp=fopen("TopList.txt","r");        //打开存放记错单词文件库
   if(!fp)        //如果文件不存在
   {
       printf("\n打开文件TopList.txt失败!");

   }
  
   while(fscanf(fp,"%s %d %d ",user[i].id,&user[i].HP,&user[i].score)==3)//读取下一个用户 
   {
       i++;//计数器+1
   }
   unum=i;//记录用户总数
   fclose(fp);//关闭文件

}

//向用户文件写入用户信息的函数
void writeTopfile(){
       FILE *fp;//声明文件
       int i=0;
       fp=fopen("TopList.txt","w");//打开文件
       if(!fp)//如果文件存在
       {
               printf("\n打开文件TopList.txt失败!");
           }
           for(i=0;i<unum;i++)
           {
        fprintf(fp,"\n%s    %d  %d ",user[i].id,user[i].HP,user[i].score);//fprintf(可以从一个文件流中格式化写入数据)
        }
           printf("\n");
           fclose(fp);//关闭文件
            
}

//初始化 
void Initc(cStack *s1)
{
    s1->top=-1;
}
 
 //字符栈压栈 
 int Pushc(cStack *c1,char op)
 {
     if(c1->top<MAX)
     {
         c1->data[++c1->top]=op;
         return 1;
    }
    else return 0;
}
 
//GET栈顶元素 
char Gettopc(cStack *c1)
{
    return c1->data[c1->top];
}
 
//字符栈出栈 
char Popc(cStack *c1)
{
    return c1->data[c1->top--];
}
 
//初始化数据栈 
void Initd(dStack *d1)
{
    d1->top=-1;
}
 
//数据栈压栈 
int Pushd(dStack *d1,int data)
{
    if(d1->top<MAX)
    {
        d1->data[++d1->top]=data;
        return 1;
    }
    else return 0;
}
 
//数据栈出栈 
int Popd(dStack *d1)
{
    return d1->data[d1->top--];
}
 
int Isop(char op)        //当前扫描运算符优先级
{
    switch(op)
    {
        case '(': return 6;
        case '+': case '-': return 2;
        case '*': case '/': return 4;
    }
}
int Inop(char op)        //当前扫描运算符优先级
{
    switch(op)
    {
        case '(': return 1;
        case '+': case '-': return 3;
        case '*': case '/': return 5;
    }
}
 
void Trans(char *s1,char *s2)
{
    int i=0;
    int j=0;
    int flag1=-1;                //flag1为0表示上次输出为数字,flag1为1表示上次输出为字符
    int flag2=-1;                 //flag2为0表示上次扫描为数字,flag为1表示上次扫描为运算符,用于区分数字后加空格
    cStack st1;                //暂放运算符 
    Initc(&st1);
    while(s1[i]!='\0')
    {
        if(flag1==0&&flag2==1)        //若上次的输出为数字,上次循环扫描为字符,则表示该数字串结束,则在数字后加空格区分 
        {
            s2[j++]=' ';
            flag1=1; 
        }
        if(s1[i]>='0'&&s1[i]<='9')
        {
            s2[j++]=s1[i];
            flag2=0;
            flag1=0;
        }
        else if(s1[i]=='+'||s1[i]=='-'||s1[i]=='*'||s1[i]=='/'||s1[i]=='(')
        {
            flag2=1;
            if(st1.top<0||Isop(s1[i])>Inop(Gettopc(&st1)))
            {
                Pushc(&st1,s1[i]);
            }
            else
            {
                while(st1.top>=0&&Isop(s1[i])<Inop(Gettopc(&st1)))        //当前扫描字符优先级不断与栈顶字符优先级比较,当前字符                                                                                                     //小于栈顶字符时退栈并输出 
                {
                        s2[j++]=Popc(&st1);
                        flag1=1;
                }
                if(st1.top<0||Isop(s1[i])>Inop(Gettopc(&st1)))            //当前字符优先级大于栈顶优先级或栈空时当前字符压入字符栈内 
                {
                    Pushc(&st1,s1[i]);
                }
                
            }
        }
        else if(s1[i]==')')                 
        {
            flag2=1;
            if(Gettopc(&st1)!='(')        //若括号仅包含数字则没有输出运算符 
            {
                flag1=1;
            }
            while(Gettopc(&st1)!='(')
            {
                s2[j++]=Popc(&st1);
            }
            Popc(&st1);        //将'('出栈 
        }
        i++;
    }
    while(st1.top>=0)        //将栈内剩余的运算符依次退栈输出 
    {
        s2[j++]=Popc(&st1);
    }
    s2[j]='\0';
}
 
//表达式求值 
int Calculate(char *s1)
{
    int i=0;
    int flag;                //char类型转换为int类型数据标记 
    int data1,data2;
    int sum;
    dStack ds1;
    Initd(&ds1);
    while(s1[i]!='\0')
    {
        if(s1[i]=='+'||s1[i]=='-'||s1[i]=='*'||s1[i]=='/')            //若为运算符获取栈顶两个元素进行计算 
        {
            data1=Popd(&ds1);
            data2=Popd(&ds1);
            if(s1[i]=='+') Pushd(&ds1,data2+data1);
            else if(s1[i]=='-') Pushd(&ds1,data2-data1);
            else if(s1[i]=='*') Pushd(&ds1,data2*data1);
            else if(s1[i]=='/') Pushd(&ds1,data2/data1);
        }
        else
        {
            flag=0;                    //初始化为0为整数部分标记,1为小数部分标记 
            sum=0;
            int divider=1;
            while(s1[i]!=' '&&s1[i]!='+'&&s1[i]!='-'&&s1[i]!='*'&&s1[i]!='/')
            {
                if(flag==0)
                    sum=sum*10+(int)(s1[i]-'0');
                else
                {
                    divider=divider*10;
                    sum=sum+((int)(s1[i]-'0'))/divider;
                }
                i++;
            }
            if(s1[i]=='+'||s1[i]=='-'||s1[i]=='*'||s1[i]=='/') i--;//转化成功一个数据,若下个字符为运算符,则i--,回到当前运算的数据位置 
            Pushd(&ds1,sum);
        }
        i++;        //i++准备下一个字符的转换 
    }
     return Popd(&ds1);
}
 

六、运行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值