24点游戏

#include <iostream>
#include <string.h>
#include <string>
#include <iomanip>
#include <time.h>
#include <math.h>
#include <stack>
#include <windows.h>
using namespace std;


#define ILLEGAL -1000.00 //表达式不合法的计算结果


double arrNum[4] = {0};  //随机生成的四张牌
int arrFlag[4] = {0};    //标记数字的使用与否
string str[4];           //搜索所有解时用于保存相应的字符串
string sAllAnsw[1000];    //所有可能的答案
int nAllAnsw = 0;        //所有可能的答案的种类


/*      **        算法实现     **      */


bool IsLegal(int num);                           //判断四个数中是否包含num,并且判断num是否重复使用
int Priority(char operators);                    //制定运算符优先级
int Isoperator(char ch);                         //判断是否为运算符
void Mid_To_Back(string mid,char back[],int& n); //将中缀表达式转换成后缀表达式
double GetNum(char back[],int& i);               //获取后缀表达式从i个位置起的数字
double CalculateBack(char back[],int n);         //计算后缀表达式
double CalcExpression(string mid);               //计算一个中缀表达式的值
void searchAllAnsw(int n);                       //找到所有解




/*       **      菜单维持      **      */


void mainMenu();                                 //主菜单 
void startGame();                                //开始游戏
void help();                                     //帮助菜单
void answer();                                   //回答问题
void IsNoans();                                  //确认无解
void lookAnsw();                                 //查看所有答案
void clearData();                                //清除一些对下一步有影响的数据




int main()
{
bool IsExit = false;          //是否退出


while(!IsExit)
{
int item;
mainMenu();
cout<<"请选择:";
cin>>item;


switch(item)
{
case 1: startGame();  break;
case 2: help();       break;
case 3: IsExit = true;break;
}
}


return 0;
}


//判断四个数中是否包含num,并且判断num是否重复使用
bool IsLegal(int num)
{
int i = 0;
for(i = 0; i < 4; i++)
{
if(arrNum[i] == num && 0 == arrFlag[i])
{
arrFlag[i] = 1;
return true;
}
}
return false;
}


//制定运算符优先级 
int Priority(char operators)
{
switch(operators)
{
case '*':
case '/':
return 2;
case '+':
case '-':
return 1;
case '(':
return 0;
case '#':
return -1;
default:
return -1;
}
}


//判断是否为运算符
int Isoperator(char ch)
{
switch(ch)
{
case '*':
case '/':
case '+':
case '-':
return 1;
default:
return 0;
}
}


//将中缀表达式转换成后缀表达式 
void Mid_To_Back(string mid,char back[],int& n)
{                                //mid为中缀表达式,back为后缀表达式,n记录back的长度 
int i = 0;       
n = 0;
stack <char> opstack;        //存放运算符 
int length = mid.size();
opstack.push('#');           //进入栈底作为"哨兵" 
for(i = 0; i < length; i++)  //对mid进行遍历 
{
if((mid[i] >= '0' && mid[i] <= '9') || mid[i] == '.')   
{
back[n++] = mid[i];  //为数字,直接进入back
}
else if( Isoperator(mid[i]) )
{                        //为运算符 
back[n++] = ' ';     //加入空格以区分数字 
while(Priority(mid[i]) <= Priority(opstack.top()))
{                    //优先级不大于栈内运算符 
back[n++] = opstack.top();
opstack.pop(); //取栈顶运算符到back,并出栈 
}
opstack.push(mid[i]);//运算符入栈 
}
else if('(' == mid[i])
{
opstack.push(mid[i]);//为左括号,直接入栈 
}
else if(')' == mid[i])
{
while('(' != opstack.top())
{ //为右括号
back[n++] = opstack.top();
opstack.pop();   //将栈内左括号以上的运算符移动到back 
}
opstack.pop();       //将左括号出栈
}
else
{
//...... 
}
}
while('#' != opstack.top())
{
back[n++] = opstack.top();
opstack.pop();           //将栈内运算符移动到back 
}
}


