【C++】24点游戏

 

       提前bb:采用的ide是vc++ 6.0 ,并且是通过24点游戏.cpp包含Judge.h、compute.h、menu.h3个文件


一、题目分析

       24点游戏是经典的纸牌益智游戏。

       游戏规则:

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

       要求(全部实现)

       1.随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式。

       2.程序风格良好(使用自定义注释模板)。

       3.列出表达式无重复。

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

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

       6.所有成绩均可记录在TopList.txt文件中。

二、算法分析

       难难点在于表达式的计算,其实就是后缀表达式的计算~具体过程可见代码或者其他教程。

       计时可以用time_t类型的变量,设定一个time_begin,然后用当前已运行的时间减去起始时间,超过规定的时间则执行其他操作(此处我设定的是3s,觉得时间短了的可以改)。

三、流程图

四、代码实现

【24点游戏.cpp】

//版本:1.1
//主要功能:系统随机生成四个数字,游戏玩家输入由四个数字组成的四则运算表达式,使计算结果得24
//系统会检查玩家输入的四则运算表达式是否正确。并给出提示。同时系统会给出所有的表达式使得这四个
//数字的运算结果为24
#include<iostream>
#include"menu.h"
#include"compute.h"
#include"Judge.h"
#include<math.h>
using namespace std;
int main()
{
	int option;
	int flag;
	char a;
	Menu();
	do
	{
		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: Compute();JudgeAnswer();lefts();break;
		case 2: GameRule();  break;
		case 3: exit(0);     break;
		default:             break;
		}
		cout<<"是否要继续(y or n):";
		cin>>a;
		if(a=='y')
		{
			flag=1;
			system("cls");
			Menu();
			cout<<"请输入你的选项:";
		    cin>>option;
		}
		else
			exit(0);
	}
}

【Judge.h】

//Judge.h
//中缀表达式的计算
#include <string.h> 
#include <iostream> 
#include <stdlib.h> 
#include <conio.h>
#include <fstream>
#define SIZE 40
#define MaxSize 32 
using namespace std;
int life=3;    //生命值
int point=0;    //得分

//定义结点,存放字符
struct node                       
{
	char *base;
	char *top;        //头指针
	int size;
}m;

//数值结点定义
struct list                   
{
	float *base;
	float *top;
	int size;
}n;


//将数值放入栈中的算法
void ValuePush(list& S,float e)   
{
	*S.top++=e;
}



//将运算符放入栈中
void CharPush(node& S,char e)     
{
	*S.top++=e;
}


//数值出栈
float ValuePop(list& S)            
{
	if(S.base==S.top) cout<<"整数栈为空,不能输出";
	float x= *(--S.top); 
	return x;
}

//字符出栈
char CharPop(node& S)
{
	if(S.base==S.top) cout<<"字符栈为空,不能输出";
	char x= *(--S.top);
	return x;
}

 //初始化字符栈
void InitCharStack(node& S)                    
{
	S.base=(char *)malloc(SIZE *sizeof(char));    //建立一个节
	if(!S.base)
	{
		cout<<"errer abc"<<endl;
        exit(1);
	}
	S.top=S.base;
	S.size=20;
}

//初始化数值栈
void InitValueStack(list& S)                   
{
	S.base=(float *)malloc(SIZE *sizeof(float));     //建立一个节点
	if(!S.base)
	{
		cout<<"errer efg"<<endl;
		exit(1);
	}
	S.top=S.base;
	S.size=20;
}
 

//解决比较优先级的时候如何处理运算符的值的大小,进而进入下一步的运算
int Prior(char c)                          
{
	//cout<<"要求栈内优先数的字符为"<<c<<endl;
	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 asdf"<<endl;
	}
	return r;
}

int Prior2(char c)
{
	int w;
	//cout<<"要求栈内优先数的字符为"<<c<<endl;
	switch(c)
	{
	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 sfd"<<endl;
	}
	return w;
}



