第3章 作业
24点游戏是经典的纸牌益智游戏。
完整代码在最后
常见游戏规则:
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
基本要求: 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式,用擅长的语言(C/C++/Java或其他均可)实现程序解决问题。
-
1.程序风格良好(使用自定义注释模板)
-
2.列出表达式无重复。
提高要求:用户初始生命值为一给定值(比如3),初始分数为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。
-
- 程序风格良好(使用自定义注释模板)
- 2.使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。
- 3.所有成绩均可记录在TopList.txt文件中。
先展示一下运行结果:
思路:我们首先完成基本要求,首先用map初始化一下扑克牌,之后随机生成4张扑克牌,之后对4张扑克牌的值和操作符进行全排列,之后进行组合,进行判断是否值为24,并将值为24的保存在结果集中。然后是提高要求,我们使用java的图形用户界面来做,设置一些基本的控件之后,通过之前的方法,我们获取到可以生成24的扑克牌,我们通过label为用户显示要计算的扑克牌,用户输入要计算的字符串,之后我们获取到字符串,对字符串进行整理,利用栈进行计算,判断结果是否正确,最后我们再加上分数,生命值,计时功能,并将结果写入数据库。
- 初始化一些基本变量
static Integer score = 0; //分数
static Integer life = 3; //生命值
static Map<String, Integer> map = new HashMap<>(); //初始化扑克牌map
static List<String> sourceList = new ArrayList<>(); //源list
static List<String> targetList = new ArrayList<>(); //生成随机的目标list
static Set<String> set; //可以进行运算得到24的set集合
static JTextField countText; //输入框
static JButton signIn; //press按钮
static JButton nextQuestion; //next按钮
static JLabel label; //标题label
static JLabel scoreLabel1; //分数label
static JLabel lifeLabel1; //生命值label
static JLabel question; //问题label
static String string; //获取到输入框的字符串
static Set<String> resultSet1; //正确答案的结果集
static Integer time = 90; //时间
static JLabel timeLabel1; //时间label
static Thread thread; //时间的线程
public static char[] op = { '+', '-', '*', '/', '(', ')' }; //操作符数组
public static String[] strOp = { "+", "-", "*", "/", "(", ")" };
/**
* 先初始化map
*/
static {
map.put("A", 1);
for (int i = 2; i <= 10; i++) {
map.put(String.valueOf(i), i);
}
map.put("J", 11);
map.put("Q", 12);
map.put("K", 13);
}
/**
* 利用线程实现计时功能
* @author yangjiaxin
*
*/
class MyThread implements Runnable {
public void run() {
while (time > 0) {
time--;
timeLabel1.setText(time + "");
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
//Jishi.this.dispose();
}
};
- 将随机的4张牌进行全排列组合
/**
* 获取随机的4张扑克牌
*/
public static void getrandom() {
for (String key : map.keySet()) {
sourceList.add(key);
}
Random random = new Random();
for (int i = 0; i < 4; i++) {
Integer integer = random.nextInt(13);
targetList.add(sourceList.get(integer));
}
// System.out.print("随机的四张牌为:");
// for (String string : targetList) {
// System.out.print(string+" ");
// }
// System.out.println();
}
//
// /**
// * 打印结果集
// *
// * @param resultSet
// * 结果集
// */
// private static void printlnResultSet(Collection<String> resultSet) {
// for (String str : resultSet) {
// System.out.println(str);
// }
// }
/**
* 得到给定整形数组的全排列情况
*
* @param numbers
* 给定的整形数组
* @return 全排列数组
*/
private static int[][] arrangeAllNumbers(int[] numbers) {
List<int[]> list = new ArrayList<int[]>();
allSort(numbers, 0, numbers.length - 1, list);
int[][] resultSet = new int[list.size()][list.get(0).length];
resultSet = list.toArray(resultSet);
return resultSet;
}
/**
* 得到给定的操作中出现的所有操作符排列情况
*
* @param operators
* 出现的操作符数组
* @param number
* 每组操作符的数量
* @return 所有操作符排列数组
*/
private static char[][] arrangeAllOperators(char[] operators, int number) {
int setSize = (int) Math.pow(operators.length, number);
int index = 0;
char[][] resultSet = new char[setSize][number];
for (int i = 0; i < operators.length; i++) {
for (int j = 0; j < operators.length; j++) {
for (int k = 0; k < operators.length; k++) {
resultSet[index][0] = operators[i];
resultSet[index][1] = operators[j];
resultSet[index][2] = operators[k];
index++;
}
}
}
return resultSet;
}
/**
*
*
* @param numbers
* 给定进行运算的一组整数,4个数为一组
* @param targetNumber
* 想要得到的结果
* @return 所有可能得到想要的结果的所有运算形式的字符串形式集合
* @throws Exception
* 如果不能得到想要的结果,则抛出该异常,表明根据指定的一组数字通过一系列的加减乘除不能得到想要的结果
*/
public static Set<String> caculate(int[] numbers, int targetNumber)
throws Exception {
resultSet1 = new HashSet<String>();// 这里用Set而不是用List,主要是因为当给定的一组数字中如果有重复数字的话,同一结果会被出现多次,如果用List存放的话,会将重复的结果都存放起来,而Set会自动消除重复值
char[][] operatorsArrangement = arrangeAllOperators(new char[] { '+',
'-', '*', '/' }, 3);
int[][] numbersArrangement = arrangeAllNumbers(numbers);
for (int[] nums : numbersArrangement)
for (char[] operators : operatorsArrangement) {
int result = 0;
try {
result = caculate(nums, operators);
} catch (Exception e) {// 出现非精确计算
continue;
}
if (result == targetNumber)
resultSet1.add(buildString(nums, operators, targetNumber));// 如果计算后的结果等于想要的结果,就存放到集合中
}
if (resultSet1.isEmpty())
throw new Exception("给定的数字:" + Arrays.toString(numbers)
+ "不能通过加减乘除运算得到结果:" + targetNumber);
return resultSet1;
}
/**
* 将一组整型数字以给定的操作符按顺序拼接为一个完整的表达式字符串
*
* @param nums
* 一组整型数字
* @param operators
* 一组操作符
* @param target
* 目标值
* @return 拼接好的表达式字符串
*/
private static String buildString(int[] nums, char[] operators, int target) {
String str = String.valueOf(nums[0]);
for (int i = 0; i < operators.length; i++) {
if (operators[i] == '+' || operators[i] == '-' ) {
str = "("+ str + ' ' + operators[i] + ' ' + nums[i + 1] +")";
} else {
str = str + ' ' + operators[i] + ' ' + nums[i + 1];
}
}
str = str + " = " + target;
return str;
}
/**
* 将给定的一组数字以给定的操作符按顺序进行运算,如:int result = caculate(new int[]{3,4,5,8}, new
* char[]{'+','-','*'});
*
* @param nums
* 一组数字
* @param operators
* 一组运算符,数量为数字的个数减1
* @return 最后的计算结果
* @throws Exception
* 当计算结果不精确时,抛出该异常,主要是针对除法运算,例如18 / 8 = 2,诸如这样不精确计算将抛出该异常
*/
private static int caculate(int[] nums, char[] operators) throws Exception {
int result = 0;
for (int i = 0; i < operators.length; i++) {
if (i == 0) {
result = caculate(nums[i], nums[i + 1], operators[i]);
} else {
result = caculate(result, nums[i + 1], operators[i]);
}
}
return result;
}
/**
* 根据指定操作符将两个给定的数字进行计算
*
* @param num1
* 数字1
* @param num2
* 数字2
* @param operator
* 操作符,只能从“+、-、*、/”4个操作符中取值
* @return 计算结果
* @throws Exception
* 当计算结果不精确时,抛出该异常,主要是针对除法运算,例如18 / 8 = 2,诸如这样不精确计算将抛出该异常
*/
private static int caculate(int num1, int num2, char operator)
throws Exception {
double result = 0;
switch (operator) {// 根据操作符做相应的计算操作
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = (double) num1 / (double) num2;
break;
}
if (!check(result))
throw new Exception("不精确的计算数字");
return (int) result;
}
/**
* 检查指定的浮点数是否可以直接转换为整型数字而不损失精度
*
* @param result
* 要检查的浮点数
* @return 如果可以进行无损转换,返回true,否则返回false
*/
private static boolean check(double result) {
String str = String.valueOf(result);
int pointIndex = str.indexOf(".");// 小数点的下标值
String fraction = str.substring(pointIndex + 1);
return fraction.equals("0") ? true : false;// 通过判断小数点后是否只有一个0来确定是否可以无损转换为整型数值
}
/**
* 对传入的整型数组buf进行全排列
*
* @param buf
* 要进行全排列的整型数组
* @param start
* 开始的下标值
* @param end
* 结束下标值
* @param list
* 保存最后全排列结果的集合
*/
private static void allSort(int[] buf, int start, int end, List<int[]> list) {
if (start == end) {// 当只要求对数组中一个字母进行全排列时,只要就按该数组输出即可
int[] a = new int[buf.length];
System.arraycopy(buf, 0, a, 0, a.length);
list.add(a);
} else {// 多个字母全排列
for (int i = start; i <= end; i++) {
int temp = buf[start];// 交换数组第一个元素与后续的元素
buf[start] = buf[i];
buf[i] = temp;
allSort(buf, start + 1, end, list);// 后续元素递归全排列
temp = buf[start];// 将交换后的数组还原
buf[start] = buf[i];
buf[i] = temp;
}
}
}
- 利用栈进行计算
/**
* 判断是否为数字
* @param c
* @return
*/
public static boolean isDigit(char c) {
if (c >= '0' && c <= '9') {
return true;
}
return false;
}
/**
* 判断是否为操作符
* @param c
* @return
*/
public static boolean isOp(char c) {
for (int i = 0; i < op.length; i++) {
if (op[i] == c) {
return true;
}
}
return false;
}
public static boolean isOp(String s) {
for (int i = 0; i < strOp.length; i++) {
if (strOp[i].equals(s)) {
return true;
}
}
return false;
}
/**
* 处理输入的计算式
*
* @param str
* @return
*/
public static List<String> work(String str) {
List<String> list = new ArrayList<String>();
char c;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (isDigit(c)) {
sb.append(c);
}
if (isOp(c)) {
if (sb.toString().length() > 0) {
list.add(sb.toString());
sb.delete(0, sb.toString().length());
}
list.add(c + "");
}
}
if (sb.toString().length() > 0) {
list.add(sb.toString());
sb.delete(0, sb.toString().length());
}
return list;
}
// public static void printList(List<String> list) {
// for (String o : list) {
// System.out.print(o + " ");
// }
// }
/**
* 中缀表达式转化为后缀表达式 1,遇到数字输出 2,遇到高优先级的全部出栈 3,最后全部出栈
*/
public static List<String> InfixToPostfix(List<String> list) {
List<String> Postfixlist = new ArrayList<String>();// 存放后缀表达式
Stack<String> stack = new Stack<String>();// 暂存操作符
// stack.push('#');
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (s.equals("(")) {
stack.push(s);
} else if (s.equals("*") || s.equals("/")) {
stack.push(s);
} else if (s.equals("+") || s.equals("-")) {
if (!stack.empty()) {
while (!(stack.peek().equals("("))) {
Postfixlist.add(stack.pop());
if (stack.empty()) {
break;
}
}
stack.push(s);
} else {
stack.push(s);
}
} else if (s.equals(")")) {
while (!(stack.peek().equals("("))) {
Postfixlist.add(stack.pop());
}
stack.pop();
} else {
Postfixlist.add(s);
}
if (i == list.size() - 1) {
while (!stack.empty()) {
Postfixlist.add(stack.pop());
}
}
}
return Postfixlist;
}
/**
* 后缀表达式计算
*/
public static int doCal(List<String> list) {
Stack<Integer> stack = new Stack<Integer>();
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
int t = 0;
if (!isOp(s)) {
t = Integer.parseInt(s);
stack.push(t);
} else {
if (s.equals("+")) {
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2 + a1;
stack.push(v);
} else if (s.equals("-")) {
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2 - a1;
stack.push(v);
} else if (s.equals("*")) {
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2 * a1;
stack.push(v);
} else if (s.equals("/")) {
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2 / a1;
stack.push(v);
}
}
}
return stack.pop();
}
/**
* 判断用户输入的字符串是否可以得到24点
* @return
*/
public static boolean cal() {
List<String> list = work(string);
List<String> list2 = InfixToPostfix(list);
// System.out.println("原式为:" + string);
// System.out.print("后缀表达式为:");
// printList(list2);
// System.out.println(" ");
//System.out.println("计算结果为:" + doCal(list2));
if (doCal(list2) == 24) {
return true;
}
return false;
}
/**
* 获取到可以组成24点的有效扑克牌
* @return
*/
public static boolean getUsefulRandom() {
getrandom();
int[] a = new int[4];
int i = 0;
for (String string : targetList) {
a[i] = map.get(string);
i++;
}
try {
set = caculate(a, 24);
return true;
} catch (Exception e) {
//e.printStackTrace();//开发期间方便查找错误,测试通过后就无需打印错误信息了
//System.err.println(e.getMessage());
targetList.clear();
return false;
}
}
public static void getUserfulRandom1() {
boolean b = false;
while (!b) {
b = getUsefulRandom();
}
System.out.print("有效的四张牌为:");
for (String string : targetList) {
System.out.print(string+" ");
}
System.out.println();
//printlnResultSet(set);
}
最后的是全部的代码:
package shilaoshi;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class TwentyFour extends JFrame{
static Integer score = 0; //分数
static Integer life = 3; //生命值
static Map<String, Integer> map = new HashMap<>(); //初始化扑克牌map
static List<String> sourceList = new ArrayList<>(); //源list
static List<String> targetList = new ArrayList<>(); //生成随机的目标list
static Set<String> set; //可以进行运算得到24的set集合
static JTextField countText; //输入框
static JButton signIn; //press按钮
static JButton nextQuestion; //next按钮
static JLabel label; //标题label
static JLabel scoreLabel1; //分数label
static JLabel lifeLabel1; //生命值label
static JLabel question; //问题label
static String string; //获取到输入框的字符串
static Set<String> resultSet1; //正确答案的结果集
static Integer time = 90; //时间
static JLabel timeLabel1; //时间label
static Thread thread; //时间的线程
public static char[] op = { '+', '-', '*', '/', '(', ')' }; //操作符数组
public static String[] strOp = { "+", "-", "*", "/", "(", ")" };
/**
* 先初始化map
*/
static {
map.put("A", 1);
for (int i = 2; i <= 10; i++) {
map.put(String.valueOf(i), i);
}
map.put("J", 11);
map.put("Q", 12);
map.put("K", 13);
}
/**
* 利用线程实现计时功能
* @author yangjiaxin
*
*/
class MyThread implements Runnable {
public void run() {
while (time > 0) {
time--;
timeLabel1.setText(time + "");
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
//Jishi.this.dispose();
}
};
/**
* 构造方法初始化可视化图形界面
*/
public TwentyFour() {
// TODO Auto-generated constructor stub
setBg();
this.setTitle("24点小游戏");
this.setSize(600, 400);
this.setLocation(300, 100);
this.setLayout(null);
JLabel timeLabel = new JLabel("时间:");
timeLabel.setFont(new Font("宋体", Font.PLAIN, 20));
timeLabel.setForeground(Color.decode("#9C9C9C"));
timeLabel.setBounds(480, 110, 60, 40);
timeLabel1 = new JLabel(time.toString());
timeLabel1.setFont(new Font("宋体", Font.PLAIN, 20));
timeLabel1.setForeground(Color.decode("#9C9C9C"));
timeLabel1.setBounds(540, 110, 60, 40);
label = new JLabel("24点小游戏",JLabel.CENTER);
label.setFont(new Font("宋体",Font.PLAIN,20));
label.setForeground(Color.decode("#9C9C9C"));
label.setBounds( 200, 10, 200, 80);
this.add(label);
JLabel questionLabel = new JLabel("题目:");
questionLabel.setFont(new Font("宋体", Font.PLAIN, 20));
questionLabel.setForeground(Color.decode("#9C9C9C"));
questionLabel.setBounds(70, 110, 90, 40);
question = new JLabel("");
question.setBounds(150, 110, 350, 40);
question.setFont(new Font("宋体", Font.PLAIN, 20));
question.setForeground(Color.decode("#9C9C9C"));
getUserfulRandom1();
question.setText(targetList.toString());
JLabel result = new JLabel("result:");
result.setFont(new Font("宋体", Font.PLAIN, 20));
result.setForeground(Color.decode("#9C9C9C"));
result.setBounds(70, 190, 90, 40);
JLabel scoreLabel = new JLabel("score:");
scoreLabel.setFont(new Font("宋体", Font.PLAIN, 20));
scoreLabel.setForeground(Color.decode("#9C9C9C"));
scoreLabel.setBounds(480, 50, 60, 40);
scoreLabel1 = new JLabel(score.toString());
scoreLabel1.setFont(new Font("宋体", Font.PLAIN, 20));
scoreLabel1.setForeground(Color.decode("#9C9C9C"));
scoreLabel1.setBounds(540, 50, 60, 40);
JLabel lifeLabel = new JLabel("life:");
lifeLabel.setFont(new Font("宋体", Font.PLAIN, 20));
lifeLabel.setForeground(Color.decode("#9C9C9C"));
lifeLabel.setBounds(480, 80, 60, 40);
lifeLabel1 = new JLabel(life.toString());
lifeLabel1.setFont(new Font("宋体", Font.PLAIN, 20));
lifeLabel1.setForeground(Color.decode("#9C9C9C"));
lifeLabel1.setBounds(540, 80, 60, 40);
countText = new JTextField(200);
countText.setBounds(150, 190, 350, 40);
nextQuestion = new JButton("next");
nextQuestion.setBounds(320, 290, 60, 30);
signIn = new JButton("press");
signIn.setBounds(240, 290, 60, 30);
// signIn.addActionListener(new ActionListener() {
//
// @Override
// public void actionPerformed(ActionEvent e) {
// // TODO Auto-generated method stub
// string = countText.getText();
// boolean b = cal();
// if (b) {
// label.setText("恭喜你答对了");
// score = score + 20;
// scoreLabel1.setText(score.toString());
// }else {
// label.setText("答错了");
// life--;
// lifeLabel1.setText(life.toString());
//
// }
// }
//
// });
this.add(timeLabel1);
this.add(timeLabel);
this.add(questionLabel);
this.add(countText);
this.add(signIn);
this.add(question);
this.add(result);
this.add(scoreLabel);
this.add(scoreLabel1);
this.add(lifeLabel);
this.add(lifeLabel1);
this.add(nextQuestion);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
thread = new Thread(new MyThread()); //开启线程
thread.start();
start(); //开始答题
}
/**
* 开始答题的方法
*/
public void start() {
signIn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
string = countText.getText();
boolean b = cal();
if (b) {
label.setText("恭喜你答对了");
score = score + 20;
scoreLabel1.setText(score.toString());
}else {
label.setText("答错了,正确答案如下");
countText.setText(resultSet1.toString());
life = life - 1;
System.out.println("life-----"+life);
lifeLabel1.setText(life.toString());
}
if (life<0) {
save(score);
label.setText("life out");
score = 0;
life = 3;
}
}
});
nextQuestion.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
time = 90;
label.setText("24点小游戏");
if (life == 3) {
scoreLabel1.setText(score.toString());
lifeLabel1.setText(life.toString());
}
targetList.clear();
getUserfulRandom1();
question.setText(targetList.toString());
countText.setText("");
}
});
}
/**
* 建立连接
*
* @return
*/
public static Connection getConnection() {
Connection conn = null;
try {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.建立连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/Fish?useSSL=yes", "root", "1234");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("注册驱动失败");
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
/**
* save函数,将score存入数据库
*
* @param strDate
* @param state
*/
public static void save(Integer score) {
PreparedStatement ps = null;
Connection conn = null;
String sql = "insert into twentyFour(score) values(?)";
try {
conn = getConnection();
ps = conn.prepareStatement(sql);
ps.setInt(1, score);
ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 获取随机的4张扑克牌
*/
public static void getrandom() {
for (String key : map.keySet()) {
sourceList.add(key);
}
Random random = new Random();
for (int i = 0; i < 4; i++) {
Integer integer = random.nextInt(13);
targetList.add(sourceList.get(integer));
}
}
/**
* 得到给定整形数组的全排列情况
*
* @param numbers
* 给定的整形数组
* @return 全排列数组
*/
private static int[][] arrangeAllNumbers(int[] numbers) {
List<int[]> list = new ArrayList<int[]>();
allSort(numbers, 0, numbers.length - 1, list);
int[][] resultSet = new int[list.size()][list.get(0).length];
resultSet = list.toArray(resultSet);
return resultSet;
}
/**
* 得到给定的操作中出现的所有操作符排列情况
*
* @param operators
* 出现的操作符数组
* @param number
* 每组操作符的数量
* @return 所有操作符排列数组
*/
private static char[][] arrangeAllOperators(char[] operators, int number) {
int setSize = (int) Math.pow(operators.length, number);
int index = 0;
char[][] resultSet = new char[setSize][number];
for (int i = 0; i < operators.length; i++) {
for (int j = 0; j < operators.length; j++) {
for (int k = 0; k < operators.length; k++) {
resultSet[index][0] = operators[i];
resultSet[index][1] = operators[j];
resultSet[index][2] = operators[k];
index++;
}
}
}
return resultSet;
}
/**
*
*
* @param numbers
* 给定进行运算的一组整数,4个数为一组
* @param targetNumber
* 想要得到的结果
* @return 所有可能得到想要的结果的所有运算形式的字符串形式集合
* @throws Exception
* 如果不能得到想要的结果,则抛出该异常,表明根据指定的一组数字通过一系列的加减乘除不能得到想要的结果
*/
public static Set<String> caculate(int[] numbers, int targetNumber)
throws Exception {
resultSet1 = new HashSet<String>();// 这里用Set而不是用List,主要是因为当给定的一组数字中如果有重复数字的话,同一结果会被出现多次,如果用List存放的话,会将重复的结果都存放起来,而Set会自动消除重复值
char[][] operatorsArrangement = arrangeAllOperators(new char[] { '+',
'-', '*', '/' }, 3);
int[][] numbersArrangement = arrangeAllNumbers(numbers);
for (int[] nums : numbersArrangement)
for (char[] operators : operatorsArrangement) {
int result = 0;
try {
result = caculate(nums, operators);
} catch (Exception e) {// 出现非精确计算
continue;
}
if (result == targetNumber)
resultSet1.add(buildString(nums, operators, targetNumber));// 如果计算后的结果等于想要的结果,就存放到集合中
}
if (resultSet1.isEmpty())
throw new Exception("给定的数字:" + Arrays.toString(numbers)
+ "不能通过加减乘除运算得到结果:" + targetNumber);
return resultSet1;
}
/**
* 将一组整型数字以给定的操作符按顺序拼接为一个完整的表达式字符串
*
* @param nums
* 一组整型数字
* @param operators
* 一组操作符
* @param target
* 目标值
* @return 拼接好的表达式字符串
*/
private static String buildString(int[] nums, char[] operators, int target) {
String str = String.valueOf(nums[0]);
for (int i = 0; i < operators.length; i++) {
if (operators[i] == '+' || operators[i] == '-' ) {
str = "("+ str + ' ' + operators[i] + ' ' + nums[i + 1] +")";
} else {
str = str + ' ' + operators[i] + ' ' + nums[i + 1];
}
}
str = str + " = " + target;
return str;
}
/**
* 将给定的一组数字以给定的操作符按顺序进行运算,如:int result = caculate(new int[]{3,4,5,8}, new
* char[]{'+','-','*'});
*
* @param nums
* 一组数字
* @param operators
* 一组运算符,数量为数字的个数减1
* @return 最后的计算结果
* @throws Exception
* 当计算结果不精确时,抛出该异常,主要是针对除法运算,例如18 / 8 = 2,诸如这样不精确计算将抛出该异常
*/
private static int caculate(int[] nums, char[] operators) throws Exception {
int result = 0;
for (int i = 0; i < operators.length; i++) {
if (i == 0) {
result = caculate(nums[i], nums[i + 1], operators[i]);
} else {
result = caculate(result, nums[i + 1], operators[i]);
}
}
return result;
}
/**
* 根据指定操作符将两个给定的数字进行计算
*
* @param num1
* 数字1
* @param num2
* 数字2
* @param operator
* 操作符,只能从“+、-、*、/”4个操作符中取值
* @return 计算结果
* @throws Exception
* 当计算结果不精确时,抛出该异常,主要是针对除法运算,例如18 / 8 = 2,诸如这样不精确计算将抛出该异常
*/
private static int caculate(int num1, int num2, char operator)
throws Exception {
double result = 0;
switch (operator) {// 根据操作符做相应的计算操作
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = (double) num1 / (double) num2;
break;
}
if (!check(result))
throw new Exception("不精确的计算数字");
return (int) result;
}
/**
* 检查指定的浮点数是否可以直接转换为整型数字而不损失精度
*
* @param result
* 要检查的浮点数
* @return 如果可以进行无损转换,返回true,否则返回false
*/
private static boolean check(double result) {
String str = String.valueOf(result);
int pointIndex = str.indexOf(".");// 小数点的下标值
String fraction = str.substring(pointIndex + 1);
return fraction.equals("0") ? true : false;// 通过判断小数点后是否只有一个0来确定是否可以无损转换为整型数值
}
/**
* 对传入的整型数组buf进行全排列
*
* @param buf
* 要进行全排列的整型数组
* @param start
* 开始的下标值
* @param end
* 结束下标值
* @param list
* 保存最后全排列结果的集合
*/
private static void allSort(int[] buf, int start, int end, List<int[]> list) {
if (start == end) {// 当只要求对数组中一个字母进行全排列时,只要就按该数组输出即可
int[] a = new int[buf.length];
System.arraycopy(buf, 0, a, 0, a.length);
list.add(a);
} else {// 多个字母全排列
for (int i = start; i <= end; i++) {
int temp = buf[start];// 交换数组第一个元素与后续的元素
buf[start] = buf[i];
buf[i] = temp;
allSort(buf, start + 1, end, list);// 后续元素递归全排列
temp = buf[start];// 将交换后的数组还原
buf[start] = buf[i];
buf[i] = temp;
}
}
}
///
/**
* 判断是否为数字
* @param c
* @return
*/
public static boolean isDigit(char c) {
if (c >= '0' && c <= '9') {
return true;
}
return false;
}
/**
* 判断是否为操作符
* @param c
* @return
*/
public static boolean isOp(char c) {
for (int i = 0; i < op.length; i++) {
if (op[i] == c) {
return true;
}
}
return false;
}
public static boolean isOp(String s) {
for (int i = 0; i < strOp.length; i++) {
if (strOp[i].equals(s)) {
return true;
}
}
return false;
}
/**
* 处理输入的计算式
*
* @param str
* @return
*/
public static List<String> work(String str) {
List<String> list = new ArrayList<String>();
char c;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (isDigit(c)) {
sb.append(c);
}
if (isOp(c)) {
if (sb.toString().length() > 0) {
list.add(sb.toString());
sb.delete(0, sb.toString().length());
}
list.add(c + "");
}
}
if (sb.toString().length() > 0) {
list.add(sb.toString());
sb.delete(0, sb.toString().length());
}
return list;
}
// public static void printList(List<String> list) {
// for (String o : list) {
// System.out.print(o + " ");
// }
// }
/**
* 中缀表达式转化为后缀表达式 1,遇到数字输出 2,遇到高优先级的全部出栈 3,最后全部出栈
*/
public static List<String> InfixToPostfix(List<String> list) {
List<String> Postfixlist = new ArrayList<String>();// 存放后缀表达式
Stack<String> stack = new Stack<String>();// 暂存操作符
// stack.push('#');
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (s.equals("(")) {
stack.push(s);
} else if (s.equals("*") || s.equals("/")) {
stack.push(s);
} else if (s.equals("+") || s.equals("-")) {
if (!stack.empty()) {
while (!(stack.peek().equals("("))) {
Postfixlist.add(stack.pop());
if (stack.empty()) {
break;
}
}
stack.push(s);
} else {
stack.push(s);
}
} else if (s.equals(")")) {
while (!(stack.peek().equals("("))) {
Postfixlist.add(stack.pop());
}
stack.pop();
} else {
Postfixlist.add(s);
}
if (i == list.size() - 1) {
while (!stack.empty()) {
Postfixlist.add(stack.pop());
}
}
}
return Postfixlist;
}
/**
* 后缀表达式计算
*/
public static int doCal(List<String> list) {
Stack<Integer> stack = new Stack<Integer>();
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
int t = 0;
if (!isOp(s)) {
t = Integer.parseInt(s);
stack.push(t);
} else {
if (s.equals("+")) {
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2 + a1;
stack.push(v);
} else if (s.equals("-")) {
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2 - a1;
stack.push(v);
} else if (s.equals("*")) {
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2 * a1;
stack.push(v);
} else if (s.equals("/")) {
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2 / a1;
stack.push(v);
}
}
}
return stack.pop();
}
/**
* 判断用户输入的字符串是否可以得到24点
* @return
*/
public static boolean cal() {
List<String> list = work(string);
List<String> list2 = InfixToPostfix(list);
// System.out.println("原式为:" + string);
// System.out.print("后缀表达式为:");
// printList(list2);
// System.out.println(" ");
//System.out.println("计算结果为:" + doCal(list2));
if (doCal(list2) == 24) {
return true;
}
return false;
}
/**
* 获取到可以组成24点的有效扑克牌
* @return
*/
public static boolean getUsefulRandom() {
getrandom();
int[] a = new int[4];
int i = 0;
for (String string : targetList) {
a[i] = map.get(string);
i++;
}
try {
set = caculate(a, 24);
return true;
} catch (Exception e) {
//e.printStackTrace();//开发期间方便查找错误,测试通过后就无需打印错误信息了
//System.err.println(e.getMessage());
targetList.clear();
return false;
}
}
public static void getUserfulRandom1() {
boolean b = false;
while (!b) {
b = getUsefulRandom();
}
System.out.print("有效的四张牌为:");
for (String string : targetList) {
System.out.print(string+" ");
}
System.out.println();
//printlnResultSet(set);
}
/**
* 设置背景图片
*/
public void setBg(){
((JPanel)this.getContentPane()).setOpaque(false);
ImageIcon img = new ImageIcon
("bg.jpg");
JLabel background = new JLabel(img);
this.getLayeredPane().add(background, new Integer(Integer.MIN_VALUE));
background.setBounds(0, 0, img.getIconWidth(), img.getIconHeight());
}
public static void main(String[] args) {
new TwentyFour();
}
}