//获取后缀表达式从i个位置起的数字
double GetNum(char back[],int& i)
{ //i为数字后的位置 
double x1 = 0.0;            //存放整数 
double x2 = 0.0;            //存放小数 
int flag = 1; //判断是否移动到小数点 
double k = 10.0;
while((back[i] >= '0' && back[i] <= '9') || back[i] == '.')
{ //一直计算到非数字和小数点(空格和运算符) 
if(back[i] == '.')
{
flag = 0;  
i++;  
continue; //为小数点,该步不计算 
}
if(flag) //小数点之前 
{
x1 = x1*10 + (back[i] - '0');
}
else //小数点之后 
{
x2 += (back[i] - '0') / k;
k = k * 10;
}
i++;
}
return (x1+x2);
}


//计算后缀表达式
//后缀表达式里只有数字、运算符、空格 
double CalculateBack(char back[],int n)
{ //n为back的长度 
stack <double> restack; //结果栈 
double x1 = 0.0; //每次运算前一个数字 
double x2 = 0.0; //每次运算后一个数字 
int i = 0;
for(i = 0; i < n; i++)
{
if(back[i] >= '0' && back[i] <= '9')
{ //为数字,进入结过栈 
restack.push(GetNum(back,i));

if(!IsLegal(restack.top()))
{                   //判断这个数字是否合法
return ILLEGAL;
}
i--; //由于下一步i++,这里减1 
}
else if(' ' == back[i])
{ //空格 
continue;
}
else
{ //运算符 
x2 = restack.top();   //在结果栈里取出两个作运算 
restack.pop();
x1 = restack.top();
restack.pop(); 
switch(back[i])
{    
case '+':      //再将计算结果入结果栈 
{
restack.push(x1+x2);
break;
}
case '-':
{
restack.push(x1-x2);
break;
}
case '*':
{
restack.push(x1*x2);
break;
}
case '/':
{
restack.push(x1/x2);
break;
}
default:break;
}
}
} //现在栈内只有一个数字
return restack.top(); //就是后缀表达式的值 
}


//计算一个中缀表达式的值
double CalcExpression(string mid)
{
int n = 0;
double result = 0;             //结果
char back[100];
Mid_To_Back(mid,back,n);       //将中缀表达式转化成后缀表达式 
result = CalculateBack(back,n);//计算后缀表达式的值


for(int i = 0; i < 4; i++)
{
if(0 == arrFlag[i])
{                          //四个数没有用完
return ILLEGAL;        //表达式不合法
}
}


return result;
}


//找到所有解
void searchAllAnsw(int n)
{
int i,j;
double num_a, num_b;
string str_a,str_b;


if(1 == n)
{
//if(fabs(arrNum[0] - 24) < 1E-6)
if(arrNum[0] - 24 == 0)
{
sAllAnsw[nAllAnsw++] = str[0];
}
}
else
{
for(i = 0; i < n; i++)
{
for(j = i+1; j < n; j++)
{
num_a = arrNum[i];
num_b = arrNum[j];
arrNum[j] = arrNum[n-1];

str_a = str[i];
str_b = str[j];
str[j] = str[n-1];

//加
arrNum[i] = num_a + num_b;
str[i] = '(' + str_a + "+" + str_b + ')';
searchAllAnsw(n-1);
//减
arrNum[i] = num_a - num_b;
str[i] = '(' + str_a + "-" + str_b + ')';
searchAllAnsw(n-1);
//反减
arrNum[i] = num_b - num_a;
str[i] = '(' + str_b + "-" + str_a + ')';
searchAllAnsw(n-1);
//乘
arrNum[i] = num_a * num_b;
str[i] = '(' + str_a + "*" + str_b + ')';
searchAllAnsw(n-1);
//除
if(num_b != 0)
{
arrNum[i] = num_a / num_b;
str[i] = '(' + str_a + '/' + str_b + ')';
searchAllAnsw(n-1);
}
//反除
if(num_a != 0)
{
arrNum[i] = num_b / num_a;
str[i] = '(' + str_b + '/' + str_a + ')';
searchAllAnsw(n-1);
}

arrNum[i] = num_a;  //回溯
arrNum[j] = num_b;

str[i] = str_a;
str[j] = str_b;
}
}
}
}


