计算24(随机法)

程序描述:

许多人小的时候可能都玩过计算24的游戏。从一副扑克牌中任意取出4张,根据点数用加、减、乘、除计算出24。花色不计,点数:AJQK都算1,其它牌算本身的牌点。

用计算机搜索算法的解法有很多。一般是用穷举法罗列每一种情况。本程序打算用一种不同寻常的算法:随机地交换牌的位置,随机地产生运算符,看看是符合要求,大量重复这个过程,看看能否碰上运气。实验表明,当试验次数很大的时候,“运气”的概率是很高的。

请考生参看【原型】的效果,理解程序的目的。先是随机地抽取4张牌,然后用随机试探的方法求解。只要找到一个解就可以了。

需要考虑计算结果为分数的情况:( 3 + (3 / 7) ) * 7

 

/*
*作者:杜红光
*DATA:2012/3/27
*描述:利用随机产生扑克牌,随机组合选出的牌,随机产生三个运算符,随机产
* 生两个括号,来解决24点问题
*/
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<conio.h>
using namespace std;
#define CARDNUMBER 4
#define RANDTIMES 10000 //随机计算次数
char card[13]={'A','2','3','4','5','6','7','8','9',10,'J','Q','K'};
char operators[4]={'+','-','*','/'};
void cardRand(int *a)
{
for(int i=0;i<CARDNUMBER;i++)
a[i]=rand()%13;
}

void printCard(int *a)
{
printf("题目:");
int i;
for(i=0;i<CARDNUMBER-1;i++)
{
if(a[i]==9 )
printf("10 ");
else
printf("%c ",card[a[i]]);
}
if(a[i]==9 )
printf("10\n");
else
printf("%c\n",card[a[i]]);
}

void changeA(int *a,double *theA)
{
for(int i=0;i<CARDNUMBER;++i)
(a[i]>0 && a[i]<10)?theA[i]=a[i]+1.0:theA[i]=1.0;
}

void randNumList(int *theRandA)
{
bool flag[CARDNUMBER];
memset(flag,0,sizeof(flag));
for(int i=0;i<CARDNUMBER;++i)
{
while(1)
{
int n=rand()%4;
if(!flag[n])
{
flag[n]=true;
theRandA[i]=n;
break;
}
}
}
//for(int i=0;i<4;i++) cout<<theRandA[i]<<endl;
//cout<<endl;
}

void randOperator(int *theRandOperator)
{
for(int i=0;i<CARDNUMBER-1;++i)
{
int n=rand()%4;
theRandOperator[i]=n;
//cout<<operators[n]<<" ";
}
//cout<<" RandOpe"<<endl;
}

double computeIt(double t1,double t2,char ch)
{
switch(ch)
{
case '+':return t1+t2;
case '-': return t1-t2;
case '*': return t1*t2;
case '/':
if(t2==0) return 10000;
else return t1/t2;
}
return 10000;
}

template<class T>
void removeZero(T *t,int len)
{
int i;
for(i=0;i<len;i++)
if(t[i]==0) break;
for(int j=i;j<len-1;j++)
t[j]=t[j+1];
}

double dealM(double *digit,char *operatorRand,int m,int n)
{
digit[m]=computeIt(digit[m],digit[m+1],operatorRand[m]);
digit[m+1]=0; operatorRand[m]=0;
//计算后把计算过的数据踢除
removeZero(digit,4-n);removeZero(operatorRand,3-n);
return digit[m];
}

double computeAnswer(double *theA,int *theRandA,int *theRandOperator,int m1,int m2)
{
double digit[CARDNUMBER];
char operatorRand[3];
int mComputePos[3]={m1,m2,0};
for(int i=0;i<CARDNUMBER;++i) digit[i]=theA[theRandA[i]];
for(int j=0;j<3;++j) operatorRand[j]=operators[theRandOperator[j]];
double sum=0;
for(int i=0;i<3;i++)
{
//计算括号里的数,最后剩余的两个数看成一个新括号里的数据进行运算
sum=dealM(digit,operatorRand,mComputePos[i],i);
//如果发现除0的情况直接返回10001,最大的计算数据是10000(即4个10相乘)
if(sum==10000) return 10001;
}
return sum;
}

