Java 24点游戏递归实现(借鉴别人,附链接)

24点递归理解起来确实难,基本要求做不出来,只好看别人做的
原作者:https://blog.csdn.net/qq_36691353/article/details/82949813

题目:

24点游戏是经典的纸牌益智游戏。
常见游戏规则:
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
基本:
随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式且表达式无重复。

提高:
除此之外,我们还可以多加一点功能让它变成一个游戏,比如我们随机给出四张牌并给玩家设置一个生命值,让其在一定的时间内组成表达式,如果值为24,则加分,答错则扣分和扣生命值!最后将成绩存在本地文件!

基本(列出所有值为24的表达式):

这里是用递归实现的(思想):
(1)在四个数中取俩个(例如:第一个,第二个)进行计算(遍历每一种情况)
(2)计算结果
(3)将结果放在数组中的第一个位置,并将空余出来的位置(第二个)存放最后一个数字,形成一个新数组
(4)递归调用函数计算找到表达式返回
(5)将步骤2的结果移除,并将该组合中的两个数重新放回该数组,进行下一个循环遍历另外俩个数继续计算
Java源码:

package zy;

import java.util.Random;

public class Found {
static int n = 4;//运算次数标记
static int[] A = new int[4];//存放四个数字
static String[] B = new String[4];//存放字符串型的四个数字,也存放表达式
static int count = 0;//计数
public static void f(int n) {
	//判断是否已完成三次运算
	if(n == 1)
		if(A[0] == 24) {//A[0]里面存放的最后的结果
			System.out.println(B[0]);//B[0]存放的结果表达式
			count++;
		}
		else {//空的不做处理进行下一条语句
			
		}
	//从数组中任意取出俩个数的组合
	for(int i = 0;i < n;i++) {
		for(int j = i + 1;j < n;j++) {
			int a,b;
			String x,y;
			a = A[i];
			b = A[j];
			A[j] = A[n-1];//将最后一位的数字放入下标为j的位置(也就是空出来的那个位置,相当于空出来,)
			x = B[i];
			y = B[j];
			B[j] = B[n-1];//与上面同理
			
			A[i] = a + b;//第一个空间保存运算的结果
			B[i] = '(' + x + '+' + y + ')';//将第一步运算的表达式放在字符串数组中
			f(n-1);
			
			//减法需要区分顺序
			A[i] = a - b;
			B[i] = '(' + x + '-' + y + ')';
			f(n-1);
			A[i] = b - a;
			B[i] = '(' + y + '-' + x + ')';
			f(n-1);
			
			//乘法
			A[i] = a * b;
			B[i] = '(' + x + '*' + y + ')';
			f(n-1);
			
			//除法和减法一样需区分顺序这里要处理除数为0的情况,因为计算过程中可能出现除数为0的情况
			if(b!=0) {
				A[i] = a / b;
				B[i] = '(' + x + '/' + y + ')';
				f(n-1);
			}
			if(a!=0) {
				A[i] = b / a;
				B[i] = '(' + y + '/' + x + ')';
				f(n-1);
			}	
			//当上面四则运算都不满足时
			//为了方便进入下一个for循环, 需要将之前的i和j上的值都重新找回 
			A[i] = a;
			A[j] = b;
			B[i] = x;
			B[j] = y;
		}
	}
}
public static void getnumber() {
	Random r = new Random();
	for(int i = 0;i < 4;i++) {
		A[i] = r.nextInt(13) + 1;//产生1-13之间的数
	}
	for(int i = 0;i < 4;i++) {
		if(A[i] == 1)
			B[i] = "A";
		else if(A[i] == 11)
			B[i] = "J";
		else if(A[i] == 12)
			B[i] = "Q";
		else if(A[i] == 13)
			B[i] = "K";
		else
			B[i] = String.valueOf(A[i]);
	}
	System.out.println("产生的随机牌为以下四张:");
	for(int i = 0;i < 4;i++) {
		System.out.println(B[i]);
	}
}
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
        getnumber();//得到随机数
        f(n);       //调用函数求解
        System.out.println("共有"+count+"种解法");
	}

}

结果截图:
在这里插入图片描述
总结:
(1)真的意识到了递归的强大,我开始想到的是穷举,但是代码太冗杂了,尝试着在网上找到递归方法学习一下,然后就看不懂,最后在本子上带入算了一番,才算模糊有点感觉了,果然还是太笨了吗?哈哈
(2)虽然笨了点,但是还是对递归加深了一点理解!
(3)在调试途中收获了一点知识!写了另一篇博客
字符加数字会产生什么(有点low)

提高(将24点游戏真的做成一个简单游戏):

思路:

利用栈来判断用户输入的表达式是否等于24
计时功能用多线程实现(不完善:新线程一直运行会到第二题的开始,没有解决,期待大佬的指点)
求值:
使用中缀表达式求值的,所以括号必须平衡并且表达式完全括号化(太low了)
什么是完全括号化?比如:
4+4+10+6
这个表达式需要写成:
(((4+4)+6)+10)
也就是3对括号必须有。。。
Java源码:

