(C++)24点小游戏

题目描述

24点游戏是经典的纸牌益智游戏,其游戏规则如下:

   从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按要求编程解决24点游戏。

基本要求: 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式

         1.列出的表达式无重复

提高要求:用户初始生命值为一给定值(比如3),初始分数为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。

         1.使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。

分析

自己在源程序的基础上建立了类的概念,在Card里设置了几个方法,因为这次的问题自己没太怎么懂,所以核心代码是在网上找的,在这里把原博主的分析过程拿过来,以便日后理解消化......

原博主博客:https://puffsun.iteye.com/blog/587136

因为能使用的4种运算符 + - * / 都是2元运算符,所以本文中只考虑2元运算符。2元运算符接收两个参数,输出计算结果,输出的结果参与后续的计算。

由上所述,构造所有可能的表达式的算法如下:

(1) 将4个整数放入数组中

(2) 在数组中取两个数字的排列,共有 P(4,2) 种排列。对每一个排列,

(2.1) 对 + - * / 每一个运算符,
(2.1.1) 根据此排列的两个数字和运算符,计算结果
(2.1.2) 改表数组:将此排列的两个数字从数组中去除掉,将 2.1.1 计算的结果放入数组中
(2.1.3) 对新的数组,重复步骤 2
(2.1.4) 恢复数组:将此排列的两个数字加入数组中,将 2.1.1 计算的结果从数组中去除掉

可见这是一个递归过程。步骤 2 就是递归函数。当数组中只剩下一个数字的时候,这就是表达式的最终结果,此时递归结束。

在程序中,一定要注意递归的现场保护和恢复,也就是递归调用之前与之后,现场状态应该保持一致。在上述算法中,递归现场就是指数组,2.1.2 改变数组以进行下一层递归调用,2.1.3 则恢复数组,以确保当前递归调用获得下一个正确的排列。

括号 () 的作用只是改变运算符的优先级,也就是运算符的计算顺序。所以在以上算法中,无需考虑括号。括号只是在输出时需加以考虑。

附:程序源代码

/****************************************************************************
*文件名: 24PointGame.cpp
*内容简述:从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中J代表11,Q代表12,K代表13,A代表1),编程解决24点游戏。基本要求: 随机生成4个代表扑克牌牌面的数字字母,
程序自动列出所有可能算出24的表达式,要求列出的表达式无重复
*2019-04-12董怡馨创建该文件,增加文件头注释
*/
#include<stdlib.h> 
#include<string.h>
#include<iostream>
#include <math.h>//用到了求绝对值函数 
#include<time.h>//利用时间戳保证每次运行产生的随机数都不同 
using namespace std;

#define NUM  4
#define ZERO 1E-6

class Card{
	private:
		int i;
		int j;
		bool m_judge = false; 	//判断是否有解
		int number[NUM];	//存放用户输入的4个随机数	
		char expression[NUM][20] ;	//表达式	
		int cnt;//计数器,统计满足24点规则的表达式总数 	
	public:
		Card()
		{
			cnt=0;	
		} 
		void InitNumber()//初始化要输入的四个数 
		{
			srand((unsigned int)time(NULL));//随机数种子 
			printf("随机产生的四个数:   ");
			for( i =0;i<NUM;i++)
			{
				char ch[20], s;
				int a ;
				cout<<"第"<<i+1<<"个数:";
				number[i]=(rand()%10+1);//在1到10之间产生随机数 
				cout<<number[i]<<"\t";
				a = number[i];
				s = char(a + 48);
				ch[0] = s ; 
				for (j = 1; j < 20; j++) 
				{
					ch[j] = 0 ;
				}
				strcpy(expression[i], ch) ;
			}
			printf("\n") ;
		}
		
		void FindExpression(int num)
		{
			int i = 0, j = 0;
			if (num == 1)//递归结束,输出 
			{
				if ( fabs(number[0] - 24) <= ZERO)
				{
					for (i = 0; i < 20; i++)  
					{
						printf("%c", expression[0][i]) ;
					}
					printf("\n") ;
					m_judge = true;
					cnt ++;
				}
			}
			//递归查找 
			for(i = 0; i < num; i++)
			{
				for (j = i + 1; j < num; j++)//与其后面的查找进行计算
				{
					double a, b;	
					char expressiona[20], expressionb[20];
						
					a = number[i];
					b = number[j];
					
					//数组前移删除number[j]元素,用number[num-1]补上 
					number[j] = number[num - 1];
					strcpy(expressiona, expression[i]) ;
					strcpy(expressionb, expression[j]) ;
					//数组前移删除expression[j]元素,用expression[num-1]补上 
					strcpy(expression[j], expression[num - 1]) ;			
					sprintf(expression[i], "(%s+%s)", expressiona, expressionb) ;
					
					// 
					number[i] = a + b;
					FindExpression(num-1);
				
					//减法 
					sprintf(expression[i], "(%s-%s)", expressiona, expressionb) ;
					number[i] = a - b;
					FindExpression(num-1);
					
					//乘法 
					sprintf(expression[i], "(%s*%s)", expressiona, expressionb) ;
					number[i] = a * b;
					FindExpression(num-1);
					
					//除法 
					if (b != 0)
					{
						sprintf(expression[i], "(%s/%s)", expressiona, expressionb) ;
						number[i] = a / b;
						FindExpression(num-1);
					}
					
					//恢复数组 
					number[i] = a;							// 最后一层的Find(2)调用完成后将a重新赋值给number[i]即number[0]
					number[j] = b;							// 最后一层的Find(2)调用完成后将b重新赋值给nubmer[j]即number[1]
					strcpy(expression[i], expressiona) ;
					strcpy(expression[j], expressionb) ;
					
				}
			}	
		}
};

int main(void)
{
	//创建一个纸牌类对象 
	Card card;
	//初始化四个随机数,代表四张卡片 
	card.InitNumber();
	//查找表达式 
	card.FindExpression(NUM);	
}

运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值