void printExpression(int *a,int *theRandA,int *theRandOperator,int m1,int m2)
{
char str[20];
//memset(str,'\0',sizeof(str));
switch(m1)
{
case 0:
switch(m2)
{
case 0:
sprintf(str,"((%c%c%c)%c%c)%c%c",card[a[theRandA[0]]],operators[theRandOperator[0]],card[a[theRandA

[1]]],operators[theRandOperator[1]],card[a[theRandA[2]]],operators[theRandOperator[2]],card[a[theRandA[3]]]);
break;
case 1:
sprintf(str,"(%c%c%c)%c(%c%c%c)",card[a[theRandA[0]]],operators[theRandOperator[0]],card[a[theRandA

[1]]],operators[theRandOperator[1]],card[a[theRandA[2]]],operators[theRandOperator[2]],card[a[theRandA[3]]]);
break;
}
break;
case 1:
switch(m2)
{
case 0:
sprintf(str,"(%c%c(%c%c%c))%c%c",card[a[theRandA[0]]],operators[theRandOperator[0]],card[a[theRandA

[1]]],operators[theRandOperator[1]],card[a[theRandA[2]]],operators[theRandOperator[2]],card[a[theRandA[3]]]);
break;
case 1:
sprintf(str,"%c%c((%c%c%c)%c%c)",card[a[theRandA[0]]],operators[theRandOperator[0]],card[a[theRandA

[1]]],operators[theRandOperator[1]],card[a[theRandA[2]]],operators[theRandOperator[2]],card[a[theRandA[3]]]);
break;
}
break;
case 2:
switch(m2)
{
case 0:
sprintf(str,"(%c%c%c)%c(%c%c%c)",card[a[theRandA[0]]],operators[theRandOperator[0]],card[a[theRandA

[1]]],operators[theRandOperator[1]],card[a[theRandA[2]]],operators[theRandOperator[2]],card[a[theRandA[3]]]);
break;
case 1:
sprintf(str,"%c%c(%c%c(%c%c%c))",card[a[theRandA[0]]],operators[theRandOperator[0]],card[a[theRandA

[1]]],operators[theRandOperator[1]],card[a[theRandA[2]]],operators[theRandOperator[2]],card[a[theRandA[3]]]);
break;
}
break;
}
for(unsigned i=0;i<strlen(str);i++)
str[i]==10?printf("10"):printf("%c",str[i]);
printf("\n");
}

void findAnswer(int *a)
{
int randTimes=RANDTIMES;
double theA[CARDNUMBER];
int theRandA[CARDNUMBER];
int theRandOperator[3];
char ch;
//改变a中表示的数字和字母
changeA(a,theA);
//for(int i=0;i<4;++i) cout<<"$"<<theA[i]<<endl;
ch=getch();//scanf("%c",&ch);
while(randTimes--)
{
//产生数字的随机顺序
randNumList(theRandA);
//随机产生3个运算符
randOperator(theRandOperator);
//随机产生两个括号,第一个有3个位置,第二个有2个位置
int m1=rand()%3;
int m2=rand()%2;
//按照产生的结果运算,返回计算结果
//如果结果是24,则输出,并返回
double temp=computeAnswer(theA,theRandA,theRandOperator,m1,m2);
if(fabs(temp-24) < 0.00001)
{
//cout<<temp<<endl;
printExpression(a,theRandA,theRandOperator,m1,m2);
break;
}
}
if(randTimes==-1)
printf("可能是无解...\n");
}

void printTitle()
{
printf("****************************\n");
printf("计算24\n");
printf("A J Q K 均按1计算,其他按牌点计算\n");
printf("目标是:通过四则运算组合出结果:24\n");
printf("****************************\n\n");
}
int main()
{
int a[CARDNUMBER];
char ch;
srand(time(NULL));
//输出介绍信息
printTitle();
do{
//随机产生牌点
cardRand(a);
//输出选牌
printCard(a);
printf("按任意键参考答案...\n");
//寻找答案
findAnswer(a);
printf("按任意键下一题目,x键退出...\n");
ch=getch();//scanf("%c",&ch);使输入无回显
}while(ch!='x');
return 0;
}


原文地址:https://www.cnblogs.com/redlight/p/2419131.html