package zy;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
public class Yx extends Thread{
static int HP = 3;//用户初始生命值
static int CORE = 0;//用户初始成绩
static boolean t = true;
public void run() {
	if(t=true) {
		int time = 0;
		while(++time<=6){
			try{
				Thread.sleep(1000);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
		HP = HP - 1;
		System.out.println("时间到!当前你的生命值为:"+HP+" "+"得分为:"+CORE);
		t = false;
	}
	else
		return;
}
	//用来取出栈中的俩个元素进行计算的函数
	public static void evaluateStackTops(Stack<Integer> numbers,Stack<Character> operations) {
		int operand1,operand2;
		if(numbers.size()<2||operations.isEmpty()) {
			System.out.println("表达式错误!");
			return;
		}
		operand2 = numbers.pop();   //先取出来的数给与右操作数,因为计算除法和减法的时候是用更下一层的数做被除数和被减数的
		operand1 = numbers.pop();
		switch(operations.pop()) {
		case '+':
			numbers.push(operand1+operand2);
			break;
		case '-':
			numbers.push(operand1-operand2);
			break;
		case '*':
			numbers.push(operand1*operand2);
			break;
		case '/':
			numbers.push(operand1/operand2);
			break;
		default:
			System.out.println("表达式错误!");
			return;
		}
	}
	
	//实现计算功能,参数必须是一个完全括号化的表达式,所以用到了括号的平衡判断
	public static int evaluate(String expression) {
		Stack<Integer> numbers = new Stack<Integer>();
		Stack<Character> operations = new Stack<Character>();
		//将表达式转化为一个Scanner 类对象好操作
		//字符串next中存放表达式下一个字段,比如数值或运算符
		Scanner input = new Scanner(expression);
		char next;
		while(input.hasNext()) { //当字符串有下一个字符时
			if(input.hasNextInt()) {//如果下一个是数字压栈
				numbers.push((input.nextInt()));
			}
			else {
				next = input.next().charAt(0);
				switch(next) {
				case '+'://加法
				case '-'://
				case '*'://
				case '/'://
					operations.push(next);
					break;
				case ')':
					evaluateStackTops(numbers,operations);//计算
					break;
				case '(':
					break;
				default://其他字符
					System.out.println("表达式错误!");
					return 0;
				}
			}		
		}
		input.close();
		if(numbers.size()!=1){
			System.out.println("表达式错误!");
			return 0;
		}
		return numbers.pop();   //栈中最后一个元素就是表达式的值
	}
	
	public static void game(){
		if(HP==0) {//终止条件
			writer();
			System.out.println("游戏结束!");
			return;
		}
		Scanner in = new Scanner(System.in);
		Random r = new Random();
		String s = null;
		int[] a = new int[4];   //存放随机数
		for(int i = 0;i<a.length;i++)
			a[i] = r.nextInt(13)+1;  //随机产生1-13个数
		System.out.println("你获得的随机数是:");
		for(int i:a)
			System.out.println(i);
		System.out.println("请动用你的聪明才智在60秒内将它组成一个表达式且值为24!(表达式需要完全括号化)");
		System.out.println("友情提示:每个字符之间请用空格隔开,否则会出错");
        Yx t = new Yx();
        t.start();
		s = in.next();
		if(evaluate(s)==24) {
			System.out.println("可以呀答对了,+10分");
			CORE = CORE + 10;
			System.out.println("当前你的生命值为:"+HP+"  "+"得分为:"+CORE);
		}
		else {
				System.out.println("答案错误,-10分");
				CORE = CORE - 10;
				HP = HP - 1;
				System.out.println("当前你的生命值为:"+HP+"  "+"得分为:"+CORE);
		}
	}
	public static void writer() {
		File f = new File("TopList.txt");
		try {
			FileWriter out = new FileWriter(f);
			String s = Integer.toString(CORE);
			out.write(s);
			out.close();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}	
	}

	public static  void reader() {
		File f = new File("TopList.txt");
		if(!f.exists()) {
			System.out.println("请先参与游戏,否则没有成绩!");
			return;
		}
		try {
			FileReader in = new FileReader(f);
			char[] r = new char[1024];
			int len = in.read(r);
			String s = new String(r,0,len);
			System.out.println("你的成绩为:"+s);
			in.close();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}	
	}
	public static void menu() {
		System.out.println("**********************");
		System.out.println("1.开始游戏\n2.查看成绩");
		Scanner in = new Scanner(System.in);
		int t = in.nextInt();
		switch(t) {
		case 1:
			while(HP>0) {
				game();
			}
			writer();
            System.exit(0);
			break;
		case 2:
			reader();
			break;	
	}
		in.close();
	}
	public static void main(String[] args){
		menu();
	}
}
		

总结:
(1)了解到了Java中的栈的用法以及其封装的方法–>pop()出栈,peek()读取栈顶元素但不出栈,push()压栈
(2)了解了多线程的基础用法,认识到了多线程的“恐怖”,如果不好好处理,它会一直运行。
(3)了解了文件的读写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值