一、简单介绍 给出4个数字,所给数字均为有理数,用加、减、乘、除(可加括号)把给出的数算成24.每个数必须用一次且只能用一次,先算出结果者获胜。 二、深入讨论 24点游戏能极大限度地调动多种感官的协调活动,对于培养我们快捷的心算能力和反应能力很有帮助.因此我们课后要多加练习,练习方法可以从一副扑克牌中去掉大王小王,剩余52张进行游戏,需要说明的是,经计算机准确计算,一副牌(52张)中,任意抽取4张可有1820种不同组合,其中有458个牌组算不出24点,如1、1、1、5. 三、算24一般掌握以下方法 8、化除为乘法。用一个数除于一个分数,相当于乘与一个数,最后得24。如3、3、8、8
#include "stdafx.h" #include "conio.h" #include "stdlib.h" #include "time.h" #include "math.h" #include "string.h" #include "iostream.h" /* 从一副扑克牌中,任取4张。 2-10 按其点数计算(为了表示方便10用T表示),J,Q,K,A 统一按 1 计算 要求通过加减乘除四则运算得到数字 24。 本程序可以随机抽取纸牌,并用试探法求解。 */ int s[21][4]={-1}; int sum=0; void GivePuzzle(char* buf) { char card[] = {'A','2','3','4','5','6','7','8','9','T','J','Q','K'}; for(int i=0; i<4; i++){ buf[i] = card[rand() % 13]; } }
void SetPuzzle(char *buf) { scanf("%c %c %c %c",&buf[0],&buf[1],&buf[2],&buf[3]); }
void shuffle(char * buf) { for(int i=0; i<5; i++){ int k = rand() % 4; char t = buf[k]; buf[k] = buf[0]; buf[0] = t; } }
int GetCardValue(int c) { if(c=='T') return 10; if(c>='0' && c<='9') return c - '0'; return 1; }
char GetOper(int n) { switch(n) { case 0: return '+'; case 1: return '-'; case 2: return '*'; case 3: return '/'; }
return ' '; }
double MyCalcu(double op1, double op2, int oper) { switch(oper) { case 0: return op1 + op2; case 1: return op1 - op2; case 2: return op1 * op2; case 3: if(fabs(op2)>0.0001) return op1 / op2; else return 100000; }
return 0; }
void MakeAnswer(char* answer, int type, char* question, int* oper) { char p[4][3]; for(int i=0; i<4; i++) { if( question[i] == 'T' ) strcpy(p[i], "10"); else sprintf(p[i], "%c", question[i]); }
switch(type) { case 0: sprintf(answer, "%s %c (%s %c (%s %c %s))", p[0], GetOper(oper[0]), p[1], GetOper(oper[1]), p[2], GetOper(oper[2]), p[3]); break; case 1: sprintf(answer, "%s %c ((%s %c %s) %c %s)", p[0], GetOper(oper[0]), p[1], GetOper(oper[1]), p[2], GetOper(oper[2]), p[3]); break; case 2: sprintf(answer, "(%s %c %s) %c (%s %c %s)", p[0], GetOper(oper[0]), p[1], GetOper(oper[1]), p[2], GetOper(oper[2]), p[3]); break; case 3: sprintf(answer, "((%s %c %s) %c %s) %c %s", p[0], GetOper(oper[0]), p[1], GetOper(oper[1]), p[2], GetOper(oper[2]), p[3]); break; case 4: sprintf(answer, "(%s %c (%s %c %s)) %c %s", p[0], GetOper(oper[0]), p[1], GetOper(oper[1]), p[2], GetOper(oper[2]), p[3]); break; } }
bool TestResolve(char* question, int* oper, char* answer) { // 等待考生完成 int type[5]={0,1,2,3,4};//计算类型 double p[4]; double sum=0;
for(int i=0; i<4; i++) //循环取得点数 { p[i]=GetCardValue(int(question[i])); }
for(i=0;i<5;i++) { MakeAnswer(answer,type[i],question,oper); //获取可能的答案 //printf("Doing:%s\n", answer); switch(type[i]) { case 0: sum=MyCalcu(p[0],MyCalcu( p[1],MyCalcu(p[2], p[3], oper[2]),oper[1]),oper[0]); //A*(B*(c*D)) break; case 1: sum=MyCalcu(p[0],MyCalcu(MyCalcu(p[1], p[2], oper[1]),p[3],oper[2]),oper[0]); //A*((B*C)*D) break; case 2: sum=MyCalcu(MyCalcu(p[0], p[1], oper[0]),MyCalcu(p[2], p[3], oper[2]),oper[1]); // (A*B)*(C*D) break; case 3: sum=MyCalcu(MyCalcu(MyCalcu(p[0], p[1], oper[0]),p[2],oper[1]),p[3],oper[2]); //((A*B)*C)*D break; case 4: sum=MyCalcu(MyCalcu(p[0],MyCalcu(p[1], p[2], oper[1]),oper[0]),p[3],oper[2]); //(A*(B*C))*D break; } if(sum==24) return true; } return false; }
bool permNum(int* oper, int i,int N,char*question,char*answer) //递归实现重新排列数字、运算符 { int j, k; char tmp; if(i < N) { for(j = i; j < N; j++) { tmp = question[j]; for(k = j; k > i; k--) question[k] = question[k-1]; question[i] = tmp; if( permNum(oper, i+1,N,question,answer)) return true; for(k = i; k < j; k++) question[k] = question[k+1]; question[j] = tmp; } } else { //int type; if( TestResolve(question, oper, answer) ) { //getch(); return true; } } return false; }
bool perm(int* num, int i,int N,char*question,char*answer) //递归实现重新排列数字、运算符 { int j, k, tmp; if(i < N) { for(j = i; j < N; j++) { tmp = num[j]; for(k = j; k > i; k--) num[k] = num[k-1]; num[i] = tmp; if(perm(num, i+1,N,question,answer)) return true; for(k = i; k < j; k++) num[k] = num[k+1]; num[j] = tmp; } } else { if (permNum(num,0,4,question,answer)) return true; } return false; }
int ifcan(int str[4]) { for(int i=0;i<sum;i++) { if(s[i][0]==str[0]&&s[i][1]==str[1]&&s[i][2]==str[2]) {
return 1; } } s[i-1][0]=str[0]; s[i-1][1]=str[1]; s[i-1][2]=str[2]; sum++; return 0; }
bool Chooseoper(int *oper,char*question,char*answer) //递归从四个运算符获取三个运算符 {
int n=3,m=12,i,j; int oper1[12];
for (i=0;i<n;i++) { oper1[i]=i; }
for (i=0;i<n;i++) { oper[i]=oper1[i]/3; }
if (!ifcan(oper)) { if(perm(oper,0,n,question,answer)) return true; }
j=n-1; while (1) { if (oper1[n-1]==m-1) j--; else j=n-1; oper1[j]++; for (i=j+1;i<n;i++) oper1[i]=oper1[i-1]+1;
for (i=0;i<n;i++) { oper[i]=oper1[i]/3; } if (!ifcan(oper)) { if(perm(oper,0,n,question,answer)) return true; }
if (oper1[0]>=m-n) break; } return false; } bool Try(int *oper,char*question,char* answer) { if(Chooseoper(oper,question,answer)) return true; return false; }
int main(int argc, char* argv[]) { // 初始化随机种子 srand( (unsigned)time( NULL ) ); char buf1[4]; // 题目 char buf2[30]; // 解答
printf("***************************\n"); printf("计算24\n"); printf("A J Q K 均按1计算,其它按牌点计算,T 代表 10\n"); printf("目标是:通过四则运算组合出结果:24\n"); printf("Mode 1 of Give Puzzle: Rand to give puzzle\n"); printf("Else Type of Give Puzzle:Give by Youself \n"); printf("***************************\n\n"); int mode=1; //默认为1 printf("Mode:"); scanf("%d",&mode); getchar(); printf("***************************\n"); for(;;) {
if (mode==1) { GivePuzzle(buf1); // 出题模式1 } else { printf("Num:"); SetPuzzle(buf1); //出题模式2 } getchar(); printf("题目:"); for(int j=0; j<4; j++){ if( buf1[j] == 'T' ) printf("10 "); else printf("%c ", buf1[j]); }
printf("\n按任意键参考答案...\n"); getch();
int type[4]; if( Try(type, buf1,buf2) ) //1全局搜索解法,精确解 printf("参考:%s\n", buf2); else printf("无解...\n");
for (int i=0;i<sum;i++) { for(int j=0;j<3;j++) s[i][j]=-1; } sum=0;
printf("按任意键出下一题目,x 键退出...\n"); if( getch() == 'x' ) break;
}
return 0; }
Thanks! |
|