第三次作业--24点游戏

作者:罗傲宇

日期:2019/4/12

运行环境:Visual C++ 6.0

一、问题描述:
24点游戏是经典的纸牌益智游戏。
常见游戏规则:
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
基本要求: 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式。
1.程序风格良好(使用自定义注释模板)
2.列出表达式无重复。
提高要求:用户初始生命值为一给定值(比如3),初始分数为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。
1. 程序风格良好(使用自定义注释模板)
2.使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。
3.所有成绩均可记录在TopList.txt文件中。

二、算法设计思路及流程图:
算法分析:
1.基本要求:
先用rand()函数将四个1-13的随机数存入结构体
数组a[]中,其中symbol表示该数是否进行过操作,若为0则未进行过操作,若为1则表示已进行过操作;
caculate()函数返回两数进行基本操作后的值;
judgement()函数里面先将4个随机数的任意两个
数进行四种运算操作,在每一次运算操作后将该次操作结果赋给temp1;然后再将temp1与余下未进行操作数的任一个进行四种操作运算,在每一次操作后再将结果赋给temp2;然后再将temp2与余下的一个未进行操作的数进行四种操作运算,在每一次操作后再将结果赋给temp3,若temp324,则将操作数与操作符按序输出即为表达式。
2.提高要求
利用出栈入栈操作对中缀表达式进行运算并判断
定义栈内元素为结构体数组,该结构体类型包含操作数num和操作标识符symbol;若symbol
1则进行’+’ ‘-’操作,若symbol==2则进行’’ ‘/’操作;
Init()函数初始化栈;
Push()函数将操作数入栈;
Pop()函数将栈顶元素取出;
dispaly()函数将表达式键入并用getchar()函数对输入的每个字符进行判断,若为个位整数,则入栈,若为’+’ ‘-’符则栈顶元素symbol为1,若为’
’ ‘/’符则栈顶元素symbol为2,若为’(‘符则lay为1,若为’)’符则lay为0;判断栈顶第二个元素symbol的值,若为0,为出栈两个操作数合成十位数再入栈,若为2且lay不为1则出栈两个数进行’*’或‘/’操作后将结果入栈,若为1且lay为1则进行’+’ ‘-’操作后将结果入栈;上述操作完后出栈栈顶元素,返回栈顶元素。
在键入表达式前设置开始计时器start,在输入完后设置结束计时器end;
game()函数将display()输入的表达式运算结果进行判断,若为24且键入表达式时间(end-start)不多于30s,则得分+1,否则生命值-1,若生命值为0则游戏结束。

流程图:
1.基本要求
在这里插入图片描述

2.提高要求
在这里插入图片描述
三、代码实现

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#define MAX 20
bool size=false;                                 /*标志是否有运算结果,是则为true,否则为false*/
int line=1;
typedef struct                                   /*定义操作数结构体,a为操作数的值,symbol标示进行的操作*/
{
	double a;
	int symbol;
}task;

typedef struct
{
	task data[MAX];
	int top;
}seqlist;


seqlist *Init()                                /*初始化栈*/
{
	seqlist *s;
	s=(seqlist *)malloc(sizeof(seqlist));
	s->top=-1;
	return s;
}

int Push(seqlist *s,double x)                    /*将操作数入栈*/
{
	s->top++;
	s->data[s->top].a=x;
	s->data[s->top].symbol=0;
	return 1;
}

int Pop(seqlist *s,double *x)
{
	*x=s->data[s->top].a;
	s->top--;
	return 1;
}
struct Number                               /*24点随机四个数*/
{
	int symbol;
	double num;
}a[4];


double caculate(double num1,double num2,char caculate) /*计算两数的操作结果*/
{
	switch(caculate)
	{
	  case '+':
		  return(num1+num2);
	  case '-':
		  return(num1-num2);
	  case '*':
		  return(num1*num2);
	  case '/':
		  return(num1/num2);
	}
	return 0;
}

void judgement(char c[4])                        /*列出四种数所有可能的情况*/
{
	int i,j,m,n,o,p,q;
	double temp1,temp2,temp3;
	for(i=0;i<4;i++) 
	{
		for(j=i+1;j<4;j++)                       
		{
			for(o=0;o<4;o++)                     /*四种数任取两种先进行运算*/
			{
				temp1=double(caculate(a[i].num,a[j].num,c[o]));
				a[i].symbol=0;
				a[j].symbol=0;
				for(m=0;m<4;m++)
				{
					if(a[m].symbol!=0)
					{
						for(p=0;p<4;p++)         /*任取剩余一个数与上一个结果进行运算*/
						{
							temp2=caculate(temp1,a[m].num,c[p]);
							a[m].symbol=0;
							for(n=0;n<4;n++)
							{
								if(a[n].symbol!=0)
								{
									for(q=0;q<4;q++)  /*将最后一个数与上一次结果进行运算得到结果*/
									{
										temp3=caculate(temp2,a[n].num,c[q]);
										if(temp3==24) /*若结果等于24,则打印出该表达式*/
										{
											if(o<2&&p<2&&q<2)
											    printf("\n%d%c%d%c%d%c%d",int(a[i].num),c[o],int(a[j].num),c[p],int(a[m].num),c[q],int(a[n].num));
											else if(o<2&&p<2&&q>=2)
												printf("\n(%d%c%d%c%d)%c%d",int(a[i].num),c[o],int(a[j].num),c[p],int(a[m].num),c[q],int(a[n].num));
											else if(o<2&&p>=2)
												printf("\n(%d%c%d)%c%d%c%d",int(a[i].num),c[o],int(a[j].num),c[p],int(a[m].num),c[q],int(a[n].num));
											else if(o>2&&p<2&&q>2)
												printf("\n((%d%c%d)%c%d)%c%d",int(a[i].num),c[o],int(a[j].num),c[p],int(a[m].num),c[q],int(a[n].num));
											else if(o>2)
												printf("\n%d%c%d%c%d%c%d",int(a[i].num),c[o],int(a[j].num),c[p],int(a[m].num),c[q],int(a[n].num));
											size=true;
										}
									}
								}
							}
							a[m].symbol=1;
						}
					}
				}
				a[j].symbol=1;
			}
		}
		a[i].symbol=1;
	}
}

