24点游戏

24点游戏

1.题目分析
题目要求:本次作业有关24点游戏,从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
基本要求: 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式,用擅长的语言(C/C++/Java或其他均可)实现程序解决问题。
提高要求:给一用户初始生命值和初始分数。随机生成4个代表扑面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。最后所有成绩均可记录在TopList.txt文件中。
具体题目分析:①本次游戏要求生成的四张牌是随机的,所以会用到随机数rand()随机生成四个数,②四个数产生值为24的不同表达式重点在于表达式符号的类型以及位置,所以应该列出四个数组成的表达式的可能情况。③提高要求涉及表达式的计算,所以需要用到数据结构中栈对表达式进行求解。(此处涉及栈的相关操作例如栈的初始化,如何放置表达式,如何将表达式从栈中取出)④在一定时间内执行某个操作会涉及系统函数kbhit(),所以我查阅资料了解了关于这个函数的用法。⑤将最终的得分写入文件,需注意文件的读写方式(Fprintf)以及文件路径是否正确。
2.算法构造
①列出生成随机数值为24的表达式。需注意表达式符号的类型以及位置。四个数组成的表达式总共有五种类型。{第一种表达式:a b b bc d = 第 二 种 表 达 式 ( a d=第二种表达式(a d=(a(b c ) ) c)) c))d=第三种表达式a ( b (b (b(c d ) ) = 第 四 种 表 达 式 a d))= 第四种表达式a d))=a((b c ) c) c)d)= 第五种表达式(a b ) b) b)(cKaTeX parse error: Expected 'EOF', got '}' at position 4: d)=}̲(代表某个具体运算符,a,b,c,d代表随机产生的四个操作数)。
②栈对表达式求值算法。(此算法参考相关资料)建立两个栈,一个栈存放运算数,另一个存放操作符。设置一个数组cmp[7][7] 用来进行比较运算符优先级的矩阵,3代表’=’,2代表’>’,1是代表’<’,0代表不可比,对两个栈进行初始化操作,输入表达式如果没有结束标识符#,将不会输出结果,或出现错误结果。具体操作函数{void InitStack(SeqStack *S)/初始化运算符栈/;void InitStacknum(numSeqStack *S)/初始化运算数栈/int IsEmpty(SeqStack *S)/判操作符栈为空栈时返回值为真,反之为假/int IsFull(SeqStack *S)/判断符号栈S为满栈时返回值为真,反之为假/void Push(SeqStack *S, char x)/运算符栈入栈函数, '#'为结束标志/void Pushnum(numSeqStack *S, int x)/运算数入栈函数/int Pop(SeqStack *S)/运算符栈出栈函数/int Isoperator(char ch) /判断输入字符是否为运算符函数,是返回TRUE,不是返回FALSE/等。(本算法重点是判断运算符运算顺序,以及分清表达式中的运算符和算数)。
③控制时间算法。运用系统函数setlocale(LC_ALL,“chs”);sleep(3000);用kbhit()判断玩家若不在三秒内输入表达式,将减少生命值,开始新的一轮。
④写入文件算法:fprintf(文件指针,写入文件类型,变量)。
3.算法实现

