24点游戏(Java)
题目描述:24点游戏是经典的纸牌益智游戏。
常见游戏规则:
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
基本要求: 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式。
算法设计思路:
用穷举法列出四个数加上三个运算符号所构成的表达式所有可能的结果。
所谓穷举法就是列出4个数字加减乘除的各种可能性。我们可以将表达式分成以下几种:首先我们将4个数设为a,b,c,d,,将其排序列出四个数的所有排序序列组合(共有A44=24种组合)。再进行符号的排列表达式,其中算术符号有+,—,,/,(,)。其中有效的表达式有a(b-c/b),a*b-c*d,等等;其中加入文件的保存。
程序要求随机产生四个数字(范围为1到13),列出所有有效的表达式,并且无重复出现;用户在程序产生随机数后,写出能够构成24点的表达式,程序判断是否正确,正确则可以选择继续游戏,不正确提示是否显示答案。
程序流程图:
源代码如下:
Game24类:
package com._520it.chapter03;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
/**
* 24点游戏
* @author Jack
* @date 2018-10-01
* @version 1.0
*/
public class Game24 {
private static final double DIFF = 1E-6F; // 接近24的精度
private static final int CardsNumber = 4; // 卡片数
private static final int CardMax = 13; // 卡片上数字最大值
private static final int ResultValue = 24;
public static void main(String[] args) throws Exception {
int k = 0;
// 测试1次
while (k < 1) {
int[] source = new int[CardsNumber];
double[] number = new double[CardsNumber];
String[] result = new String[CardsNumber]; // 记录number[i]是通过什么运算表达式得到的
Random random = new Random();
for (int index = 0; index < CardsNumber; index++) {
// 随机生成4个数字
int x = random.nextInt(CardMax) + 1;
source[index] = x;
number[index] = x;
result[index] = "" + x;
}
// 打印参与运算的数字
System.out.println(Arrays.toString(source));
boolean isSuccess = Game24.compute(number, result, CardsNumber);
if (isSuccess) {
System.out.println(result[0]);
}
System.out.println("===================================");
k++;
}
//playing();
}
/**
* 用户自定义输入
*/
public static void playing() {
Random r = new Random();
int[] numbers = new int[4];
for (int index = 0; index < 4; index++) {
numbers[index] = r.nextInt(CardMax) + 1;
}
System.out.println("请输入用户名:");
Scanner sc = new Scanner(System.in);
User user = new User();
user.setUsername(sc.next());
while (user.getLife() > 0) {
System.out.println("产生的随机数如下:" + Arrays.toString(numbers));
System.out.println("请输入包含上述数字的表达式来使运算结果为24(可包含括号):");
String str = sc.next();
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
Integer result = null;
try {
// 判断表达式的值是否为24
result = (Integer) engine.eval(str);
if (result == 24) {
user.setScore(user.getScore() + 10);
System.out.println("回答正确!加10分,当前得分为:" + user.getScore());
} else {
user.setLife(user.getLife() - 1);
System.out.println("回答错误!生命值减1!当前剩余生命值为:" + user.getLife());
}
} catch (ScriptException e) {
e.printStackTrace();
}
}
// 将成绩写入文件
writeScoreToFile(user);
}
/**
* 穷举法求表达式值为24的解法
* @param number 卡片上的数字
* @param result 记录临时表达式
* @param n 卡片数
* @return 结果是否为24
*/
public static boolean compute(double[] number, String[] result, int n) {
if (n == 1) {
return (Math.abs(number[0] - ResultValue) < DIFF); // 接近24的程度
}
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
double a = number[i];
double b = number[j];
String expa = result[i];
String expb = result[j];
// 每计算一次,参与运算的数字就少一个。将最后一个数字复制到位置j,可达到缩小数组的目的
number[j] = number[n - 1];
result[j] = result[n - 1];
// 加法操作 a+b
number[i] = a + b;
result[i] = '(' + expa + '+' + expb + ')';
if (compute(number, result, n - 1)) {
return true;
}
// 减法操作 a-b
number[i] = a - b;
result[i] = '(' + expa + '-' + expb + ')';
if (compute(number, result, n - 1)) {
return true;
}
// 减法操作 b-a
number[i] = b - a;
result[i] = '(' + expb + '-' + expa + ')';
if (compute(number, result, n - 1)) {
return true;
}
// 乘法操作 a*b
number[i] = a * b;
result[i] = '(' + expa + '*' + expb + ')';
if (compute(number, result, n - 1)) {
return true;
}
// 除法操作 a/b, 如果除数不为0
if (b != 0) {
number[i] = a / b;
result[i] = '(' + expa + '/' + expb + ')';
if (compute(number, result, n - 1)) {
return true;
}
}
// 除法操作 b/a , 如果除数不为0
if (a != 0) {
number[i] = b / a;
result[i] = '(' + expb + '/' + expa + ')';
if (compute(number, result, n - 1)) {
return true;
}
}
number[i] = a;
number[j] = b;
result[i] = expa;
result[j] = expb;
}
}
return false;
}
/**
* 将成绩写入文件
* @param user User对象
*/
public static void writeScoreToFile(User user) {
try {
// 创建字符输出流对象
FileWriter desFile = new FileWriter("resources/top_list.txt", true);
// 字符缓冲输出流
BufferedWriter out = new BufferedWriter(desFile);
out.write("用户名:" + user.getUsername());
out.write(" 成绩:" + user.getScore());
// 输出换行
out.newLine();
// 关闭资源
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
User类:
package com._520it.chapter03;
/**
* 用户类
* @author Jack
* @date 2018-10-01
* @version 1.0
*/
public class User {
private String username;
private int life = 3;
private int score = 0;
public User() {
}
public User(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
运行界面程序流程图及个人体会
一、程序运行结果展示
1.程序运行效果
2.将用户成绩写入文件中:
二、个人总结及心得体会
对于这次的24点游戏来说,使用到的算法是穷举法。在写这个程序之前,我还没有接触过24点这个游戏,穷举法主要是在含有4个数字的基础上计算所有可能出现的表达式结果,运用加减乘除,加上括号的算法,计算表达式的结果,若等于24就输出。通过这次作业,我收获到了很多有用的知识,锻炼了自己的逻辑思维,进一步了解了穷举法的基本原理。