作业题目:24点游戏
所用语言:java
所用类:Main MainTest
其他文件:null
程序流程:Main方法中开始执行程序,获得一组范围由1到13的(闭区间)4张牌组,通过穷举法把四张牌两两运算(加减乘除)得出最后结果是24的卡组视为胜出。若没有得出24的卡组视为失败,随即下一组继续运算直到发现存在24的卡组,然后输出不带重复的得出24的数学表达式。
代码如下:
import java.util.ArrayList;
import java.util.Random;
public class Main {
public static void main(String[] args) {
boolean flag = true;//判断第一个出现24点的人
System.out.println("all right,游戏开始~!!");
while (flag) {
System.out.println("发牌ing");
ArrayList<Integer> random = getCardNumber();//获得4个范围由1到13的随机卡组
System.out.println("这组牌是"+random);
flag = gameStart(random);//传入参数正式开始运算
if (flag == true) {
System.out.println("这组牌没有24点,下一组");
}
}
}
private static boolean gameStart(ArrayList<Integer> random) {
ArrayList<String> allOpeations = new ArrayList<>();//用于存储所有的运算式
boolean isExist = true;//给主函数返回计算结果,判断是否存在运算可以算的24
int first = 0, second = 0, third = 0;//first第一轮运算的运算符,second第二轮运算的运算符,third第三轮运算的运算符
//穷举法计算各种情况
for (first = 0; first < 4; first++) {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
if (i != j) {
double result1 = CaculateResults((double) random.get(i), (double) random.get(j), first);
String[] operators = new String[3];
operators[0] = getOperator(first);
for (second = 0; second < 4; second++) {
for (int k = 0; k < 4; k++) {
if (k != i && k != j) {
double result2 = CaculateResults(result1, (double) random.get(k), second);
operators[1] = getOperator(second);
for (third = 0; third < 4; third++) {
for (int m = 0; m < 4; m++) {
if (m != i && m != j && m != k) {
double result3 = CaculateResults(result2, (double) random.get(m), third);
operators[2] = getOperator(third);
if (result3 == 24) {
//最后的格式是两两运算的顺序
allOpeations.add("[" + "(" + random.get(i) + operators[0] + random.get(j) + ")" + operators[1] + random.get(k) + "]" + operators[2] + random.get(m));
isExist = false;
}
}
}
}
}
}
}
}
}
}
//把所有的公式传参后去排除相同的公式
showResults(allOpeations);
return isExist;
}
private static void showResults(ArrayList<String> allOpeations) {
System.out.println("看来我们已经有了一个赢家!而且他的组合牌是!");
ArrayList<String> list1 = new ArrayList();//list1用来存放所有的()小括号里的表达式,只要确保()小括号里的表达式一至就能有效排除相同的公式
//分割表达式
for (int i = 0; i < allOpeations.size(); i++) {
list1.add(splitString(allOpeations.get(i), "(", ")"));
}
//list2用来存放所有相同的方程式,有多少相同的就放多少,最后用于删除
ArrayList<String> list2 = new ArrayList<>();
for (int i = 0; i < list1.size(); i++) {
for (int index = 0; index < list1.get(i).length(); index++) {
//遍历表达式判断运算符,因为+和*有特殊性
if (list1.get(i).charAt(index) == '+') {
String[] temp = list1.get(i).split("[+]");
String chekStr = temp[1] + "+" + temp[0];
allOpeations.get(i).replaceAll(list1.get(i), chekStr);
for (int j = i + 1; j < allOpeations.size(); j++) {
if (allOpeations.get(i).equals(allOpeations.get(j))) {
list2.add(allOpeations.get(i));
break;
}
}
} else if (list1.get(i).charAt(index) == '*') {
String[] temp = list1.get(i).split("[*]");
String chekStr = temp[1] + "*" + temp[0];
allOpeations.get(i).replaceAll(list1.get(i), chekStr);
for (int j = i + 1; j < allOpeations.size(); j++) {
if (allOpeations.get(i).equals(allOpeations.get(j))) {
list2.add(allOpeations.get(i));
break;
}
}
} else if (list1.get(i).charAt(index) == '-') {
for (int a = i + 1; a < list1.size(); a++) {
if (allOpeations.get(a).equals(allOpeations.get(i))) {
list2.add(allOpeations.get(i));
break;
}
}
} else if (list1.get(i).charAt(index) == '/') {
for (int a = i + 1; a < list1.size(); a++) {
if (allOpeations.get(a).equals(allOpeations.get(i))) {
list2.add(allOpeations.get(i));
break;
}
}
}
}
}
//删除所有表达式中存在于list2的表达式
for (int j = 0; j < list2.size(); j++)
{
String temp = list2.get(j);
allOpeations.remove(temp);
}
//输出不一样的表达式
for (int length = 0; length < allOpeations.size(); length++)
{
System.out.println(allOpeations.get(length));
}
}
//用于分割表达式,有目标表达式,分割开始的字符(串),分割结束的字符(串)
public static String splitString(String target, String begin, String end) {
int left = target.indexOf(begin);
int right = target.indexOf(end);
String result = target.substring(left + 1, right);
return result;
}
//根据运算的参数来判断返回到公式里的运算符
private static String getOperator(int first) {
String str = null;
if (first == 0)
return str = "+";
if (first == 1)
return str = "-";
if (first == 2)
return str = "*";
if (first == 3)
return str = "/";
return str;
}
//用参数判断计算的类型
private static double CaculateResults(double x, double y, int operator) {
double result = 0;
if (operator == 0) {
result = x + y;
return result;
}
if (operator == 1) {
result = x - y;
return result;
}
if (operator == 2) {
result = x * y;
return result;
}
if (operator == 3) {
if (y != 0) {
result = x / y;
return result;
}
}
return result;
}
//获得随机牌组
public static ArrayList getCardNumber() {
Random random = new Random();
ArrayList<Integer> randomNumber = new ArrayList();
while (randomNumber.size() != 4) {
int i = random.nextInt(14);
if (i > 0) {
if (randomNumber.size() == 0) {
randomNumber.add(i);
} else {
randomNumber.add(i);
}
}
}
return randomNumber;
}
}
不要急着关!不要慌!看我给你慢慢道来!!!
我的程序计算上可能比较繁琐,但是比较好理解。
首先:
程序由Main开始
public static void main(String[] args) {
boolean flag = true;//判断第一个出现24点的人
System.out.println("all right,游戏开始~!!");
while (flag) {
System.out.println("发牌ing");
ArrayList<Integer> random = getCardNumber();//获得4个范围由1到13的随机卡组
System.out.println("这组牌是"+random);
flag = gameStart(random);//传入参数正式开始运算
if (flag == true) {
System.out.println("这组牌没有24点,下一组");
}
}
}
random是获得随机数的牌组,怎么获得的呢??通过限制随机数的范围和随机数的数量,拿到了就跟扑克牌一样A(1),2,3,4,5,6,7,8,9,10,J(11),K(12),Q(13),没有王。返回了一个存放整数的列表。
public static ArrayList getCardNumber() {
Random random = new Random();
ArrayList<Integer> randomNumber = new ArrayList();
while (randomNumber.size() != 4) {
int i = random.nextInt(14);
if (i > 0) {
if (randomNumber.size() == 0) {
randomNumber.add(i);
} else {
randomNumber.add(i);
}
}
}
return randomNumber;
}
拿到卡之后就发卡?,flag用来标记能通过两两运算后得到的结果来判断游戏什么时候结束。
boolean flag = true;//判断第一个出现24点的人
System.out.println("all right,游戏开始~!!");
while (flag) {
System.out.println("发牌ing");
ArrayList<Integer> random = getCardNumber();//获得4个范围由1到13的随机卡组
System.out.println("这组牌是"+random);
flag = gameStart(random);//传入参数正式开始运算
if (flag == true) {
System.out.println("这组牌没有24点,下一组");
}
}
来!算!?代码里注释给的很清楚,从下面的for开始就是在选择两两数字去计算,具体计算在CaculateResults里计算,注意其中的first用来标注第一次运算的运算符。second 和 third的用法一样。
private static boolean gameStart(ArrayList<Integer> random) {
ArrayList<String> allOpeations = new ArrayList<>();//用于存储所有的运算式
boolean isExist = true;//给主函数返回计算结果,判断是否存在运算可以算的24
int first = 0, second = 0, third = 0;//first第一轮运算的运算符,second第二轮运算的运算符,third第三轮运算的运算符
//穷举法计算各种情况
for (first = 0; first < 4; first++) {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
if (i != j) {
double result1 = CaculateResults((double) random.get(i), (double) random.get(j), first);
String[] operators = new String[3];
operators[0] = getOperator(first);
for (second = 0; second < 4; second++) {
for (int k = 0; k < 4; k++) {
if (k != i && k != j) {
double result2 = CaculateResults(result1, (double) random.get(k), second);
operators[1] = getOperator(second);
for (third = 0; third < 4; third++) {
for (int m = 0; m < 4; m++) {
if (m != i && m != j && m != k) {
double result3 = CaculateResults(result2, (double) random.get(m), third);
operators[2] = getOperator(third);
if (result3 == 24) {
//最后的格式是两两运算的顺序
allOpeations.add("[" + "(" + random.get(i) + operators[0] + random.get(j) + ")" + operators[1] + random.get(k) + "]" + operators[2] + random.get(m));
isExist = false;
}
}
}
}
}
}
}
}
}
}
//把所有的公式传参后去排除相同的公式
showResults(allOpeations);
return isExist;
}
而CacluateResults是这样实现的?,很简单对吧。
private static double CaculateResults(double x, double y, int operator) {
double result = 0;
if (operator == 0) {
result = x + y;
return result;
}
if (operator == 1) {
result = x - y;
return result;
}
if (operator == 2) {
result = x * y;
return result;
}
if (operator == 3) {
if (y != 0) {
result = x / y;
return result;
}
}
return result;
}
那每次运算后要把包括运算符和数字存放到allOpeations中来存放所有的运算式,那肯定要确定存放某个运算式的时候考虑怎么存放这个运算符,存放哪个运算符对吧,?这里头的first只是个参数,不要和上面的first混淆。
private static String getOperator(int first) {
String str = null;
if (first == 0)
return str = "+";
if (first == 1)
return str = "-";
if (first == 2)
return str = "*";
if (first == 3)
return str = "/";
return str;
}
算完了拿到结果了最后就是筛选结果。怎么获得不带重复样的表达式呢??
private static void showResults(ArrayList<String> allOpeations) {
System.out.println("看来我们已经有了一个赢家!而且他的组合牌是!");
ArrayList<String> list1 = new ArrayList();//list1用来存放所有的()小括号里的表达式,只要确保()小括号里的表达式一至就能有效排除相同的公式
//分割表达式
for (int i = 0; i < allOpeations.size(); i++) {
list1.add(splitString(allOpeations.get(i), "(", ")"));
}
//list2用来存放所有相同的方程式,有多少相同的就放多少,最后用于删除
ArrayList<String> list2 = new ArrayList<>();
for (int i = 0; i < list1.size(); i++) {
for (int index = 0; index < list1.get(i).length(); index++) {
//遍历表达式判断运算符,因为+和*有特殊性
if (list1.get(i).charAt(index) == '+') {
String[] temp = list1.get(i).split("[+]");
String chekStr = temp[1] + "+" + temp[0];
allOpeations.get(i).replaceAll(list1.get(i), chekStr);
for (int j = i + 1; j < allOpeations.size(); j++) {
if (allOpeations.get(i).equals(allOpeations.get(j))) {
list2.add(allOpeations.get(i));
break;
}
}
} else if (list1.get(i).charAt(index) == '*') {
String[] temp = list1.get(i).split("[*]");
String chekStr = temp[1] + "*" + temp[0];
allOpeations.get(i).replaceAll(list1.get(i), chekStr);
for (int j = i + 1; j < allOpeations.size(); j++) {
if (allOpeations.get(i).equals(allOpeations.get(j))) {
list2.add(allOpeations.get(i));
break;
}
}
} else if (list1.get(i).charAt(index) == '-') {
for (int a = i + 1; a < list1.size(); a++) {
if (allOpeations.get(a).equals(allOpeations.get(i))) {
list2.add(allOpeations.get(i));
break;
}
}
} else if (list1.get(i).charAt(index) == '/') {
for (int a = i + 1; a < list1.size(); a++) {
if (allOpeations.get(a).equals(allOpeations.get(i))) {
list2.add(allOpeations.get(i));
break;
}
}
}
}
}
//删除所有表达式中存在于list2的表达式
for (int j = 0; j < list2.size(); j++)
{
String temp = list2.get(j);
allOpeations.remove(temp);
}
//输出不一样的表达式
for (int length = 0; length < allOpeations.size(); length++)
{
System.out.println(allOpeations.get(length));
}
}
然后输出就OK了呀?。
游戏截图:
Coder:Flyige