``#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<windows.h>
#include<conio.h>
#include<locale.h>
#include<math.h>
int i,j,k,life=10,score=0,num=0; //定义循环变量,用户生命值以及得分
#define Stack_increment 20   
#define Stack_Size 100
char ops[7] = { '+', '-', '*', '/', '(', ')', '#' };/*运算符数组*/
int  cmp[7][7] = {  /*用来进行比较运算符优先级的矩阵,3代表'=',2代表'>',1代表'<',0代表不可比*/
{ 2, 2, 2, 2, 2, 1, 1 },
{ 2, 2, 2, 2, 2, 1, 1 },
{ 1, 1, 2, 2, 2, 1, 1 },
{ 1, 1, 2, 2, 2, 1, 1 },
{ 2, 2, 2, 2, 3, 1, 0 },
{ 1, 1, 1, 1, 0, 1, 1 },
{ 2, 2, 2, 2, 2, 0, 3 }  };
typedef struct/*运算符栈的定义*/
{
    int stacksize;
    int *top;
    int *base;
}SeqStack;
typedef struct/* 运算数栈的定义*/
{
    int stacksize;
    int *top;
    int *base;
}numSeqStack;
void InitStack(SeqStack *S)/*初始化运算符栈*/
{
    S->base = (int *)malloc(Stack_Size * sizeof(int));
    S->top = S->base;
    S->stacksize = Stack_Size;
}
void InitStacknum(numSeqStack *S)/*初始化运算数栈*/
{
    S->base = (int *)malloc(Stack_Size * sizeof(int));
    S->top = S->base;
    S->stacksize = Stack_Size;
}
int IsEmpty(SeqStack *S)/*判操作符栈为空栈时返回值为真,反之为假*/
{
    return(S->top  == S->base ? 1 : 0);
}
int IsEmptynum(numSeqStack *S)/*判断栈S为空栈时返回值为真,反之为假*/
{
    return(S->top == S->base ? 1 : 0);
}
int IsFull(SeqStack *S)/*判断符号栈S为满栈时返回值为真,反之为假*/
{
    return (*S->top == Stack_Size - 1 ? 1 : 0);
}
int IsFullnum(numSeqStack *S)/*判断操作数栈为满栈时返回值为真,反之为假*/
{
    return (*S->top == Stack_Size - 1 ? 1 : 0);
}
void Push(SeqStack *S, char x)/*运算符栈入栈函数, '#'为结束标志*/
{
    if (* (S -> top) == Stack_Size - 1)
    {
        printf("Stack is full\n");
        S->base = (int *)realloc(S->base, (S->stacksize + Stack_increment) * sizeof(int));
        S->top = S->base + S->stacksize;
        S->stacksize = S->stacksize + Stack_increment;
    }
    else if (x == '#')
    {
        return;
    }
    else
    {
        *S->top++ = x;
    }
}
void Pushnum(numSeqStack *S, int x)/*运算数入栈函数*/
{
    if (*S->top == Stack_Size - 1)
    {
        S->base = (int *)realloc(S->base, (S->stacksize + Stack_increment) * sizeof(int));
        S->top = S->base + S->stacksize;
        S->stacksize = S->stacksize + Stack_increment;
    }
    else  if ((char)x == '#')
    {
        return;
    }
    else
    {
        *(S -> top) = x;
        S -> top++;
    }
}
int Pop(SeqStack *S)/*运算符栈出栈函数*/
{
    if (S->top == S->base)
    {
        return 0;
    }
    else
    {
        --(S->top);
        return 1;
    }
}
int Popnum(numSeqStack *S)/*运算数栈出栈函数*/
{
    if (S -> top == S -> base)
    {
        return 0;
    }
    else
    {
        --(S -> top);
        return 1;
    }
}
char GetTop(SeqStack *S)/*运算符栈取栈顶元素函数*/
{
    return (*(S->top - 1));
}
int GetTopnum(numSeqStack *S)/*运算数栈取栈顶元素函数*/
{
    if (S -> top == S -> base)
    {
        return (*(S -> top ));
    }
    return (* (S -> top - 1));
}

