C++语言实现 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文件中。

二、关键算法构造

在这里插入图片描述

三、程序实现

#include<iostream>
#include<iomanip>
#include<cstdlib>
#include <stdlib.h>
#include <stdio.h>
#include<ctime>
#include <string>
#include <stack>
#include <fstream>
using namespace std;
int allnumber[13] = { 1,2,3,4,5,6,7,8,9,10,11,12,13 };
int score=0;
double result;
char card[] = { 'A','2','3','4','5','6','7','8','9','10','J','Q','K' };
char pai[4] = {'@','@','@','@'};//对牌初始化 
double nums[4];
char ope[4] = { '+','-','*','/' };
void GetCards(int a[])
{
	for(int i = 0; i < 4; i++) {
		pai[i] = '@';
	}
	while(pai[0]=='0'||pai[0]=='@'||pai[1]=='0'||pai[1]=='@'||pai[2]=='0'||pai[2]=='@'||pai[3]=='0'||pai[3]=='@')//若牌没有输入,则重新输入 
	{
		int i=0;
		int j;
	    for (i = 0; i<4; i++)
		{
			j =a[i];
			pai[i] = card[j];
		}
		for (i = 0; i<4; i++)
		{
			if (pai[i] == 'A')  nums[i] = 1;
			if (pai[i] == '2')  nums[i] = 2;
			if (pai[i] == '3')  nums[i] = 3;
			if (pai[i] == '4')  nums[i] = 4;
			if (pai[i] == '5')  nums[i] = 5;
			if (pai[i] == '6')  nums[i] = 6;
			if (pai[i] == '7')  nums[i] = 7;
			if (pai[i] == '8')  nums[i] = 8;
			if (pai[i] == '9')  nums[i] = 9;
			if (pai[i] == '10') nums[i] = 10;
			if (pai[i] == 'J')  nums[i] = 11;
			if (pai[i] == 'Q')  nums[i] = 12; 
			if (pai[i] == 'K')  nums[i] = 13;
		}
	}
	
	cout<<"            随机获得的4张牌为"<<pai[0]<<","<<pai[1]<<","<<pai[2]<<","<<pai[3]<<","<<endl;
}
double calculate(double a,double b,char op)
{
	if(op == '+') return a + b;
	if(op == '-') return a - b;
	if(op == '*') return a * b;
	if((op == '/')&&(b != 0)) return a/b;
}
void qiongju()
{
	double  temp[3], tem[2];   //第一个符号放置后,经过计算后相当于剩下三个数,这个数组用于存储这三个数  
	double  sum;  //求得的和  
	int  judge = 0;   //判断是否找到一个合理的解   
	for (int i = 0; i < 4; i++)  //第一次放置的符号  
	{
		for (int j = 0; j < 4; j++)   //第二次放置的符号   
		{
			for (int k = 0; k < 4; k++)    //第三次放置的符号    
			{
				for (int m = 0; m < 3; m++)      //首先计算的两个相邻数字,共有3种情况,相当于括号的作用     
				{
					if (nums[m + 1] == 0 && ope[i] == '/') break;
					temp[m] = calculate(nums[m], nums[m + 1], ope[i]);
					temp[(m + 1) % 3] = nums[(m + 2) % 4];
					temp[(m + 2) % 3] = nums[(m + 3) % 4];      //先确定首先计算的两个数字,计算完成相当于剩下三个数,按顺序储存在temp数组中       
					for (int n = 0; n < 2; n++)       //三个数字选出先计算的两个相邻数字,两种情况,相当于第二个括号       
					{
						if (temp[n + 1] == 0 && ope[j] == '/') break;
						tem[n] = calculate(temp[n], temp[n + 1], ope[j]);
						tem[(n + 1) % 2] = temp[(n + 2) % 3];        //先确定首先计算的两个数字,计算完成相当于剩下两个数,按顺序储存在temp数组中        
						if (tem[1] == 0 && ope[k] == '/') break;
						sum = calculate(tem[0], tem[1], ope[k]);       //计算和               
						if (sum == 24)        //若和为24       
						{
							judge = 1;         //判断符为1,表示已求得解          
							if (m == 0 && n == 0)
								cout << "((" << nums[0] << ope[i] << nums[1] << ")" << ope[j] << nums[2] << ")" << ope[k] << nums[3] << "=" << sum << endl;
							else if (m == 0 && n == 1)
								cout << "(" << nums[0] << ope[i] << nums[1] << ")" << ope[k] << "(" << nums[2] << ope[j] << nums[3] << ")=" << sum << endl;
							else if (m == 1 && n == 0)
								cout << "(" << nums[0] << ope[j] << "(" << nums[1] << ope[i] << nums[2] << ")" << ope[k] << nums[3] << "=" << sum << endl;
							else if (m == 1 && n == 1)
								cout << nums[0] << ope[k] << "((" << nums[1] << ope[i] << nums[2] << ")" << ope[j] << nums[3] << ")=" << sum << endl;
							else if (m == 2 && n == 0)
								cout << "(" << nums[0] << ope[j] << nums[1] << ")" << ope[k] << "(" << nums[2] << ope[i] << nums[3] << ")=" << sum << endl;
							else if (m == 2 && n == 0)
								cout << nums[0] << ope[k] << "(" << nums[1] << ope[j] << "(" << nums[2] << ope[i] << nums[3] << "))=" << sum << endl;          //m=0,1,2 n=0,1表示六种括号放置可能,并按照这六种可能输出相应的格式的计算式               
						}
					}
				}
			}
		}
	}
	if (judge == 0)
		cout << "            这四张扑克牌无法找到一个合理的解" << endl;  //如果没有找到结果,符号位为0 
}

