JAVA二十四点

问题描述

24点游戏是经典的纸牌益智游戏。
常见游戏规则:
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
基本要求: 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式,用擅长的语言(C/C++/Java或其他均可)实现程序解决问题。
1.程序风格良好(使用自定义注释模板)
2.列出表达式无重复。
提高要求:用户初始生命值为一给定值(比如3),初始分数为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。
1. 程序风格良好(使用自定义注释模板)
2.使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。
3.所有成绩均可记录在TopList.txt文件中。

算法实现

2.1 基本要求设计思路
大体是思路上采用穷举法,即列举出四个数字的所有排列组合情况,以及所有运算符的排列组合情况。每种数字组合都默认优先级从第一位开始,相当与第一位和第二位现进行运算,其运算结果在于第三位进行运算,最后上面运算结果在与第四位进行运算。即满足((a#b)#c)#c。
利用二维数组operator[24][4]列举出24种数字的组合情况,利用for循环结构循环查找每一个数字组合中符合最后结果等于24的运算符组合方式。实现这一要求,需要利用利用四个for循环。
2.2 提高要求设计思路
提高要求大体思路是:用户根据随机生成的四个属列出中缀表达式,根据用户输入的中缀表达式(含括号)转化为后缀表达式。利用中缀表达式求出最终值的大小。判断最终值大小是否为24。
中缀表达式转化为后缀表达式是实践核心算法。利用栈堆实现这一功能。把输入的中缀表达式转成后缀表达式,利用正则表达式来处理数字,然后利用栈来得出结果。转化的思路如下:
(1)如果遇到操作数,直接输出,添加到后缀表达式之后;
(2)如果遇到运算符(+ - * /)且此时栈为空,将运算符入栈;
(3)如果遇到运算符(+ - * /)且此时栈为不为空,先弹出优先级高与或等于扫描到的运算符的运算符,弹出后的运算符写入后缀表达式之后,并将扫描得到运算符压入栈中;
(4)如果遇到括号(“(”)直接压入栈中;
(5)如果遇到括号(“)”)弹出最近一个左括号及其上面的所有运算符,并顺序地写入后缀表达式中。
最终将栈中的元素依次出栈,输出。
计时器的处理上,调用System.currentTimeMillis()获取当前的时间,定义两个变量starttime和endtime计算出输入表达式的值是否控制在1分钟内。

流程图

在这里插入图片描述在这里插入图片描述

源码

package game24;

import java.util.Random;

public class Game24 
{
	
	public float[] Generate4Num()//随机产生四个数,即为四个纸牌
	{
		Random ran =new Random();
		float[] num =new float[4];
		//依次产生这四个数
		for(int i = 0 ;i<num.length ;i++ )
		{
			int k =ran.nextInt(13)+1;
			num[i] = (float)(k);
		}
		return num;
	}
	
	public void print4Num(float num[]) //输出随机产生的四个数
	{
		System.out.print("随机产生的这四张牌为: ");
		for(int i = 0 ; i<num.length ;i++)
		{
			
			if(num[i]==1.0|num[i]==11.0|num[i]==12.0|num[i]==13.0)
			{
				switch((int)num[i])
				{
					case 1: System.out.print("A(1) ");break;
					case 11:System.out.print("J(11) ");break;
					case 12:System.out.print("Q(12) ");break;
					case 13:System.out.print("K(13) ");break;
					default:break;
				}
			}
			else
			{
				int k =(int) num[i];
				 System.out.print( k + " " );
			}
				
		}
		System.out.println();
	}
	
	//获取四个数字进行循环判断符合的表达式
	public String game24(float num[])
	{
		//将数组中四个值分别赋值给a\b\c\d
		float a = num[0];
		float b = num[1];
		float c = num[2];
		float d = num[3];
		//操作数数组,存放四个操作数(4个数的排列组合情况共有24种)
		float operator[][] = {{a,b,c,d},{a,b,d,c},{a,c,b,d},{a,c,d,b},{a,d,b,c},{a,d,c,b}
						     ,{b,a,c,d},{b,a,d,c},{b,c,a,d},{b,c,d,a},{b,d,a,c},{b,d,c,a}
						     ,{c,a,b,d},{c,a,b,b},{c,b,a,d},{c,b,d,a},{c,d,a,b},{c,d,b,a}
				             ,{d,a,b,c},{d,a,c,b},{d,b,a,c},{d,b,c,a},{d,c,a,b},{d,c,b,a}};
		
		//float operator[][] = new float[24][4];

		char []symbol= {'+','-','*','/'};//运算数组,存放四个运算符号即加减乘除
		
		//依次循环这24种数字情况
		for(int i = 0 ;i < 24 ; i++)
		{      //依次循环这所有运算符号可能的排列组合方式 ,共有4*4*4=64种
				for(int k1 = 0 ; k1 < 4 ;k1++)
				{
					for(int k2 = 0 ; k2 < 4 ;k2++)
					{
						for(int k3 = 0 ; k3 < 4 ; k3++)
						{
							//计算前两个数
							float m1 = fun(operator[i][0],operator[i][1],symbol[k1]);
							//计算前两个数的运算结果结果和第三个数
							float m2 = fun(m1,operator[i][2],symbol[k2]);
							//
							float m3 = fun(m2,operator[i][3],symbol[k3]);
							
							//如果最后运算结果为24的话,输出运算过程
							if(m3 == 24.0 )
							{
//								System.out.print(operator[i][0]+symbol[k1]+operator[i][1]+"="+m1+"  ");
//								System.out.print(m1+symbol[k2]+operator[i][2]+"="+m2+"  ");
//								System.out.print(m2+symbol[k3]+operator[i][3]+"="+m3+"  ");

								System.out.println("(("+operator[i][0]+symbol[k1]+operator[i][1]
										+")"+symbol[k2]+operator[i][2]+")"
										+symbol[k3]+operator[i][3]);
							}
						}
					}
				}
		}
		System.out.println("输出1完毕");
		return null;
	}

	//依据传来的参数执行相应的加减乘除运算
	public  float fun(float f, float g, char c) {
		// TODO 自动生成的方法存根
		switch(c)
		{
			case '+':return f+g; 
			case '-':return	f-g; 		
			case '*':return f*g;  
			case '/':return f/g; 
			default:break;
		}
		return 0;
	}
}

package game24;

import java.util.Scanner;

public class Test01 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Game24 game = new Game24();
		float[] num =new float[4];
		num=game.Generate4Num();
		game.print4Num(num);
		//float[] num = {11,2,3,4};
		game.game24(num);
		
		
	}

}