//加载游戏主菜单
void mainMenu()
{
system("cls");
cout<<"           >>>>>>      欢迎来到24点游戏     <<<<<<<"<<endl<<endl;
cout<<"                         1、开始游戏               "<<endl<<endl;
cout<<"                         2、查看帮助               "<<endl<<endl;
cout<<"                         3、退出游戏               "<<endl<<endl;
}


//加载游戏菜单
void gameMenu()
{
string sPoker[] = {"0","A","2","3","4","5","6","7","8","9","10","J","Q","K"};   //13张牌


system("cls");
cout<<"           >>>>>>          游戏菜单        <<<<<<<<"<<endl<<endl<<endl;
cout<<"                     "<<sPoker[(int)arrNum[0]]<<"      "<<sPoker[(int)arrNum[1]]
<<"      "<<sPoker[(int)arrNum[2]]<<"      "<<sPoker[(int)arrNum[3]]<<endl<<endl;
cout<<"                         1、开始答题               "<<endl<<endl;
cout<<"                         2、确认无解               "<<endl<<endl;
cout<<"                         3、查看答案               "<<endl<<endl;
cout<<"                         4、返回主菜单             "<<endl<<endl;
}


//为开始游戏做一些准备
void startGame()
{
bool IsExit = false;          //是否退出游戏菜单
srand(time(NULL));
for(int i = 0; i < 4; i++)
{                             //随机获取4张牌
arrNum[i] = rand() % 13 + 1;


char ch[10];
itoa(arrNum[i],ch,10);    //将数字转换为字符串
str[i] = ch;
}


while(!IsExit)
{
gameMenu();
fflush(stdin);
int item;
cout<<"请选择:";
cin>>item;

switch(item)
{
case 1: answer();      break;
case 2: IsNoans();     break;
case 3: lookAnsw();    break;
case 4: IsExit = true; break;
}


clearData();
}
}


//帮助菜单
void help()
{
cout<<"说明: 24点纸牌游戏一个益智类的数字游戏"<<endl;
cout<<"规则: 系统随机出四张牌                "<<endl;
cout<<"       你需要用加减乘除和括号使之等于24"<<endl;


fflush(stdin);


cout<<"按任意键返回主菜单"<<endl;
getchar();
}


void answer()
{
string sMid;              //中缀表达式
cin>>sMid;                //输入表达式
double result;            //结果


result = CalcExpression(sMid);

if(ILLEGAL == result)     //检验结果
{
cout<<"你输入的运算表达式不合法"<<endl;
}
else if(0 == result - 24)
{
cout<<"恭喜,回答正确 !"<<endl;
}
else
{
cout<<"大遗憾了! 回答错误"<<endl;
}
fflush(stdin);


cout<<"按任意键返回主菜单"<<endl;
getchar();
}


//确认无解
void IsNoans()
{
if(0 == nAllAnsw)
{
searchAllAnsw(4);
}
if(0 == nAllAnsw)
{
cout<<"回答正确!"<<endl;
}
else
{
cout<<"还有答案哦!"<<endl;
}


cout<<"按任意键返回"<<endl;
fflush(stdin);
getchar();
}


//查看所有答案
void lookAnsw()
{
if(0 == nAllAnsw)
{
searchAllAnsw(4);
}


for(int i = 0; i < nAllAnsw; i++)
{
cout<<left<<setw(2)<<i+1<<":  "<<sAllAnsw[i]<<endl;
}


if(0 == nAllAnsw)
{
cout<<"无解!"<<endl;
}
cout<<"按任意键返回"<<endl;
fflush(stdin);
getchar();




}


//清除一些对下一步有影响的数据
void clearData()
{
for(int i = 0; i < nAllAnsw; i++)
{
sAllAnsw[i] = "";
}
nAllAnsw = 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值