float Compute(char* str)
{
	int i=0;
	float x;
	CharPush(m,';');           //初始化字符栈,中只有一个元素';',整数栈为空栈
	while(str[i]&&i<SIZE-1)   //处理中缀表达式循环
	{ 
		x=0;
		if(str[i]==' ')
		{
			i++;
			continue;
		}
		while(str[i]>=48&&str[i]<=57) //1到10的ASCII码值
		{
			x=x*10+str[i]-48;     //从屏幕上获取的都是以字符的形式展现出来的,所以要ASCILL码值都要减去48 ,这样才能输入多位数
			i++;
		}
		if(x!=0) ValuePush(n,x);     //如果x的值不等于 0那么就进整数栈
		else
		{
			int a=Prior2(str[i]);   //处理栈外字符
			int b=Prior(*(m.top-1)); //处理栈内字符,成员变量是字符栈中的栈顶元素
			if(a>b)                  //栈外运算符优先级高于栈内运算符优先级
			{
				CharPush(m,str[i]);i++;} //将其插入到字符栈中
			else 
				switch(CharPop(m))       //优先级相反,括号里面的参数变量是字符栈内的首元素
			{
				case '+':x=ValuePop(n)+ValuePop(n); //从整数栈中抛出两个数值,进行以上的运算
					ValuePush(n,x); break;
				case '-':x=ValuePop(n);
					x=ValuePop(n)-x;
					ValuePush(n,x);break;
				case '*':x=ValuePop(n)*ValuePop(n);
					ValuePush(n,x);break;
				case '/':x=ValuePop(n);
					if(x!=0.0)
					{
						x=ValuePop(n)/x;
						ValuePush(n,x);
					}
					else {cout<<"零不能做除数"<<endl;i=SIZE-1;}
					break;
				case '(':i++;break;
				case ';':i=SIZE-1;break;
				default:cout<<"====输入有误===="<<endl;
			} 
		} 
	}
	x=ValuePop(n);
	return x;
}


void JudgeAnswer()
{
	ofstream f;  
	f.open("TopList.txt",ios::app);
	if(!f){
		cout<<"打开文件失败!"<<endl;
		exit(0);
	}

	char str[32]; 
	char a[SIZE];

	InitCharStack(m);      //字符栈初始化
	InitValueStack(n);     //数值栈初始化
	f<<"-------------------"<<endl;
	f<<"这是新的一轮的记录"<<endl; 
	cout<<"输入24点表达式,以;结束:"<<endl;
	cout<<"你一共有三秒的时间思考,超过时间视为失败"<<endl;
	time_t timeBegin=time(0);
	int n=0;
	float z=0;
	while(true){
		if(kbhit()){
			cin>>str; 
			z=Compute(str);
			break;
		}
		//输出倒计时
		else if(time(0)-timeBegin>=3){
			cout<<"时间到!你没有输入表达式!"<<endl;
			n=0;
			break;
		}
	}

	cout<<"你的表达式的结果为:"<<z<<endl;

	if(24==(int)z)
		{
			point++;
			f<<"当前得分为:"<<point<<endl; 
			cout<<"你的回答是正确的!"<<endl;
			cout<<"目前你的分数为:"<<point<<endl;
			cout<<"目前你的生命值为:"<<life<<endl;
		}
	else
	{
		life--;
		cout<<"你的回答是错误的!"<<endl;
		f<<"当前得分为:"<<point<<endl; 
		cout<<"目前你的分数为:"<<point<<endl;
		cout<<"目前你的生命值为:"<<life<<endl;
		if(life==0)
		{
			f<<"-------------------"<<endl;
			f.close;
			cout<<"没有生命值!游戏结束!"<<endl;
			exit(0);
		}
	}
}

【compute.h】

//compute.h 计算24点的表达式
#include<iostream>
#include<string>
#include<time.h>
#include<math.h>
const double LING = 1E-6;
const int    VALUE=24;
const int    COUNT=4;
double       number[COUNT];
string       expression[COUNT];
string       ShowAnswers[50];
int          FINDNUM=0;   
bool         Judge=false;
int          NUM=0;

using namespace std;

