一、题目要求
24点游戏是经典的纸牌益智游戏。
常见游戏规则:
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
基本要求: 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式。
二、算法设计
算法流程图:
基础部分的算法设计主要在四个数的计算结果设计,该程序通过两个数的以此计算进而得到四个数的计算结果,从而在进行验证四个数是否满足通过“+”,“-”,“*”,“/”四种算术运算得到24的结果。
三、算法实现
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 类Solution中包含了各种static变量和static方法,方便程序书写,该类用于解决24点游戏的基础部分
*
* 方法public static void main(String[] args)是main方法
* 方法public static int calcute(int count1, int count2, char operator)是给定两个数和一个操作符的计算方法
* 方法public static void calculate()是寻找生成24点游戏的方法
* 方法public static void calculation(int num1, int num2, int num3, int num4)是打印结果并寻相互结果的方法
*
* data:2019年4月12日
*
* @author 包海金
* @version 1.0.0
* */
public class Solution {
//定义随机产生的四个数
static int data[] = new int[4];
//转换后的num1,num2,num3,num4
static int reData[]=new int [4];
static String dataString[] = new String[4];
//用来判断是否有解
static boolean flag = false;
//存放操作符
static char[] operator = { '+', '-', '*', '/' };
private static Object key;
/**
* 程序main方法
* @param args
* */
public static void main(String[] args){
Random rand = new Random();
System.out.println("下列给出四个数字,使用+,-,*,/进行计算使最后计算结果为24");
for(int i=0;i<4;i++){
data[i]=rand.nextInt(13)+1;//随机生成四个int型数
if(data[i]==1){
System.out.println("A");//如果随机生成的数为1,则显示为扑克牌牌面中的A
}
else if(data[i]==11){
System.out.println("J");//如果随机生成的数为11,则显示为扑克牌牌面中的J
}
else if(data[i]==12){
System.out.println("Q");//如果随机生成的数为12,则显示为扑克牌牌面中的Q
}
else if(data[i]==13){
System.out.println("K");//如果随机生成的数为13,则显示为扑克牌牌面中的K
}
else
System.out.println(data[i]);
}
System.out.println("可能的结果有:");
calculate();
}
/**
* 方法public static int calcute(int count1, int count2, char operator)是给定两个数和一个操作符的计算方法
* @param count1 操作数一
* @param count2 操作数二
* @param operator 操作符
* @return 返回计算结果
* */
public static int calcute(int count1, int count2, char operator) {
if (operator == '+') {
return count1 + count2;
}
else if (operator == '-') {
return count1 - count2;
}
else if (operator == '*') {
return count1 * count2;
}
else if ((operator == '/' )&& (count2 != 0) && (count1%count2==0)) {
return count1 / count2;
}
else {
return -1;
}
}
/**
* 方法public static void calculate()是寻找生成24点游戏的方法
* */
public static void calculate(){
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
//存放数字,用来判断输入的4个数字中有几个重复的,和重复的情况
for (int i = 0; i < data.length; i++) {
if(map.get(data[i]) == null){
map.put(data[i], 1);
}
else {
map.put(data[i], map.get(data[i]) + 1);
}
}
if(map.size() == 1){
//如果只有一种数字,此时只有一种排列组合,如5,5,5,5
calculation(data[0], data[1],data[2],data[3]);
}
else if(map.size()==2){
//如果只有2种数字,有2种情况,如1,1,2,2和1,1,1,2
int index = 0;//用于数据处理
int state = 0;//判断是哪种情况
for (Integer key : map.keySet()) {
if(map.get(key) == 1){
//如果是有1个数字和其他3个都不同,将data变为 data[0]=data[1]=data[2],
//将不同的那个放到data[3],方便计算
data[3] = key;
state = 1;
}
else if(map.get(key)==2){
//如果是两两相同的情况,将data变为data[0]=data[1],data[2]=data[3]的情况
data[index++]=key;
data[index++]=key;
}
else{
data[index++]=key;
}
}
//列出2种情况的所有排列组合,并分别计算
if(state == 1){
calculation(data[3],data[1],data[1],data[1]);
calculation(data[1],data[3],data[1],data[1]);
calculation(data[1],data[1],data[3],data[1]);
calculation(data[1],data[1],data[1],data[3]);
}
if(state==0){
calculation(data[1],data[1],data[3],data[3]);
calculation(data[1],data[3],data[1],data[3]);
calculation(data[1],data[3],data[3],data[1]);
calculation(data[3],data[3],data[1],data[1]);
calculation(data[3],data[1],data[3],data[1]);
calculation(data[3],data[1],data[1],data[3]);
}
}
else if(map.size()==3){
//有3种数字的情况
int index = 0;
for (Integer key : map.keySet()) {
if(map.get(key) == 2){
//将相同的2个数字放到data[2]=data[3]
data[2] = key;
data[3] = key;
}
else {
data[index++] = key;
}
}
//排列组合,所有情况
calculation(data[0],data[1],data[3],data[3]);
calculation(data[0],data[3],data[1],data[3]);
calculation(data[0],data[3],data[3],data[1]);
calculation(data[1],data[0],data[3],data[3]);
calculation(data[1],data[3],data[0],data[3]);
calculation(data[1],data[3],data[3],data[0]);
calculation(data[3],data[3],data[0],data[1]);
calculation(data[3],data[3],data[1],data[0]);
calculation(data[3],data[1],data[3],data[0]);
calculation(data[3],data[0],data[3],data[1]);
calculation(data[3],data[0],data[1],data[3]);
calculation(data[3],data[1],data[0],data[3]);
}
else if(map.size() == 4){
//4个数都不同的情况
calculation(data[0],data[1],data[2],data[3]);
calculation(data[0],data[1],data[3],data[2]);
calculation(data[0],data[2],data[1],data[3]);
calculation(data[0],data[2],data[3],data[1]);
calculation(data[0],data[3],data[1],data[2]);
calculation(data[0],data[3],data[2],data[1]);
calculation(data[1],data[0],data[2],data[3]);
calculation(data[1],data[0],data[3],data[2]);
calculation(data[1],data[2],data[3],data[0]);
calculation(data[1],data[2],data[0],data[3]);
calculation(data[1],data[3],data[0],data[2]);
calculation(data[1],data[3],data[2],data[0]);
calculation(data[2],data[0],data[1],data[3]);
calculation(data[2],data[0],data[3],data[1]);
calculation(data[2],data[1],data[0],data[3]);
calculation(data[2],data[1],data[3],data[0]);
calculation(data[2],data[3],data[0],data[1]);
calculation(data[2],data[3],data[1],data[0]);
calculation(data[3],data[0],data[1],data[2]);
calculation(data[3],data[0],data[2],data[1]);
calculation(data[3],data[1],data[0],data[2]);
calculation(data[3],data[1],data[2],data[0]);
calculation(data[3],data[2],data[0],data[1]);
calculation(data[3],data[2],data[1],data[0]);
}
if(flag==false)
System.out.println("这四张牌面数字无法经过运算得到24!");
}
/**
* 方法public static void calculation(int num1, int num2, int num3, int num4)是打印结果并寻相互结果的方法
* @param num1 产生的数一
* @param num2 产生的数二
* @param num3 产生的数三
* @param num4 产生的数四
* */
public static void calculation(int num1, int num2, int num3, int num4){
for (int i = 0; i < 4; i++){
//第1次计算,先从四个数中任意选择两个进行计算
char operator1 = operator[i];
int firstResult = calcute(num1, num2, operator1);//先选第一,和第二个数进行计算
int midResult = calcute(num2, num3, operator1);//先选第二和第三两个数进行计算
int tailResult = calcute(num3,num4, operator1);//先选第三和第四俩个数进行计算
for (int j = 0; j < 4; j++){
//第2次计算,从上次计算的结果继续执行,这次从三个数中选择两个进行计算
char operator2 = operator[j];
int firstMidResult = calcute(firstResult, num3, operator2);
int firstTailResult = calcute(num3,num4,operator2);
int midFirstResult = calcute(num1, midResult, operator2);
int midTailResult= calcute(midResult,num4,operator2);
int tailMidResult = calcute(num2, tailResult, operator2);
for (int k = 0; k < 4; k++){
//第3次计算,也是最后1次计算,计算两个数的结果,如果是24则输出表达式
char operator3 = operator[k];
//在以上的计算中num1,num2,num3,num4都是整型数值,但若要输出为带有A,J,Q,K的表达式,则要将这四个数都变为String类型,下同
if(calcute(firstMidResult, num4, operator3) == 24){
reData[0]=num1;
reData[1]=num2;
reData[2]=num3;
reData[3]=num4;
for(int p=0;p<4;p++){
if(reData[p]==1){
dataString[p]="A";}
if(reData[p]==2){
dataString[p]="2";}
if(reData[p]==3){
dataString[p]="3";}
if(reData[p]==4){
dataString[p]="4";}
if(reData[p]==5){
dataString[p]="5";}
if(reData[p]==6){
dataString[p]="6";}
if(reData[p]==7){
dataString[p]="7";}
if(reData[p]==8){
dataString[p]="8";}
if(reData[p]==9){
dataString[p]="9";}
if(reData[p]==10){
dataString[p]="10";}
if(reData[p]==11){
dataString[p]="J";}
if(reData[p]==12){
dataString[p]="Q";}
if(reData[p]==13){
dataString[p]="k";}
}
System.out.println("((" + dataString[0] + operator1 + dataString[1] + ")"
+ operator2 + dataString[2] + ")" + operator3 + dataString[3]);
flag = true;//若有表达式输出,则将说明有解,下同
}
if(calcute(firstResult, firstTailResult, operator3) == 24){
System.out.println("(" + dataString[0] + operator1 + dataString[1] + ")"
+ operator3 + "(" + dataString[2] + operator2 + dataString[3] + ")");
flag = true;
}
if(calcute(midFirstResult, num4, operator3) == 24){
reData[0]=num1;
reData[1]=num2;
reData[2]=num3;
reData[3]=num4;
for(int p=0;p<4;p++){
if(reData[p]==1){
dataString[p]="A";}
if(reData[p]==2){
dataString[p]="2";}
if(reData[p]==3){
dataString[p]="3";}
if(reData[p]==4){
dataString[p]="4";}
if(reData[p]==5){
dataString[p]="5";}
if(reData[p]==6){
dataString[p]="6";}
if(reData[p]==7){
dataString[p]="7";}
if(reData[p]==8){
dataString[p]="8";}
if(reData[p]==9){
dataString[p]="9";}
if(reData[p]==10){
dataString[p]="10";}
if(reData[p]==11){
dataString[p]="J";}
if(reData[p]==12){
dataString[p]="Q";}
if(reData[p]==13){
dataString[p]="k";}
}
System.out.println("(" + dataString[0] + operator2 + "(" + dataString[1]
+ operator1 + dataString[2] + "))" + operator3 + dataString[3]);
flag = true;
}
if(calcute(num1,midTailResult, operator3) == 24){
reData[0]=num1;
reData[1]=num2;
reData[2]=num3;
reData[3]=num4;
for(int p=0;p<4;p++){
if(reData[p]==1){
dataString[p]="A";}
if(reData[p]==2){
dataString[p]="2";}
if(reData[p]==3){
dataString[p]="3";}
if(reData[p]==4){
dataString[p]="4";}
if(reData[p]==5){
dataString[p]="5";}
if(reData[p]==6){
dataString[p]="6";}
if(reData[p]==7){
dataString[p]="7";}
if(reData[p]==8){
dataString[p]="8";}
if(reData[p]==9){
dataString[p]="9";}
if(reData[p]==10){
dataString[p]="10";}
if(reData[p]==11){
dataString[p]="J";}
if(reData[p]==12){
dataString[p]="Q";}
if(reData[p]==13){
dataString[p]="k";}
}
System.out.println(" " + dataString[0] + operator3 + "((" + dataString[1]
+ operator1 + dataString[2] + ")" + operator2 + dataString[3] + ")");
flag = true;
}
if(calcute(num1,tailMidResult,operator3) == 24){
reData[0]=num1;
reData[1]=num2;
reData[2]=num3;
reData[3]=num4;
for(int p=0;p<4;p++){
if(reData[p]==1){
dataString[p]="A";}
if(reData[p]==2){
dataString[p]="2";}
if(reData[p]==3){
dataString[p]="3";}
if(reData[p]==4){
dataString[p]="4";}
if(reData[p]==5){
dataString[p]="5";}
if(reData[p]==6){
dataString[p]="6";}
if(reData[p]==7){
dataString[p]="7";}
if(reData[p]==8){
dataString[p]="8";}
if(reData[p]==9){
dataString[p]="9";}
if(reData[p]==10){
dataString[p]="10";}
if(reData[p]==11){
dataString[p]="J";}
if(reData[p]==12){
dataString[p]="Q";}
if(reData[p]==13){
dataString[p]="k";}
}
System.out.println(" " + dataString[0] + operator3 + "(" + dataString[1]
+ operator2 + "(" + dataString[2] + operator1 + dataString[3] + "))");
flag = true;
}
}
}
}
}
}
四、调试与测试
1、测试
2、调试
<1>调试开始
<2>第一次循环得到随即数据并且输出
<3>继续循环产生随机数,此时循环次数i = 1即循环第二次。产生第二个随机数据
<4>得到的四个随机数
<5>step into 进calculate()方法,进行分类验证
<6>step into 进calculation()方法进行计算
<7>step into进calcute()方法得到计算结果
<8>输出结果,结束调试
五、总结
由于时间问题,提高部分没有做完,基础部分的完成度页不是太好,但是基础要求基本实现了,
这道题的基础部分的逻辑不太难,主要是计算情况比较多,比较繁琐。提高部分的目前来看使
用多线程来解决时间问题更加方便,后边我会继续完成提高部分。