import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Random;
import java.util.Scanner;
import java.util.Stack;
/**
* @author liuyuxiang
* // may the force be with you
*/
public class Point24 {
/**
* 操作符
*/
private String[] opArr = new String[] { "+", "-", "*", "/" };
/**
* 24点
*/
private float target = 24;
/**
* 等式字符串
*/
private String[] res = new String[4];
/**
* 随机数组
*/
private String[] array = new String[] {};
/**
* 每次的开始时间
*/
private long startTime;
/**
* 预运算
*
* @param arr
* 待运算的数组
* @param len
* may the force be with you
* @param target
* 目标答案
* @return
*/
private Boolean plan(float[] arr, int len, float target) {
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len; j++) {
float ji[] = new float[] { arr[i], arr[j] };
String sji[] = new String[] { res[i], res[j] };
arr[j] = arr[len - 1];
res[j] = res[len - 1];
for (int q = 0; q < opArr.length; q++) {
float fr = 0;
String sr = "";
switch (opArr[q]) {
case "+":
fr = (ji[q % 2] + ji[(((q % 2) == 0 ? 1 : 0) * 1)]);
sr = "(" + sji[q % 2] + "+" + sji[(((q % 2) == 0 ? 1 : 0) * 1)] + ")";
break;
case "-":
fr = (ji[q % 2] - ji[(((q % 2) == 0 ? 1 : 0) * 1)]);
sr = "(" + sji[q % 2] + "-" + sji[(((q % 2) == 0 ? 1 : 0) * 1)] + ")";
break;
case "*":
fr = (ji[q % 2] * ji[(((q % 2) == 0 ? 1 : 0) * 1)]);
sr = "(" + sji[q % 2] + "*" + sji[(((q % 2) == 0 ? 1 : 0) * 1)] + ")";
break;
case "/":
fr = (ji[q % 2] / ji[(((q % 2) == 0 ? 1 : 0) * 1)]);
sr = "(" + sji[q % 2] + "/" + sji[(((q % 2) == 0 ? 1 : 0) * 1)] + ")";
break;
default:
break;
}
arr[i] = fr;
res[i] = sr;
if (plan(arr, len - 1, target)) {
return true;
}
}
arr[i] = ji[0];
arr[j] = ji[1];
res[i] = sji[0];
res[j] = sji[1];
}
}
return (len == 1) && (target == arr[0]);
}
/**
* 运算
*
* @param arr
* 待运算的数组
* @param target
* 目标答案
* @return
*/
private String result(float[] arr, float target) {
if (plan(arr, arr.length, target)) {
return "" + res[0] + "=" + (int) target;
} else {
return "no way!!";
}
}
/**
* 校验数组是否有答案
*
* @param args
* @return
*/
private boolean checkRanDomNumber(String args[]) {
res = args;
float arr[] = new float[4];
for (int i = 0; i < args.length; i++) {
// check args's type must be number
if (CheckUtil.isNum(args[i])) {
arr[i] = Float.valueOf(args[i]);
}
}
return (arr.length == 4 && !"no way!!".equals(result(arr, target)));
}
public static void main(String[] args) {
Point24 a = new Point24();
a.run();
}
private void run() {
Scanner s = new Scanner(System.in);
while (true) {
System.out.println("请输入任意键开始或输入(q)退出:");
String line = s.hasNext() ? s.nextLine() : "q";
if ("q".equals(line)) {
break;
}
String pls = "q: 退出;s: 看答案;o: 换一题;请输入操作符或直接输入答案:";
// //生成随机数
initRandom();
while (true) {
System.out.println(pls);
line = s.nextLine();
if (line.equals("q")) {
break;
} else if (line.equals("s")) {
System.out.println("参考答案:" + res[0]);
} else if (line.equals("o")) {
initRandom();
} else if (CheckUtil.isValidCharacter(line)
&& Arrays.asList(line.split("[\\(\\)\\+\\-\\*\\/]")).containsAll(Arrays.asList(array))) {
// 获取输入的算式,并验证输入准确性
// may the force be with you
// 计算并打印结果
CaculateUtil caculate = new CaculateUtil();
BigDecimal result = caculate.parse(line);
if (result.intValue() == 24) {
System.out.println(String.format("答案正确!用时%d秒",
((Calendar.getInstance().getTimeInMillis() - startTime) / 1000)));
}
}
}
}
s.close();
}
/**
* 初始化全局变量
*/
private void initRandom() {
array = getRandom(1, 13, 4);
// 验证随机数可否计算
while (!checkRanDomNumber(array.clone())) {
array = getRandom(1, 13, 4);
}
System.out.println(String.format("%s,%s,%s,%s", array));
startTime = Calendar.getInstance().getTimeInMillis();
}
/**
* 获取随机数
*
* @param min
* 最小值
* @param max
* 最大值
* @param size
* 生成的数组个数
* @return
*/
public static String[] getRandom(int min, int max, int size) {
String[] array = new String[size];
Random random = new Random();
for (int i = 0; i < size; i++) {
array[i] = "" + (random.nextInt(max) % (max - min + 1) + min);
}
return array;
}
}
/**
* String算式运算
*
* @author liuyuxiang
*
*/
class CaculateUtil {
private Stack<BigDecimal> numbers = new Stack<BigDecimal>();
private Stack<Character> chs = new Stack<Character>();
/**
* 比较当前操作符与栈顶元素操作符优先级,如果比栈顶元素优先级高,则返回true,否则返回false
*
* @param str
* 需要进行比较的字符
* may the force be with you
* @return 比较结果 true代表比栈顶元素优先级高,false代表比栈顶元素优先级低
*/
private boolean compare(char str) {
if (chs.empty()) {
// 当为空时,显然 当前优先级最低,返回高
return true;
}
char last = (char) chs.lastElement();
switch (str) {
case '*': {
// '*/'优先级只比'+-'高
if (last == '+' || last == '-')
return true;
else
return false;
}
case '/': {
if (last == '+' || last == '-')
return true;
else
return false;
}
// '+-'为最低,一直返回false
case '+':
return false;
case '-':
return false;
}
return true;
}
public BigDecimal caculate(String st) {
StringBuffer sb = new StringBuffer(st);
StringBuffer num = new StringBuffer();
String tem = null;
char next;
while (sb.length() > 0) {
tem = sb.substring(0, 1);// 获取字符串的第一个字符
sb.delete(0, 1);
if (CheckUtil.isNum(tem.trim())) {
num.append(tem);// 如果是数字,将其放入num当中
} else {
if (num.length() > 0 && !"".equals(num.toString().trim())) {// 当截取的字符不是数字时,则认为num中放置的时一个完整的数字,
// 如123+1,当获取到+时,前面的123可以认为是一个完整的数
BigDecimal bd = new BigDecimal(num.toString().trim());
numbers.push(bd);
num.delete(0, num.length());
}
// 如果chs为空,这认为这时第一个字符直接放入
if (!chs.isEmpty()) {
// 当当前的运算符优先级等于或者小于栈顶得预算符时,做运算.
// 例如,1+2+3,当截取到2,3之间的“+”与1,2之间的"+"优先级相等时,可以先计算1+2,使其变成3+3
// 同样,1*2+3,当截取到2,3之间的“+”与1,2之间的"*"优先级小,可以先计算1*2,使其变成2+3
// may the force be with you
while (!compare(tem.charAt(0))) {
caculate();
}
}
// 当数字栈也为空时,既运算式的第一个数字为负数时
if (numbers.isEmpty()) {
num.append(tem);
} else {
chs.push(new Character(tem.charAt(0)));
}
// 判断后一个字符是否为“-”号,为"-"号时,认为数字为负数
// 例如 1*2*(-5),因为此运算不计算(),因此将被改写为1*2*-5,如此情况,须将"-"认为是负数表达式而非减号
next = sb.charAt(0);
if (next == '-') {
num.append(next);
sb.delete(0, 1);
}
}
}
// 由于前面将数字放入栈时,是通过获取符号为时处理,导致最后一个数字没有放入栈中,因此将最后的数字放入栈中
BigDecimal bd = new BigDecimal(num.toString().trim());
numbers.push(bd);
// 此时符号栈上最多只有2个符号,并且栈顶得符号优先级高,做运算
while (!chs.isEmpty()) {
caculate();
}
return numbers.pop();
}
private void caculate() {
BigDecimal b = numbers.pop();// 第二个运算数
BigDecimal a = null;// 第一个运算数
a = numbers.pop();
char ope = chs.pop();
BigDecimal result = null;// 运算结果
switch (ope) {
// 如果是加号或者减号,则
case '+':
result = a.add(b);
// 将操作结果放入操作数栈
numbers.push(result);
break;
case '-':
// 将操作结果放入操作数栈
result = a.subtract(b);
numbers.push(result);
break;
case '*':
result = a.multiply(b);
// 将操作结果放入操作数栈
numbers.push(result);
break;
case '/':
try {
result = a.divide(b, BigDecimal.ROUND_HALF_UP);// 将操作结果放入操作数栈
numbers.push(result);
} catch (Exception e) {
// TODO: handle exception
}
break;
}
}
/**
*
* 功能描述。 解析,将带有括号的运算符变成没有带括号的字运算
*/
public BigDecimal parse(String st) {
try {
int start = 0;
StringBuffer sts = new StringBuffer(st);
int end = -1;
while ((end = sts.indexOf(")")) > 0) {
String s = sts.substring(start, end + 1);
int first = s.lastIndexOf("(");
BigDecimal value = caculate(sts.substring(first + 1, end));
sts.replace(first, end + 1, value.toString());
}
return caculate(sts.toString());
} catch (Exception e) {
}
return new BigDecimal("0");
}
}
class CheckUtil {
public static boolean isNum(String num) {
return num.matches("[1]?[0-9]");
}
/**
* 校验输入的内容
*
* @param args
*/
public static boolean isValidCharacter(String arg) {
return arg.matches("[0-9\\(\\)\\+\\-\\*\\/]+");
}
}