java版24点


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\\(\\)\\+\\-\\*\\/]+");

	}

}

 

转载于:https://my.oschina.net/liuyuxiang/blog/855451

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值