一、无括号版:
1.首先我们需要随机抽取四张牌,
2.然后在其中添加+ - * / .
3.然后就是对表达式求值,看结果是否等于24.
如何实现随机抽取牌,并且要保证不会抽到重复的牌?
首先,我们可以回想一下生活中的24游戏过程,(首先洗牌,幺牌,然后从顶上拿出连续的四张).
哎!那么我们不是可以先随机交换模拟洗牌,然后从顶上拿出连续四张就可以了吗!哈哈
实现细节:(牌编号从[0,51],其中[0-12] [13,25] [26,38] [39,51]分别表示四种花色的牌。)这样保证了不会抽到两张完全一样的牌。
package sunquan;
import java.util.Scanner;
public class T24PiontGame {
private int [] f=new int [4];//存储四个数字
private char[] op=new char [4];//存储3个运算符
//1.洗牌程序和随机取牌程序
public void shuffle()
{
int allCard[] = new int[52];//下标从一开始
String[] card = {"A", "2", "3", "4", "5", "6", "7", "8", "9","10", "J", "Q", "K" };
String[] suits={"黑桃","红心","梅花","方块"};
for(int i=0;i<allCard.length;i++)
allCard[i]=i;
for(int i=0;i<allCard.length;i++)//随机交换
{
int index= (int)(Math.random()*allCard.length);
int temp=allCard[i];
allCard[i]=allCard[index];
allCard[index]=temp;
}
System.out.println("正在洗牌.....");
for(int i=0;i<4;i++)//取最顶上四张
{
String suit=suits[allCard[i]/13];
String poke=card[allCard[i]%13];
f[i]=allCard[i]%13+1;
System.out.println("取到的牌为:"+suit+" "+poke);
}
}
//3.判断多项式能否构成24点
public Boolean judge24Point()
{
double []stack =new double[4];//数组模拟 栈
char[]s = new char [4];
int topsign=-1;
int topnum=-1;
stack[++topnum]=f[0];
for(int i=1;i<4;i++)
{
switch(op[i-1])
{
case '*':
stack[topnum]=stack[topnum]*f[i];
break;
case '/':
stack[topnum]=stack[topnum]/f[i];
break;
default:
stack[++topnum]=f[i];
s[++topsign]=op[i-1];
break;
}
}
for(int i=0;i<topnum;i++)
{
if(s[i]=='+')
stack[i+1]=stack[i]+stack[i+1];
else if(s[i]=='-')
stack[i+1]=stack[i]-stack[i+1];
}
return (Math.abs(stack[topnum]-24.0)<1e-5)?true:false;
}
//2.生成多项式
public Boolean solve()
{
char [] sign={'+','-','*','/'};
Boolean flag=false;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
for(int k=0;k<4;k++)
{ op[0]=sign[i];op[1]=sign[j];op[2]=sign[k];
if(judge24Point())
{
if(flag==false)System.out.println("The solution:");
System.out.println(""+f[0]+op[0]+f[1]+op[1]+f[2]+op[2]+f[3]+"==24");
flag=true;
}
}
return flag;
}
public static void main(String arg[]) {
T24PiontGame t=new T24PiontGame();
Scanner in=new Scanner(System.in);
while(true)
{
System.out.println("press 1: 洗牌\n"+"press 0: exit");
if(in.nextInt()==0)break;
t.shuffle();//洗牌,然后取顶上四张牌
if(t.solve()!=true)//判断四张牌能否构成24点
System.out.println("没有找到解,请重新洗牌!");
}
in.close();
}
}
运行结果:
添加括号就改变了运算顺序,那么我们直接从运算顺序着手:
分析可知:a b c d 总共进行了三次运算;因为每次是对相邻的两个数运算,那么总的情况种数总共才6种:
1 ((a b) c) d
2 (a b) (c d)
3 (a (b c)) d
4 a ((b c) d)
5 a (b (c d))
6 (a b) (c d)
发现第6种情况和情况2重复,那么我们只需要做5次判断即可。
此时,问题得解,是不是发现很多问题看似复杂,换个角度思考分析,发现情况并不复杂,那么聪明的你去用代码实现一下吧!
测试结果:
对比两个测试结果:发现没有括号,会漏掉很多可行解。
package sunquan;
import java.util.Scanner;
public class T24PiontGame {
private int [] f=new int [4];//{12,6,8,4};//
private char [] op=new char [4];
//1.洗牌程序和随机取牌程序
public void shuffle()
{
int allCard[] = new int[52];//下标从一开始
String[] card = {"A", "2", "3", "4", "5", "6", "7", "8", "9","10", "J", "Q", "K" };
String[] suits={"黑桃","红心","梅花","方块"};
for(int i=0;i<allCard.length;i++)
allCard[i]=i;
for(int i=0;i<allCard.length;i++)//随机交换
{
int index= (int)(Math.random()*allCard.length);
int temp=allCard[i];
allCard[i]=allCard[index];
allCard[index]=temp;
}
System.out.println("正在洗牌.....");
for(int i=0;i<4;i++)//取最顶上四张
{
String suit=suits[allCard[i]/13];
String poke=card[allCard[i]%13];
f[i]=allCard[i]%13+1;
System.out.println("取到的牌为:"+suit+" "+poke);
}
}
//calculate
public double cal(double a,double b,char c)
{
if(c=='+') return a+b;
if(c=='-') return a-b;
if(c=='*') return a*b;
if(Math.abs(b)>1e-3) return a/b;
else return 1<<30;//返回无穷大
}
//判断是否等于24
public Boolean equals(double ans)
{
return Math.abs(ans-24.0)<1e-3;
}
//3、判断并输出结果
public Boolean judge()
{
Boolean flag=false;
int i=0,j=1,k=2;
double temp=cal(f[0],f[1],op[i]);
//1 ((a b) c) d
if(equals(cal(cal(temp,f[2],op[j]),f[3],op[k])) )
{
System.out.println("(("+f[0]+op[i]+f[1]+")"+op[j]+f[2]+")"+op[k]+f[3]+"==24");flag=true;
}
//2 (a b) (c d)
if(equals(cal(temp,cal(f[2],f[3],op[k]),op[j])) )
{
System.out.println("("+f[0]+op[i]+f[1]+")"+op[j]+"("+f[2]+op[k]+f[3]+")==24");flag=true;
}
temp=cal(f[1],f[2],op[j]);
//3 (a (b c)) d
if(equals(cal(cal(f[0],temp,op[i]),f[3],op[k])))
{ // a + ( b + c )) d
System.out.println("("+f[0]+op[i]+"("+f[1]+op[j]+f[2]+"))"+op[k]+f[3]+"==24");flag=true;
}
//4 a ((b c) d)
if(equals(cal(f[0], cal(temp,f[3],op[k]) ,op[i])))
{
System.out.println(""+f[0]+op[i]+"(("+f[1]+op[j]+f[2]+")"+op[k]+f[3]+")==24");flag=true;
}
//5 a (b (c d))
temp=cal(f[2],f[3],op[k]);
if(equals(cal(f[0], cal(f[1],temp,op[j]) ,op[i])))
{
System.out.println(""+f[0]+op[i]+"("+f[1]+op[j]+"("+f[2]+op[k]+f[3]+"))==24");flag=true;
}
return flag;
}
//2.生成多项式
public Boolean solve()
{
char [] sign={'+','-','*','/'};
Boolean flag=false;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
for(int k=0;k<4;k++)
{ op[0]=sign[i];op[1]=sign[j];op[2]=sign[k];
if(judge()) flag=true;
}
return flag;
}
public static void main(String arg[]) {
T24PiontGame t=new T24PiontGame();
Scanner in=new Scanner(System.in);
while(true)
{
System.out.println("press 1: 洗牌\n"+"press 0: exit");
if(in.nextInt()==0)break;
t.shuffle();//洗牌,然后取顶上四张牌
if(t.solve()!=true)//判断四张牌能否构成24点
System.out.println("没有找到解,请重新洗牌!");
}
in.close();
}
}