void Find(int n)  //n为运算数的个数,当n为1时,达到递归的终止条件,此时第一位保存的就是运算结果
{
	if(n==1)   //n为1时,给出相应的处理
	{
		if(fabs(number[0]-VALUE)<=LING) //判断数值是否是24
		{
			ShowAnswers[FINDNUM]=expression[0];
			Judge=true;            //结果标识
			NUM++;FINDNUM++;
		}
	}

	for(int i=0;i<n;i++) //递归循环开始,使用穷尽的方法
	{
		for(int j=i+1;j<n;j++)
		{
			double a,b;
			string expressiona,expressionb;//表示计算的表达式
			a=number[i];    //把两个随机数赋给a和b,随机数放在了数组中
			b=number[j];
			number[j]=number[n-1];//将后面的数转移到选中的数,此时数组中的值的数量在减少
			expressiona=expression[i];
			expressionb=expression[j];
			expression[j]=expression[n-1];

			//对取出的数分别做+ - * / 运算,并将运算结果放入的原数组中,再次进行Find()运算
			expression[i]='('+expressiona+'+'+expressionb+')';
			number[i]=a+b;
			Find(n-1);
			expression[i]='('+expressiona+'-'+expressionb+')';
			number[i]=a-b;
			Find(n-1);
			expression[i]='('+expressionb+'-'+expressiona+')';
			number[i]=b-a;
			Find(n-1);
			expression[i]='('+expressiona+'*'+expressionb+')';
			number[i]=a*b;
			Find(n-1);

			//讨论除数为0的状况
			if(b!=0)
			{
				expression[i]='('+expressiona+'/'+expressionb+')';
			    number[i]=a/b;
			    Find(n-1);
			}

			if(a!=0)
			{
				expression[i]='('+expressionb+'/'+expressiona+')';
				number[i]=b/a;
			    Find(n-1);
			}

			number[i]=a;
			number[j]=b;
			expression[i]=expressiona;
			expression[j]=expressionb;
		}
	}
}






void Compute()
{
	srand(time(0));
	for(int i=0;i<COUNT;i++)
	{
		char ch[20];
		number[i]=rand()%13+1;
		itoa(number[i],ch,10);
		expression[i]=ch;
	}
	cout<<"系统自动为你生成的游戏数字是:"<<endl;
	for(int j=0;j<COUNT;j++)
	{
		if(number[j]==1)	cout<<"A"<<"  ";
		else if(number[j]==11)	cout<<"J"<<"  ";
		else if(number[j]==12)	cout<<"Q"<<"  ";
		else if(number[j]==13)	cout<<"K"<<"  ";
		else cout<<number[j]<<"  ";
	}
	cout<<endl;
}

void lefts()
{
	char a;
	cout<<"是否想看见全部解答?(y or n):";
	cin>>a;
	Find(COUNT);
	if(a=='y')
	{
		if(Judge==true)
		{
			cout<<"\n以下是全部可能:"<<endl;
			cout<<"总共的方法有:"<<NUM<<endl;
			for(int i=0;i<NUM;i++)
			{
				cout<<ShowAnswers[i]<<endl;
			}
		}
		else
			cout<<"抱歉,该组数字无正确的解!"<<endl;
	}
	else
	{};
}

【menu.h】

//Menu.h
#include<iostream>
using namespace std;

void Menu(void)
{
	cout<<"**********欢迎使用24点游戏程序**********\n";
	cout<<"             1.开始游戏\n";
	cout<<"             2.游戏规则\n";
	cout<<"             3.退出游戏\n";
	cout<<"****************************************\n";
}

void GameRule()
{
	cout<<"游戏说明如下:"<<endl;
	cout<<"    24点游戏是一种使用扑克牌来进行的益智类游戏,"<<endl;
	cout<<"由于本程序在控制台下完成,故使用具体的数字代替扑"<<endl;
    cout<<"克牌.游戏内容是:从一副扑克牌中抽去大小王剩下52张"<<endl;
	cout<<",任意抽取4张牌,把牌面上的数(A代表1)运用加、减"<<endl;
	cout<<"、乘、除和括号进行运算得出24。每张牌都必须使用一"<<endl;
	cout<<"次,但不能重复使用。"<<endl;
}

 

五、运行结果

(调试截图略)

 

六、经验归纳

       通过编写程序发现我在编程过程中细心程度不够,会出现小错误,在以后的学习过程中应该养成好的编程习惯。还有从最初的一个简单的程序,通过自己的努力慢慢调试完善修改,得到最后成果,虽然还有不足,但是这个过程我享受到了收获的感觉,是喜悦的。还有自己的知识还欠缺太多,希望自己加油努力学习更多的知识。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值