bool isone(char c){
	return (c=='+' || c=='-');
}
bool istwo(char c){
	return (c=='*' || c=='/');
}
string shorten(string m){
	stack<char> s;
	string sur;
	int i;
	char w;
	sur;
	
	for(i=0;i<m.size();i++){
		if(isdigit(m[i]) || m[i]=='.'){
			while(isdigit(m[i]) || m[i]=='.')	sur += m[i++];
			i--;
			sur += '$';
		}
		else if(isone(m[i])){
			while(s.size() && (isone(s.top()) || istwo(s.top()))){
				sur+=s.top();
				s.pop();
			}
			s.push(m[i]);
		}
		else if(m[i]==')'){
			while(s.top()!='('){
				sur+=s.top();
				s.pop();
			}
			s.pop();
		}
		else if(istwo(m[i])){
			while(s.size() &&  istwo(s.top())){
				sur+=s.top();
				s.pop();
			}
			s.push(m[i]);
		}
		else s.push(m[i]);
	}
	while(s.size()){
		sur+=s.top();
		s.pop();
	}
	return sur;
}
double tentimes(int n){
	double res=1;
	for(int i=0;i<n;i++){
		res *= 10;
	}
	return res;
}
double str2double(string s){
	double res=0;
	char c;
	int dec=0;
	for(int i=1;i<=s.size();i++){
		c=s[i-1];
		if(c=='.') dec=i;
		else if(!dec) res = res*10 + c-'0';
		else res += (c-'0')/tentimes(i-dec);
	}
	return res;
}
//计算输入的表达式 
double calculate(string s){
	double res, t;
	stack<double> num;
	string temp;
	int i;
	for(i=0;i<s.size();i++){
		temp="";
		if(isdigit(s[i]) || s[i]=='.'){
			while(isdigit(s[i]) || s[i]=='.') temp+=s[i++];	//如果最后一位是数字,这样做会出错 
			num.push(str2double(temp));
		}
		else{
			switch (s[i]){
				case '+': t=num.top(); num.pop(); t+=num.top();num.pop();num.push(t);break;
				case '-': t=num.top(); num.pop(); t=num.top()-t;num.pop();num.push(t);break;
				case '*': t=num.top(); num.pop(); t*=num.top();num.pop();num.push(t);break;
				case '/': t=num.top(); num.pop(); t=num.top()/t;num.pop();num.push(t);break;
				default: cerr << "输入表达书有误!" << endl; system("pause");break;
			}
		}
	}
	res=num.top();
	return res;
}
void jisuan()
{
	string mid, sur;
	cin >> mid;
	sur = shorten(mid);
	result = calculate(sur);
}
int main()
{
	srand((unsigned)time(0));//获取当前时间作为参数,生可以随时间变化的随机数
	time_t begin,end;
	double ret;
	int choose;
	int flag=1;
	int life=3;
	int arr[4];
	//GetCards();
	//jisuan();
	//qiongju();
	cout<<"                  24点小游戏"<<endl;
	cout<<"            *---------------------*"<<endl;
	cout<<"                 1.开始游戏"<<endl; 
	cout<<"                 2.结束游戏"<<endl;
	cout<<"            *---------------------*"<<endl;
	cout<<"             请输入编号选择功能:";
	cin>>choose;
	switch(choose)
	{
		case 1:
			{
				while(flag)
				{
					cout<<"            **剩余生命值为:"<<life<<endl;
					cout<<"            **当前所得分数为:"<<score<<endl;
					for(int i=0;i<4;i++)
					{
						arr[i] = rand() % 13 ;
					}
					begin=clock();//开始计时 
					GetCards(arr);
					jisuan();
					end=clock();//结束计时 
					ret=double(end-begin)/CLOCKS_PER_SEC;
					if(ret>60)
					{
						cout<<"            你已经超过60s了!"<<endl;
						life = life - 1;
					} 
					else
					{
						if(result == 24)
						{
							cout<<"            计算成功!"<<endl;
							score = score + 10;
						}
						else
						{
							cout<<"            计算出错!"<<endl;
							life = life - 1;
						}
					}
					if(life==0)
					{
						flag = 0;
						cout<<"            你已经用完了所有次数!"<<endl;
						
					}
				}
				break;
			}
		case 2:
			{
				break;
			}
		default:
			{
				cout<<"请输入1~3的数字!";
			}
	}
	cout<<"            共计获得分数为:"<<score<<endl;
	return 0;
}

四、调试、测试及运行结果

1)计算成功

在这里插入图片描述

2)计算失败

在这里插入图片描述

3)计算失败至退出

在这里插入图片描述

4)超出规定时间

在这里插入图片描述
五、经验总结
1、加深了对随机数产生的相关知识,并且了解到了多次生成随机数的方法
2、学习到了对于算术表达式的计算,运用一个运算数栈和一个运算符栈对表达式进行运算得出表达式
3、学习了24点的穷举算法,先将两个随机数组合起来,将四个数转化为三个数,再将三个数转化为两个数,最后求出结果与24比较便可得出结果
4、复习了程序运行时间的相关知识,这次作业将运行时间作为判断条件使用

猜你喜欢

转载自blog.csdn.net/qq_42302466/article/details/89186841
今日推荐