欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

24点游戏

程序员文章站 2024-01-29 12:54:22
...

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

程序源码
基本要求:

//author :lyq
//time :2019-4-9
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime> 
#include<string>
using namespace std;
int n=4;//一共四个数字 
int number[4]={0};//存储4个数字
string s[4];//用于记录运算表达式的字符串数组 
int count=0;//用于记录得到24点的表达式个数 
string c[100];//记录符合的表达式的字符串数组 
int f(int n)
{
 
if(n==1)//完成三次运算
{
	if(number[0]==24)//结果为24 
	{	
		cout<<s[0]<<endl;//输出得到24的表达式 
		c[count]=s[0];
		count++;
		return 1;
	} 
	else
		return 0;
}
//从数组中任意取出两个数的组合 
for(int i=0;i<n;i++)
{
	for(int j=i+1;j<n;j++)
	{
		double a,b;
		string x,y;
		a=number[i];
		b=number[j];
		number[j]=number[n-1];//将最后一位的赋给空出来的j 		
		x=s[i];
		y=s[j];
		s[j]=s[n-1];//最后一位的数字放入第j个 
		//加法 
		number[i]=a+b;//第一个空间保存前两个的运算结果 
		s[i]='('+x+'+'+y+')';//将第一步的运算结果存入数组 
		f(n-1);
		
		//减法;分顺序 
		number[i]=a-b;
		s[i]='('+x+'-'+y+')';
		f(n-1);
		
		number[i]=b-a;
		s[i]='('+y+'-'+x+')';
		f(n-1);
		//乘法 
		number[i]=a*b;
		s[i]='('+x+'*'+y+')';
		f(n-1);
		//除法;分顺序, 注意分母为零的情况 
		if(b!=0)
		{
			number[i]=a/b;
			s[i]='('+x+'/'+y+')';
			f(n-1);
		}
		if(a!=0)
		{
			number[i]=b/a;
			s[i]='('+y+'/'+x+')';
			f(n-1);
		}
		//当以上的运算都无法得到24的结果时,还原数据,进行下一个循环 
		number[i]=a;
		number[j]=b;
		s[i]=x;
		s[j]=y;
	
	}
	 
}
}
int get(int begin, int end )
{
        return rand()%(end-begin+1)+begin;
}
int main()
{
	srand((unsigned int)time(NULL));//根据当前时间产生随机种子 
	cout<<"生成的四个随机数如下:"<<endl;
    for (int i = 0; i < 4; ++i) //生成4个1~13之间的数字
	{ 
        number[i]=get(1,13);
		cout<<number[i]<<" "; 
    }
    cout<<endl;
	for(int i=0;i<4;i++){
		if(number[i]==1)
			s[i]='A';
		else if(number[i]==11) 
			s[i]='J';
		else if(number[i]==12) 
			s[i]='Q';
		else if(number[i]==13) 
			s[i]='K';
		else s[i]='0'+number[i];
	} 
	f(n);
	return 0;
}
提高要求:
//author :lyq
//time :2019-4-9
#include<iostream>
#include<fstream>
#include<cstdlib>
#include<cmath>
#include<ctime> 
#include<string>
using namespace std;
int n=4;//一共四个数字 
int number[4]={0};//存储4个数字
string s[4];//用于记录运算表达式 
int count=0;//用于记录得到24点的表达式个数 
string c[1000];//记录符合的表达式的字符串数组 
int f(int n)
{
	 
	if(n==1)//完成三次运算
	{
		if(number[0]==24)//结果为24 
		{	
//			cout<<s[0]<<endl;//输出得到24的表达式 
			c[count]=s[0];//记录可以得到24的表达式字符串 
			count++;
			return 1;
		} 
		else
			return 0;
	}
	//从数组中任意取出两个数的组合 
	for(int i=0;i<n;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			double a,b;
			string x,y;
			a=number[i];
			b=number[j];
			number[j]=number[n-1];//将最后一位的赋给空出来的j 		
			x=s[i];
			y=s[j];
			s[j]=s[n-1];//最后一位的数字放入第j个 
			//加法 
			number[i]=a+b;//第一个空间保存前两个的运算结果 
			s[i]='('+x+'+'+y+')';//将第一步的运算结果存入数组 
			f(n-1);
			
			//两种减法 
			number[i]=a-b;
			s[i]='('+x+'-'+y+')';
			f(n-1);
			
		number[i]=b-a;
		s[i]='('+y+'-'+x+')';
		f(n-1);
		//乘法 
		number[i]=a*b;
		s[i]='('+x+'*'+y+')';
		f(n-1);
		//两种除法, 注意分母为零的情况 
		if(b!=0)
		{
			number[i]=a/b;
			s[i]='('+x+'/'+y+')';
			f(n-1);
		}
		if(a!=0)
		{
			number[i]=b/a;
			s[i]='('+y+'/'+x+')';
			f(n-1);
		}
		//当以上四则运算的结果都不能满足条件时
		//为了方便进入下一个for循环, 需要将之前的i和j上的值都重新找回 
		number[i]=a;
		number[j]=b;
		s[i]=x;
		s[j]=y;
	
	}
	
	}
}
int get(int begin,int end)//获取随机数 
{
        return rand()%(end-begin+1)+begin;
}
int main()
{
	int life=3;//初始升,生命值为3 
	int score=0;//用户得分,每正确一次加十分 
	string a;//定义输入的字符串 
	srand((unsigned int)time(NULL));
cout<<"生成的四个随机数如下:"<<endl;
	for(int i = 0; i < 4; ++i) //生成4个1~13之间的数字
		{ 
        	number[i]=get(1,13);
			cout<<number[i]<<" "; 
    	}
		
		cout<<endl;
	
for(int i=0;i<4;i++)//将11~13改成相应的扑克牌符号 
{
	if(number[i]==1) 
		s[i]='A';
	else if(number[i]==11) 
		s[i]='J';
	else if(number[i]==12) 
		s[i]='Q';
	else if(number[i]==13) 
		s[i]='K';
	else 
		s[i]='0'+number[i];
} 
f(n);//调用函数 
while(life)//当生命值不为零时循环 
{
	
	cout<<"请输入你的表达式!"<<endl;
	double start=clock();//开始时间 
	cin>>a; 
	double end=clock();//结束时间 
	double time;
	time=(double)(end-start)/CLOCKS_PER_SEC;//输入所花费的总时间 
	if(time>48.0)//当超过48秒时间时,进行下一轮游戏 
	{
		cout<<"你超时了!"<<endl;
		life-=1;
		cout<<"剩余生命值为:"<<life<<endl; 
		continue;
	} 
	int k;
	for(k=0;k<count;k++)
	{
		if(a==c[k])//输入的字符串表达式符合相应的情况
		{
		 	score+=10; 
			cout<<"恭喜!你输入的表达式成功得到了24!,成功加十分!"<<endl;
			break; 
		} 
		
	} 
	if(count==k)//输入表达式无法得到24的结果,进行下一轮的游戏 
	{
		cout<<"sorry!游戏失败!"<<endl;
		life-=1;
		cout<<"剩余生命值为:"<<life<<endl;
		continue;
		cout<<endl;
	}			 
} 
ofstream out;
out.open("E://TopList.txt");//每次的得分记录在文件中 
out<<"此次测试得分为:"<<score<<endl; 
return 0;

}
调试与测试
调试:
24点游戏

24点游戏

24点游戏

24点游戏
测试:
基本要求:

24点游戏

24点游戏
提高:

24点游戏

24点游戏
总结:

这次的24点游戏,一开始的想法是进行穷举法,将所有情况都列举出来进行结果判断,如果结果为24,则将其输出,后来发现简单的for循环穷举对于括号的考虑是个问题,对此需要进行多种括号分类的列举与处理。后来一想,为什么不每次取两个数进行加减乘除的运算,将结果又与下一个数重复此过程,直到四个数都已在计算中使用过了,而每次都将运算表达式两侧加上括号,也就不用单独处理括号的问题了。

此次作业还是有些不足之处,自己的能力还是不够,需要继续提升。