扑克牌24点
最近在vc6中练习静态库创建和调用,正好前段时间写过四则混合运算代码,就拿它来练手了。vc6创建静态库很简单,只要新建工程,选择“Win32 Static Library”即可,你的代码可纯粹只有你自己写的函数,不需要包含任何头文件;调用时将你生成的库文件放到新工程的目录下,在代码头部加“ #pragma comment(lib, 库文件名)”,再声明下你要调用的函数就可以使用库函数了。
24点扑克牌游戏是经典的益智类游戏,坛子里也有好多大神写过,我甚至看到有人纯粹用“if...else...”完成的。
游戏规则是:一副牌中抽去大小王剩下52张,任意抽取4张牌,用加、减、乘、除、括号把牌面上的数算成24。每张牌必须用一次且只能用一次,用11至13代表JQK。
仔细分析,算法应该很简单,就是暴力组合法:4个数字全排列为4!=24,3个运算符相当于3位4进制数共4*4*4=64,因此在不考虑括号的情况下应该有24*64=1536种,这用程序遍历应该瞬间可以完成。
1、现在分析加括号的情况,通过分析:由于括号只在乘除的情况下优先加减时使用,((a+b)*c)+d、((a+b)*c)*d和(a+b)*c+d、(a+b)*c*d等效,所以括号嵌套不予考虑。单层括号有(a+b)+c+d、(a+b+c)+d、a+(b+c)+d、a+(b+c+d)、a+b+(c+d)、(a+b)+(c+d)共6种情况(式子中的加好代表所有运算符),再加上不含括号共7种,这样一来,考虑括号时穷举所有组合共有7*24*64=10752种,这个数量电脑穷举起来也不费力吧。
2、本次使用了我自己写的静态库,我把代码和静态库以及编译成功后的exe一并打包了,该代码在vc6下编译成功,也尝试着在codeblock下编译,还不得要领,如果无法编译,可参考我在https://bbs.bccn.net/thread-485738-1-1.html一楼代码,拷贝过来即可不以来静态库了。我在静态库里的函数有点小改动,主要针对除不尽的情况,如8/3*9+6原代码也会算成24,我把静态库里除不尽的情况直接恒定返回123456(即8/3=123456),从而避开错误的正确结果,也规避了经典bug:8/(3-8/3)。
3、同上次一样,我在代码中留了两个问号,有兴趣的可以填空。
源文件和库文件
运行效果
程序代码:#include <stdio.h>
#pragma comment(lib, "xzleval.lib")
int eval(char *);
int geteval(int *a,int k,int o)
{
char op[]="+-*/",kz[5]={0},kf[5]={0},ev[100];
int i,b[3]={0};
for(i=0;i<3;i++,o/=4)b[i]=o%4; //分解运算符组合(分解为3个4进制数组合)
if((b[0]<2&&b[1]<2&&b[2]<2)||(b[0]>1&&b[1]>1&&b[2]>1))k=0; //运算符优先级相同不需要括号
//实际上括号只和乘除配对,可以在精简算式,太啰嗦就不再考虑怎么组织逻辑了
if(k)
{//处理括号组合,0:无括号,6:两对括号,1-5:通过运算一对括号包含2个或3个操作数
if(k<6)
{//一对括号
kz[(k-1)/2]='(';
kf[(k+2)/2]=')';
}
else
{//两对括号
kz[0]=kz[2]='(';
kf[1]=kf[3]=')';
}
}
//用sprintf组合算式
sprintf(ev,"%s%d%c%s%d%s%c%s%d%s%c%d%s",kz,a[0],op[b[0]],kz+1,a[1],kf+1,op[b[1]],kz+2,a[2],kf+2,op[b[2]],a[3],kf+3);
if(eval(ev)==24)
{
printf("%s=24\n",ev);
return 1;
}
return 0;
}
void per(int *a,int *b,int n)
{//全排列
int i,j;
if(n>=4)
{
for(i=0;i<7;i++)
for(j=0;j<64;j++)
b[4]+=geteval(b,i,j); //i对应括号组合,j对应运算符组合,总组合数为7*64*24=10752
}
for(i=0;i<4;i++)
{
if(a[i])
{
b[n]=a[i];
//? 填空
per(a,b,n+1);
//? 填空
}
}
}
void main()
{
int i,a[4],b[5];
while(1)
{
printf("输入4个1至13间的数(非数字退出):\n");
for(i=0;i<4;i++)
{
if(!scanf("%d",&a[i]))break;
while(a[i]<1||a[i]>13)
{
printf("%d不合格,重新输入:",a[i]);
if(!scanf("%d",&a[i]))break;
}
}
if(i<4)break;
printf("你输入的数分别是:");
for(i=0;i<4;i++)printf("%-3d",a[i]);
printf("\n");
b[4]=0;
per(a,b,0);
if(b[4])printf("不考虑交换律结合律,共有%d个算式\n",b[4]);
else printf("无法计算24点!\n");
}
}








