1.游戏简介
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1).用户初始生命值为一给定值(比如3),初始分数为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。
2.主要算法
利用栈来计算表达式的值,在与24进行比较.
2.1数据结构
LinkedList 相当于一个栈,其pop(),push()函数,就是弹栈,入栈的功能.
//用于记录操作符
private static LinkedList<String> operators = new LinkedList<>();
//用于展示后缀表达式
private static StringBuilder sb = new StringBuilder();
2.2 中缀表达式转后缀表达式
2.2.1规则
中缀表达式a + b*c + (d * e + f) * g,其转换成后缀表达式则为a b c * + d e * f + g * +。
转换过程需要用到栈,具体过程如下:
1)如果遇到操作数,我们就直接将其输出。
2)如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。
3)如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
4)如果遇到任何其他的操作符,如(“+”, “*”,“(”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。有一点需要注意,只有在遇到" ) “的情况下我们才弹出” ( “,其他情况我们都不会弹出” ( "。
5)如果我们读到了输入的末尾,则将栈中所有元素依次弹出。
2.2.2 代码实现
//中缀表达式转为后缀表达式
private static int transferToPostfix(LinkedList<String> list) {
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (isOperator(s)) {
//1.操作符的栈为空直接入栈
if (operators.isEmpty()) {
operators.push(s);
} else {
//A1:如果读入的操作符为非")"且优先级比栈顶元素的优先级高或一样,则将操作符压入栈
if (priority(operators.peek()) <= priority(s) && !s.equals(")")){//peek():检索但不删除此列表的头(第一个元素)。
operators.push(s);
}//A2:如果读入的操作符为非")"且优先级比栈顶元素的优先级低,则弹出栈顶运算符
else if (!s.equals(")") && priority(operators.peek()) > priority(s)) {
while (operators.size() != 0 && priority(operators.peek()) >= priority(s)
&& !operators.peek().equals("(")) {
if (!operators.peek().equals("(")) {
String operator = operators.pop();
sb.append(operator).append(" ");
}
}
operators.push(s);
}
//如果读入的操作符是")",则弹出从栈顶开始第一个"("及其之前的所有操作符
else if (s.equals(")")) {
while (!operators.peek().equals("(")) {
String operator = operators.pop();
sb.append(operator).append(" ");
}
//弹出"("
operators.pop();
}
}
}
//读入的为非操作符
else {
sb.append(s).append(" ");
}
}
if (!operators.isEmpty()) {
Iterator<String> iterator = operators.iterator();
while (iterator.hasNext()) {
String operator = iterator.next();
sb.append(operator).append(" ");
iterator.remove();
}
}
// System.out.println("后缀: " + sb);
int flag=calculate();
return flag;
}
2.3 计算后缀表达式的值
简单来讲,后缀表达式的计算就是从左到右扫描表达式,遇到数字就将其压入栈,遇到操作符表示可以计算,这时取出栈顶的两个元素进行操作,然后再次将结果压入栈,最后栈里会留下一个元素,该元素就是运行结果.
//根据后缀表达式计算结果
private static int calculate() {
int flag=0;
LinkedList<String> mList = new LinkedList<>();
String[] postStr = sb.toString().split(" ");
for (String s : postStr) {
//字符则进行相应计算
if (isOperator(s)) {
if (!mList.isEmpty()) {
int num1 = Integer.valueOf(mList.pop());
int num2 = Integer.valueOf(mList.pop());
if (s.equals("/") && num1 == 0) {
System.out.println("除数不能为0");
return 0;
}
int newNum = cal(num2, num1, s);//计算出弹出来的两个数的结果
mList.push(String.valueOf(newNum));
}
} else {
//数字则压入栈中
mList.push(s);
}
}//
if (!mList.isEmpty()) {
if(Integer.parseInt(mList.pop())==24){
++score;
flag=2;
System.out.println("真棒! 加一分");
}else{
flag=1;
System.out.println("可惜!");
}
//System.out.println("result: " + mList.pop());
//int result= Integer.parseInt(mList.pop());
}
return flag;
}
2.4 通过线程控制输入的时间
private void show() {
int a = 0;
System.out.println("请在输60秒内输入表达式(每个字符之间空一格):");
new Thread() {
public void run() {
flag=stack.m();
if(Stack.live<1){
System.exit(0);
}
}
}.start();
new Thread() {
public void run() {
for (int i = 0; i < 10; ) {
try {
Thread.sleep(1000);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(flag==2){
Stack.live++;
flag=1;
}
Stack.live--;
System.out.println("时间到!,进入下一题(当前生命值:"+Stack.live+" 分数:"+Stack.score+")");
show();
if(Stack.live<1){
fileOut= new File("D://TopList.txt");
try {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
bufferedWriter=new BufferedWriter(new FileWriter(fileOut,true));
bufferedWriter.write(String.valueOf(df.format(new Date())+"-score:"+Stack.score+"\n"));
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("您当前生命值已用完,拜拜啦您嘞!!");
System.exit(0);
}
}
}.start();
}
3.运行结果
谢谢!