24点游戏

一.问题描述
24点游戏是经典的纸牌益智游戏。
常见游戏规则:
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
随机生成4个代表扑克牌牌面的数字字母,由答题者答题,判断是否等于24,根据答题者的选择列出所有可能算出24的表达式。
二.算法设计思路
24点游戏主要就是用穷举法,列出四个数字加减乘除和括号所有出现的结果的。
定义一个游戏类。
通过调用srand()和rand()函数,随机显示出4张纸牌,这四张牌从1~K这13张牌中随机调出。
定义两个栈分别存入算数符号和数值。
定义函数比较运算符的优先级。
函数计算玩家的表达式,来判断答案是否为24,
定义函数用枚举法,要列出所有符合要求的表达式,
函数输出所有符合条件表达式。
三.代码实现

#include<iostream>
#include<ctime>
#include<string>
#include<stack>
#include<cmath>
using namespace std;
#define SIZE 20
#define MAXSIZE 40 
const int count=4;//四个数字
const int answar=24;//最后的答案,定义为const 
 int life=3;//生命值
 int score=0;//分数
//字符节点定义
struct node                       
{
	char *base;
	char *top;        
	int size;
}m;                   
//数值结点定义
struct list                   
{
	float *base;
	float *top;
	int size;
}n;
class game
{
public:

	double num[count]; //数值
	string exp[count];//主要存A,J,Q,K
	string ans[20];//答案
	bool flag;
	int shu,find;