int display()                                    /*对输入的表达式进行运算并判断的函数*/
{
	seqlist *s;
	char ch,ch2;
	char ch3[MAX];
	int i=0,lay;
	double o1,o2,temp,ch1;                       /*o1表示栈顶元素,o2表示栈顶第二个元素,temp临时存储两数操作后的值*/
	s=Init();
	printf("\n\n\t\t请输入表达式:");
	while((ch=getchar())!='\n')
	{
		if(ch==' ')
			continue;
		if(ch>47&&ch<58)
		{
			ch1=ch-48;
			Push(s,ch1);
		}
		else if(ch=='+'||ch=='-')
		{
			s->data[s->top].symbol=1;
			ch3[i++]=ch;
			continue;
		}
		else if(ch=='*'||ch=='/')
		{
			s->data[s->top].symbol=2;
			ch2=ch;
			continue;
		}
		else if(ch=='(')
		{
			lay=1;
		}
		else if(ch==')')
		{
			lay=0;
		}
		if(lay!=1&&s->data[s->top-1].symbol==2)
		{
			Pop(s,&o1);
			Pop(s,&o2);
			temp=caculate(o2,o1,ch2);
			Push(s,temp);
		}
		if(lay==1&&s->data[s->top-1].symbol==1)
		{
			Pop(s,&o1);
			Pop(s,&o2);
			temp=caculate(o2,o1,ch3[--i]);
			Push(s,temp);
		}
		if(s->top!=0&&s->data[s->top-1].symbol==0)
		{
			Pop(s,&o1);
			Pop(s,&o2);
			temp=o2*10+o1;
			Push(s,temp);
		}
	}
	for(int j=i;j>0;j--)
	{
		    Pop(s,&o1);
			Pop(s,&o2);
			temp=caculate(o2,o1,ch3[j-1]);
			Push(s,temp);
	}

	Pop(s,&o1);
	return((int)o1); 
}

void game()                                      /*开始游戏*/
{
	FILE *fp;
	fp=fopen("TopList.txt","at");
	int i,j,m,sum[4];
	double temp;
	clock_t end,start;                           /*设置计时器计算键入表达式时间*/
	i=3;
	m=0;
	printf("             *************输入表达式请在30s内输入*************\n\n\n");
	while(i)
	{
		if(line!=0)
		{
			line--;
			if(getchar()=='\n')
				continue;
		}
		srand((int)time(0));
	    for(j=0;j<4;j++)
		{
		   sum[j]=rand()%13+1;
		}
        printf("\t四个随机数为:");
	    for(j=0;j<4;j++)
		   printf("%-4d",(int)sum[j]);
		start=clock();                           /*记录刚开始输入表达式时间*/
		if(display()==24)
		{
			end=clock();                         /*记录输入表达式后时间*/
			temp=(double)(end-start)/1000;
			if(temp<30)
				m++;
			else
			{
				printf("\t\t输入超时!");
				i--;
			}
		}
		else
			i--;
		printf("\n\t\t\t\t得分:%d\n\n",m);
	}
	fprintf(fp,"该次游戏的总得分为:%d\n\n",m);
	fclose(fp);
	printf("***----------------游戏结束----------------***\n");
}

void menu()                                      /*选择是否继续游戏的菜单函数*/
{
	int choose;
	printf("\n\t\t请选择是否进行游戏:");
	printf("\n\t\t\t1.进行游戏");
	printf("\n\t\t\t2.结果程序");
	printf("\n\n\t\t选择序号:");
	scanf("%d",&choose);
	switch(choose)
	{
    	case 1:
			system("cls");
			game();
			break;
		case 2:
			return;
	}
}

int main()
{
	char c[4]={'+','-','*','/'};                 
	srand((int)time(0));
	for(int i=0;i<4;i++)
	{
		a[i].num=rand()%13+1;
		a[i].symbol=1;
	}
	printf("四个随机数为:");
	for(i=0;i<4;i++)
		printf("%4d",(int)a[i].num);
	printf("\n可满足表达式:");
	judgement(c);
	if(!size)
		printf("无!");
	printf("\n");
	menu();
	return 0;
}

四、调试截图
1.judgement()函数无法输出小括号
在这里插入图片描述
发现是代码中确实运算符的优先级判断,修改之后的代码为:
在这里插入图片描述
运行截图:
在这里插入图片描述

五、测试截图
主要函数截图:
display()函数:
运行截图:
在这里插入图片描述
judgement()函数:
运行截图:

在这里插入图片描述
在这里插入图片描述

六、运行截图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

七、个人总结
有关设置计时器有了更清晰的认知,更深入了解了有关穷举法的使用,对于随机数函数rand(),需要自己设置随机数种子(seed),否则在调用时会自动设随机种子为1,然后每次运行程序所产生的随机数都是一样的,故需要利用srand()设好随机种子,此次代码中我用的是当前秒数作为随机种子。
这次作业还使用到了数据结构栈的操作,复习了半个多小时的有关操作以及这次的实际应用,让我对于入栈出栈的操作更加的熟悉。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值