基本功能运行结果
在这里插入图片描述
在这里插入图片描述

package game24;
/**
 * 测试二
 * 完成提高要求:模拟游戏
 * 用户输入随机生成的含四个数字的中缀表达式,判断返回的表达式的值是否为24
 */
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import java.util.Scanner;
import java.util.Stack;

public class Test02 {
	
	public static float lifevalue = 3;  //初始化生命值为3.0
	public static float score = 0;      //初始化分数为0.0	
	
	public static void main(String[] args) {
		
		System.out.println("-------提高要求----------");
		boolean flag = true ; //中间变量,控制游戏进程

		float res = 0;      //表达式计算结果

		
		while(lifevalue>0) //生命值还存在
		{
			System.out.println("开始(1)还是退出(2)?");
			Scanner scan = new Scanner(System.in);
			int m = scan.nextInt();
			switch(m)
			{
				case 1:gameplay();break;  //游戏开始
				case 2:{                  //游戏中途退出
							System.out.println("当前生命值为"+lifevalue);
							System.out.println("当前分数为"+score);
							String s1 = "分数为"+Float.toString(score);
							try {
								filepreserve(s1);
							} catch (IOException e) {
								// TODO 自动生成的 catch 块
								e.printStackTrace();
							}
							return;
					   }
				default:break;
			}
			
		}
		//生命值为0,游戏结束
		System.out.println("Game over!");
		System.out.println("当前分数为"+score);
		//将结果输入文件中
		String s = "分数为"+Float.toString(score);
		
		try {
			filepreserve(s);
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		
	}
	
	private static void filepreserve(String s) throws IOException {
		// TODO 自动生成的方法存根
		byte[] bs =s.getBytes();//定义字节数组当作缓冲区
		FileOutputStream file = new FileOutputStream("TopList.txt",true);
		
		try {
			file.write(bs);
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		
		file.close();
	}

	public static void gameplay()
	{
		long starttime = 0; //开始时间
		long endtime = 0;   //结束时间
		long runtime;       //输入表达式时间
		//定义game对象,随机生成4个数字并输出
		Game24 game = new Game24();
		float[] num =new float[4];
		num=game.Generate4Num();
		game.print4Num(num);
		
		System.out.println("请输入表达式");
		//获取开始的时间
		starttime =System.currentTimeMillis();
		
		Scanner in=new Scanner(System.in);
		//定义midToBack类对象 计算中缀表达式转化为后缀表达式的值
		midToBack mtb=new midToBack();
		//返回计算后的值
		float result = mtb.calculate();
		//获取输入结束的时间
		endtime =System.currentTimeMillis();
		//获取输入的时间
		runtime = endtime - starttime;
	
		//判断是否超时输入
		
		if(runtime <1000*60 )
		{
			//没有超时输入,判断表达式值是否为24
			if(result==24.0)
			{
				System.out.println("回答正确!!!");
				score++;
				System.out.println("当前生命值为"+lifevalue);
				System.out.println("当前分数为"+score);
			}
			else 
			{
				System.out.println("回答错误!!!");
				lifevalue--;
				System.out.println("当前生命值为"+lifevalue);
				System.out.println("当前分数为"+score);
			}
		}
		else
		{
			System.out.println("输入超时");
			lifevalue--;
			System.out.println("当前生命值为"+lifevalue);
			System.out.println("当前分数为"+score);
		}
	}
}



package game24;
/**
 * 该类实现把输入的中缀表达式转成后缀表达式,利用正则表达式来处理数字,然后利用栈来得出结果
 * 思路:
 * (1)如果遇到操作数,直接输出,添加到后缀表达式之后;
(2)如果遇到运算符(+ - *  /)且此时栈为空,将运算符入栈;
(3)如果遇到运算符(+ - *  /)且此时栈为不为空,先弹出优先级高与或等于扫描到的运算符的运算符,弹出后的运算符写入后缀表达式之后,并将扫描得到运算符压入栈中;
(4)如果遇到括号(“(”)直接压入栈中;
(5)如果遇到括号(“)”)弹出最近一个左括号及其上面的所有运算符,并顺序地写入后缀表达式中。
 */
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class midToBack {
 
	public  float calculate() {
		// TODO Auto-generated method stub
		Scanner in=new Scanner(System.in);
		//获取输入的中缀表达式字符串
		String s=in.nextLine();
		//计算表达之结果值
		double res = 0; 
       
		try {
			//定义存放后缀表达式数字运算符值集合List容器
			List<Object> list = trans(s);
			//定义存放运算符的栈堆
			Stack<Double>  result = new Stack<Double>();
			//计算表达式的值
			res=f(list,result);
			System.out.println(res);
		} catch (Exception e) {
			// TODO Auto-generated catch block
		System.out.println("表达式不合法!");
		}
		//将计算后的值返回
		return (float) res;
	}
 
	//计算转化后的后缀表达式的值
	public  double f(List<Object> list, Stack<Double> result) {
		// TODO Auto-generated method stub
		Iterator it=list.iterator();
        while(it.hasNext()){
        	String m=it.next().toString();
        	if (m.equals("+")||m.equals("-")||m.equals("*")||m.equals("/")) {
        		double b=result.pop();
				
				double a=result.pop();
				double v=g(a,b,m);
				result.push(v);
			}else {
				result.push(Double.valueOf(m));
			}
        }
		return(result.pop());
	}
 
	public  double g(double a, double b, String m) {
		// TODO Auto-generated method stub
 
		double v=0;
        switch (m)
        {
        case "+":
            v=a+b;
            break;
        case "-":
            v=a-b;
            break;
        case "*":
            v=a*b;
            break;
        case "/":
            v=a/b;
            break;
        }
        return v;
    
	}
 
	public  List<Object> trans(String s) {
		// TODO Auto-generated method stub
		Stack<Character> op=new Stack<Character>();
		
		
		ArrayList<Object> list=new ArrayList<Object>();
		Pattern P=Pattern.compile("[0-9]+(\\.[0-9]+)?");   //正则表达式来处理带小数点的数字
        int i=0;
        
        while(i<s.length()){
        	char c=s.charAt(i);
        	if (c>='0'&&c<='9') {
				String s1=s.substring(i);
				Matcher m =P.matcher(s1);
				if (m.find()) {    //取匹配到的第一个数字
					s1=m.group();
					
					list.add(s1);
				}
				i=i+s1.length();
				continue;
			}else if (c=='(') {
				op.push(c);
			}else if (c==')') {
				char p=op.pop();
				while(p!='('){
					list.add(p);
					p=op.pop();
				}
			}else if (c=='+'||c=='-') {
				while(!op.isEmpty()&&(op.peek()=='+'||op.peek()=='-'||
						op.peek()=='*'||op.peek()=='/')){
					
					list.add(op.pop());
				}
				op.push(c);
			}else if (c=='*'||c=='/') {
				while(!op.isEmpty()&&(op.peek()=='*'||op.peek()=='/')){
					list.add(op.pop());
				}
				op.push(c);
			}
        	i++;
        }
		
		while(!op.isEmpty()){
			list.add(op.pop());
		}
		return list;
	}
 
}

在这里插入图片描述

实践心得

通过本次实践,有了以下的体会:
(1)列出所有的表达式采用穷举法,即列出24种数字的排列组合,64中符号的自由组合。虽然可以通过多个for循环实现这一功能,不过也出现了一些重复的表达式。
(2)实现提高要求上,利用栈完成中缀表达式转化为后缀表达式后求值的思路。该部分代码借鉴自网络。这部分是用Java中的集合栈堆的知识,这部分最近正好要开始学这部分,利用此次机会了解这部分的知识。
(3)了解了一些Java语法知识上的本质。关于时间上的出来一开始是像采用Date类,后来通过了解到了Date实质还是调用了System中system.currentTimeMill()方法进行时间的获取(从1970到目前时刻的毫秒数)有了这个基础,计算出用户输入的时间就迎刃而解了。
(4)借此借鉴的源码(中缀表达式转化为后缀表达式),以此为案例学习了集合List,Stack栈堆的方法操作。如:pop()出栈并返回元素值。

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
24点纸牌游戏是一个经典的数学游戏,要求通过组合四张纸牌的数字和运算符,使得结果等于24。如何使用Java实现这个游戏呢? 首先,我们需要生成一副扑克牌,包括52张牌,每张牌都有对应的点数。可以用一个数组来表示扑克牌,每个元素对应一张牌的点数。 然后,我们从这副扑克牌中任意抽取四张牌,并使用四则运算符(加、减、乘、除)来组合这四张牌的点数,目标是得到结果等于24。 为了实现这个过程,我们可以使用递归算法。可以通过一个递归函数来对所有可能的组合进行尝试。函数的输入参数是当前要计算的数字列表,以及已经得到的计算结果。函数的返回值是一个布尔值,表示是否找到了满足条件的组合。 具体的实现过程如下: 1. 定义一个递归函数,输入参数是当前要计算的数字列表,以及已经得到的计算结果。函数返回一个布尔值。 2. 在递归函数中,首先判断数字列表是否为空,如果为空,那么判断计算结果是否等于24,如果等于24,则返回True,否则返回False。 3. 如果数字列表不为空,我们可以选择其中一个数字进行组合运算。可以使用一个循环遍历数字列表中的所有数字。 4. 在循环中,我们可以将当前遍历到的数字从数字列表中移除,然后将它与已经得到的计算结果进行四则运算,并将结果加入数字列表中。 5. 然后,我们递归调用函数,传入新的数字列表和计算结果,判断是否找到了满足条件的组合。如果找到了,就返回True,表示已经找到了,可以结束递归。 6. 如果在循环中所有数字都尝试过了,都没有找到满足条件的组合,那么返回False,表示未找到满足条件的组合。 7. 在程序的入口处,我们可以调用递归函数,传入初始的数字列表和计算结果,判断是否找到了满足条件的组合。如果找到了,可以输出结果;如果没有找到,可以提示用户没有组合满足条件。 通过以上步骤,就可以使用Java实现24点纸牌游戏。可以通过调用递归函数进行计算和判断,来得到游戏的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值