	void InitNum(list& S);   //初始化数值栈
	void InitSymbol(node& S);   //初始化字符栈
	void PushNum(list& S,float e);  //数值入栈
	void PushSymbol(node& S,char e);   //字符入栈 
    float PopNum(list& S);   //数值出栈
	char PopSymbol(node& S);   //字符出栈
	int Prior(char c);//比较优先级
	int Prior2(char c);
	void card();//随机生成四个数字
	float card(char* str); //计算表达式
	void judge();//判断答案是否正确,调用card(char* str)函数
	void Find(int n);
	void out();//输出答案
};
 void game::InitNum(list& S)                   
{
	S.base=(float *)malloc(SIZE *sizeof(float));  //动态分配空间
	if(!S.base)
	{
		cout<<"errer1"<<endl;
		exit(1);
	}
	S.top=S.base;
	S.size=20;
}
void game::InitSymbol(node& S)                    
{
	S.base=(char *)malloc(SIZE *sizeof(char));    
	if(!S.base)                                  
	{
		cout<<"errer2"<<endl;
        exit(1);
	}
	S.top=S.base;                                
	S.size=30;                                    
}
void  game::PushNum(list& S,float e)   
{
	*S.top++=e;    //将节点的值存入数组中 
}
void game::PushSymbol(node& S,char e)   
{
	*S.top++=e;   //将下一个字符存储为当前 	
}
float game::PopNum(list& S)            
{
	if(S.base==S.top) cout<<"整数栈为空,不能输出";
	float x= *(--S.top); 
	return x;
}
char game::PopSymbol(node& S)
{
	if(S.base==S.top) cout<<"字符栈为空,不能输出";
	char x= *(--S.top);
	return x;
}
int game::Prior(char c)                          
{
	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 prior1"<<endl;
	}
	return r;
}
int game::Prior2(char c)
{
	int w;
	switch(c)
	{
		//在此处W相当于权重 
		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 prior2"<<endl;
	}
	return w;
}
void game::card()
{    
	int i,k; 
	srand((unsigned)time(NULL));   //随机函数种子 
	for(i=0;i<count;i++)    
	{
		char ch[20];
		num[i]=rand()%13+1;   //随机生成1~13其中一个数字
		itoa(num[i],ch,10);   //将这个十进制的整数转换为字符型   
	    exp[i]=ch;        //将字符存储在符号数组中 
	}
	cout<<"游戏数字是:";
	for(i=0;i<count;i++)
	{
		k=num[i];
		switch(k)
		{
			case 1:
				cout<<"A"<<" ";
				break; 
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			case 7:
			case 8:
			case 9:
			case 10:
				cout<<num[i]<<" ";    
				break;
			case 11:
			 	cout<<"J"<<" ";
			 	break;
			case 12:
				cout<<"Q"<<" ";
				break;
			case 13:
				cout<<"K"<<" ";
				break;
		}
		
	}
	cout<<endl;
}
float game::card(char* str)
{
	int i=0;                     
	float x;                    //存储计算结果 
	PushSymbol(m,';');            //初始化字符栈,中只有一个元素';',整数栈为空栈
	while(str[i]&&i<SIZE-1)     //处理中缀表达式循环  表达式没有到最后且数组没有越界 
	{ 
		x=0;
		if(str[i]==' ')         //去掉无效字符 
		{
			i++;
			continue;
		}
		while(str[i]>=48&&str[i]<=57)      
		{
			x=x*10+str[i]-48;              //把字符的ASCILL码变成数字的
			i++;
		}
		if(x!=0) 
			PushNum(n,x);                
		else
		{
			int a=Prior2(str[i]);   	   	//处理栈外字符
			int b=Prior(*(m.top-1)); 		//处理栈内字符,成员变量是字符栈中的栈顶元素
			if(a>b)                  		//栈外运算符优先级高于栈内运算符优先级
			{
				PushSymbol(m,str[i]);i++;}    //将其插入到字符栈中
			else 
				switch(PopSymbol(m))           //优先级相反,括号里面的参数变量是字符栈内的首元素
			{
				case '+':
					x=PopNum(n);
					x+=PopNum(n);     //从整数栈中抛出两个数值,进行加运算
					PushNum(n,x);
					break;              //计算完之后结果重新入栈 
				case '-':
					x=PopNum(n);
					x-=PopNum(n);     //从整数栈中抛出两个字符,进行减运算 
				PushNum(n,x);     //计算之后结果存入栈中 
					break;
				case '*':
					x=PopNum(n);
					x*=PopNum(n);
					PushNum(n,x);
					break;
				case '/':
					x=PopNum(n);
					if(x!=0.0)
					{
						x=PopNum(n)/x;
						PushNum(n,x);      
					}
					else 
					{
						cout<<"零不能做除数"<<endl;
						i=SIZE-1;
					}
					break;
				case '(':
					i++;       
					break;
				case ';':
					i=SIZE-1;    
					break;
				default:cout<<"输入错误!"<<endl;
			} 
		} 
	}
	x=PopNum(n);       //将计算结果返回 
	return x;
}
void game::judge()
{
	char str[32];        		
	char a[SIZE]; 
	InitSymbol(m);      		
	InitNum(n);     	
	cout<<"输入你的答案,并以;结束:"; 
	cin>>str;             		//输入一个24点的表达式存放在数组中 
	float z=card(str);  		//将这个表达式进行计算 
cout<<"结果为:"<<z<<endl;   //输出结果 
	if(24==(int)z)
	{
		cout<<"回答正确的!"<<endl;
		score+=10;
		cout<<"分数"<<score<<endl;
	}
	else
	{
		cout<<"回答错误的!"/*<<"你还有"<<(life--)<<"次机会"*/<<endl;
		life--;
	}	
}
void game::Find(int n)   
{
	if(n==1)       //n为1时,给出相应的处理
	{
		if(fabs(num[0]-answar)<=0.0) //判断数值是否是24
		{
			ans[find]=exp[0];
			flag=true;            //结果标识
			shu++;                  
			find++;             //计算表达式个数 
		}
	}
 
	for(int i=0;i<n;i++) //递归循环开始,使用穷举法的方法
	{
		for(int j=i+1;j<n;j++)
		{
			double a,b;
			string expa,expb;     //计算的表达式
			
			a=num[i];    					//把两个随机数赋给a和b,随机数放在了数组中
			b=num[j];
			num[j]=num[n-1];				
			expa=exp[i];           
			expb=exp[j];
			exp[j]=exp[n-1];
			exp[i]='('+expa+'+'+expb+')';
			num[i]=a+b;
			Find(n-1);
			exp[i]='('+expa+'-'+expb+')';
			num[i]=a-b;
			Find(n-1);
			exp[i]='('+expb+'-'+expa+')';
			num[i]=b-a;
			Find(n-1);
			exp[i]='('+expa+'*'+expb+')';
			num[i]=a*b;
			Find(n-1);
			//除数为0
			if(b!=0)
			{
				exp[i]='('+expa+'/'+expb+')';
			    num[i]=a/b;
			    Find(n-1);
			}
 
			if(a!=0)
			{
				exp[i]='('+expb+'/'+expa+')';
				num[i]=b/a;
			    Find(n-1);
			}
 
			num[i]=a;          //递归调用的回溯,为了不影响下一次调用 
			num[j]=b;
			exp[i]=expa;
			exp[j]=expb;
		}
	}
}
void game::out()
{
	char a;
	cout<<"是否想看答案?";
	cout<<"输入y,或n;";
	cin>>a;
	Find(count);
	if(a=='y')
	{
		if(flag==true)
		{
			cout<<"\n成功!"<<endl;
			cout<<"总共的方法有:"<<shu<<endl;
			for(int i=0;i<find+1;i++)
			{
				cout<<ans[i]<<endl;
			}
		}
		else
			cout<<"无正确的解!"<<endl;		    
	}	
}
void menu()
{
	cout<<"*********欢迎来到24点游戏***************\n";
	cout<<"          1.开始游戏\n";
	cout<<"          2.游戏规则\n";
	cout<<"          3.退出游戏\n"; 
	cout<<"****************************************\n";
}
void rule()
{
	cout<<"游戏说明:"<<endl;
	cout<<" 从扑克中每次取出4张牌。使用加减乘除,"<<endl;
	cout<<" 第一个能得出24者为赢.(其中,J代表11,Q代表12,K代表13,A代表1)"<<endl;
	cout<<"答题者如果碰到如J、Q、K对应成11,12,13;"<<endl;
}
int main()
{
	game g24;
	g24.flag = false;
	g24.shu= 0;
	g24.find= 0;
	int option;  //选项 
	int flag;    //标志 
	int score;
	char a;
	do
	{    
		menu();
		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: 
				g24.card();         
				g24.judge();    
				g24.out();          
				break;
			case 2: 
				rule();  
				break;
            case 3:
				exit(0);
				break;
		}
	
		if(life>0)
		{
			menu();
			cout<<"请输入你的选项:";
		    cin>>option;
		}
		else
			exit(0);
	}
}

四.总结收获:
程序还有点缺陷,比如不能判断答题者用的是不是系统给定的四个数字,只要结果为24它都判对,显然是不合理的,还没有解决这个问题。还有之前的数据结构与算法设计学的不好,很多知识也还没有很好的理解,这次使用栈也比较吃力,参考了很多24点的例子,也结合自己的理解,在完成基础要求,还实现了计算玩家表达式的功能,还有玩家的生命值,在编程过程中也有很多问题,定义类完后没在大括号后加括号,导致很多错误,还是自己不够细心,关于栈的知识也是这周恶补,理解不是很深,这次代码不是那么完美,但我有很多收获,对这次编程结果还是比较满意的。这次编程锻炼了我的逻辑思维能力,提高解决问题的能力,也让我看到自己的能力还是不够,而且算法结构还比较重要,要好好理解,还要注重实践,之后还要优化程序,使它更完美。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值