int Isoperator(char ch)        /*判断输入字符是否为运算符函数,是返回TRUE,不是返回FALSE*/
{
    int i;
    for (i = 0; i < 7; i++)
    {
        if (ch == ops[i])
            return (int)1;
    }
    return (int)0;
}
char Compare(char ch1, char ch2)/*比较运算符优先级函数*/
{                              /*保存优先级比较后的结果'>'、'<'、'='*/
    int i, m = 0, n = 0;
    int priority;
    for (i = 0; i < 7; i++)
    {
        if (ch1 == ops[i])
            m = i;
        if (ch2 == ops[i])
            n = i;
    }
    priority = cmp[m][n];
    switch (cmp[m][n])
    {
    case 1:
        return (char)('<');
    case 2:
        return (char)('>');
    case 3:
        return (char)('=');
    default:
        printf("表达式错误!\n");
        break;
    }
}
int Execute(int a, char op, int b)/*运算函数*/
{
    switch (op)
    {
    case '+':
        return  (b + a);
        break;
    case '-':
        return (b - a);
        break;
    case '*':
        return (b * a);
        break;
    case '/':
        return (b / a);
        break;
    }
}
int expression()/*输入一个简单算术表达式并计算其值。optr和operand分别为运算符栈和运算数栈,OPS为运算符集合*/
{
    int a, b, v;
    int sum = 0;
    char ch, op, temp;
    char str[100];
	numSeqStack operand;
    SeqStack optr;
	InitStack(&optr);     /*初始化,没有元素*/
    InitStacknum(&operand);
    printf("请输入表达式(#为结束符):\n");                      /*表达式输入*/
    scanf("%s",&str);                                         /*取得一行表达式至字符串中*/
    int i = 0;
    for (i; i < (strlen(str) + 1); )
    {
        ch = str[i];
        if (ch == '#')
        {
            if (IsEmpty(&optr))
            {
                v = GetTopnum(&operand);
                return v;
            }
            else
            {
                a = GetTopnum(&operand);/*运算数栈取栈顶元素函数*/
                Popnum(&operand);//运算数栈出栈函数
                b = GetTopnum(&operand);
                Popnum(&operand);
                op = GetTop(&optr);//调用运算符栈取栈顶元素函数
                Pop(&optr);//调用运算符栈出栈函数
                v = Execute(a, op, b);//调用运算函数
                Pushnum(&operand, v);//将运算结果放入运算数栈中
                if (ch == ')')//如果碰到右括号
                {
                    Pop(&optr);//继续调用运算符出栈函数
                }
            }
        }
		else if (!Isoperator(ch))/*判断输入字符是否为运算符,是返回TRUE,不是返回FALSE*/
        {
            int dis = 0;
            int j = i, j1 = i, j2 = i, j3 = i;
            int k;                                  /*记录原始值*/
            for (k = i; k < (strlen(str) + 1); )
            {
                if (!Isoperator(ch))
                {
                    i++;
                    ch = str[i];
                    k++;
                    dis = i - j;                            /*记录差距的位数*/
                    j1 = i;
                    j2 = i;
                    j3 = i;
                }
                else if (Isoperator(ch))
                {
                    break;
                }
            }
            for (j1 = j1 - dis; j1 < j2 ; j1++)
            {
                int temp;
                temp = (int)(str[j1] - '0');
                sum = sum + temp * pow(10, (j2 - j1 - 1));              /*求和*/
                if (j2 - j1 < 0)
                {
                    break;
                }
            }
            Pushnum(&operand, sum);//运算结果入栈
            sum = 0;
            dis = 0;
        }
		else if (Isoperator(ch))
        {
            if (optr.base == optr.top)//直到运算符栈为空
            {
                Push(&optr, ch);
                i++;
            }
            else
            {
                char buf ;
                temp = GetTop(&optr);
                buf = Compare(temp, ch);
                if (buf == '>')
                {
                    Push(&optr, ch);
                    i++;
                }
                else if (buf == '=')
                {
                    Pop(&optr);
                }
                else
                {
                    a = GetTopnum(&operand);
                    Popnum(&operand);
                    b = GetTopnum(&operand);
                    Popnum(&operand);
                    op = GetTop(&optr);
                    Pop(&optr);
                    v = Execute(a, op, b);
                    Pushnum(&operand, v);
                    if (ch == ')')
                    {
                        Pop(&optr);
                    }
                    else
                    {
                        Push(&optr, ch);
                    }
                    i++;
                }
            }
        }
    }
}
int player()//玩家开始游戏,当玩家生命值为0时,停止游戏
{int b[4];
int s;
srand((unsigned)time(NULL));
for(i=0;i<4;i++)
b[i]=rand()%13+1;
printf("生成的随机数为:");
for(j=0;j<4;j++)
printf("%d\t",b[j]);
printf("\n");
printf("请输入算术表达式(随机由生成的数组成),并以#结束\n");
setlocale(LC_ALL,"chs");
printf("如果在3秒钟内不输入表达式,则未得分\n");
Sleep(3000);
s=expression();
printf("结果是: %d\n",s);
if(kbhit())//判断玩家是否在3秒内开始输入
life-=5;
else
{
if(s==24)
{score=score+5;}//玩家在3秒内输入表达式,并且表达式的值为24,分数加1
else 
life-=5;
}
printf("本轮得分%d,生命值剩余%d(生命值为0时停止游戏)\n",score,life);
return score;
}
float count(int tag,float a,float b)//写出具体运算法则
{switch(tag)
{case 1: return(a+b);break;
case 2:return(a-b);break;
case 3:return(a*b);break;
case 4:return(a/b);break;
}
}
char print(int m)//判断操作符
{char s;
switch(m)
{case 1:s='+';break;
case 2:s='-';break;
case 3:s='*';break;
case 4:s='/';break;
}
return s;
}
void turn1(int i,int j,int k,float b[])//第一种表达式:a$b$c$d=
{float a1,a2,a3;
a1=count(i,b[0],b[1]);
a2=count(j,a1,b[2]);
a3=count(k,a2,b[3]);
if(a3==24)
{printf("((%f %c %f) %c %f) %c %f)=24\n",b[0],print(i),b[1],print(j),b[2],print(k),b[3]);//输出满足24点的表达式
num++;}
} 
void turn2(int i,int j,int k,float b[])//第二种表达式(a$(b$c))$d=
{float a1,a2,a3;
a1=count(j,b[1],b[2]);
a2=count(i,b[0],a1);
a3=count(k,a2,b[3]);
if(a3==24)
{printf("(%f%c(%f%c%f))%c %f=24\n",b[0],print(i),b[1],print(j),b[2],print(k),b[3]);
num++;}
}
void turn3(int i,int j,int k,float b[])//第三种表达式a$(b$(c$d))=
{float a1,a2,a3;
a1=count(k,b[2],b[3]);
a2=count(j,b[1],a1);
a3=count(i,b[0],a2);
if(a3==24)
{printf("(%f%c(%f%c(%f%c%f ))=24\n",b[0],print(i),b[1],print(j),b[2],print(k),b[3]);
num++;}
}
void turn4(int i,int j,int k,float b[])//第四种表达式a$((b$c)$d)=
{float a1,a2,a3;
a1=count(j,b[1],b[2]);
a2=count(k,a1,b[3]);
a3=count(i,a2,b[0]);
if(a3==24)
{printf("%f%c((%f%c%f)%c%f)=24\n",b[0],print(i),b[1],print(j),b[2],print(k),b[3]);
num++;
}
}
void turn5(int i,int j,int k,float b[])//第五种表达式(a$b)$(c$d)=
{float a1,a2,a3;
a1=count(i,b[0],b[1]);
a2=count(k,b[2],b[3]);
a3=count(j,a1,a2);
if(a3==24)
{printf("(%f%c%f)%c(%f%c%f)=24\n",b[0],print(i),b[1],print(j),b[2],print(k),b[3]);
num++;}
}
void dianshu()//穷举法求出所有表达式
{float a[4];
int tag,sign=1;
srand((unsigned)time(NULL));
for(i=0;i<4;i++)
a[i]=rand()%13+1;//随机产生四张扑克牌
for(j=0;j<4;j++)
printf("%f\t",a[j]);
printf("\n");
	for(i=1;i<5;i++)//穷举法列出所有表达式
		for(j=1;j<5;j++)
			for(k=1;k<5;k++)
			{
				turn1(i,j,k,a);
				turn2(i,j,k,a);
				turn3(i,j,k,a);
				turn4(i,j,k,a);
				turn5(i,j,k,a);
			}
}
void main()
{int sign=1,tag;
FILE* p;//定义文件指针
p=fopen("TopList.txt","w");
while(sign)//进行功能选择
{
	printf("请进行功能选择\n**1----列出生成的随机数所有满足24点的表达式----***\n**2----------------玩家开始游戏----------------***\n**0----------退出--------**\n");
	scanf("%d",&tag);
	switch(tag)
	{
	case 1:
		{dianshu();
		printf("满足24点的表达式有%d个\n",num);
		}break;
	case 2:
		{
		while(life)
		{
		player();
		fprintf(p,"本轮得分%d\n",score);//将本轮得分写入文件
	   }
		fclose(p);//关闭文件
	}break;
	case 0:sign=0;break;
	}
}
}
  1. 调试、测试及运行结果。
    ①调试结果
    在这里插入图片描述
    ②运行结果
    显示随机生成四个数值为24的表达式
    在这里插入图片描述

玩家进行游戏,以及写入文件结果
在这里插入图片描述

5.经验归纳
1)错误分析:
本次实验主要内容是24点游戏。我编写程序时遇到的困难如下:①
列出满足24点表达式是未考虑不够全面,以至于结果只输出了部分表达式。②运用栈对表达式值求解时,对栈用之前未进行初始化,以至于数据无法存储进去。经过和同学的讨论最终解决。③在输入表达式式我定义的是数组存放表达式,输入应该用SCanf(“%d”,&s);我用成了gets(),导致表达式输入错误未能进行求值运算。
2)个人心得:
通过这次实验我得到的收获是:算符优先法是教材上有关栈的应用的一个具体实例,考虑到算符优先法中对于运算符的操作是先入先出的,正好符合栈这种结构的存储使用规则,于是我们便可以利用栈来实现算。遇到困难时的心态要平和,冷静地去查找问题并解决问题。注意知识的总结和积累。最近,其实不止是本次程序实验带给我的收获,就是作为一个合格的程序员,要注意对知识的积累和知识体系的梳理,每隔一段时间就应该对自己近期的工作有个小结和反思,只有这样,才能不断进步,因此,我在CSDN开通了自己的博客,关于本次实验写的知识点总结在里面都有。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值