热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

java实现24点游戏

每次取出4张牌,使用加减乘除,第一个能得出24者为赢,这篇文章主要就为大家详细介绍了java实现24点游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

游戏规则

从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。

基本要求

  • 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式
  • 列出表达式无重复
  • 用户初始生命值为一给定值(比如3),初始分数为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。
  • 使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。
  • 所有成绩均可记录在TopList.txt文件中。

解表达式基本思路

采用穷举法列举每一种存在的可能,接着判断是否值为24,如果等于24,则将表达式存入Set集合,最终遍历Set集合即可得到所有表达式。具体思路如下:

1.采用随机数生成4个符合要求的数据,假设四个数据为n1,n2,n3,n4 。
2.把数据相互组合可以得到如下组合:n1和n2 ,n1和n3,n1和n4,n2和n3,n2和n4,n3和n4
3.将上面的组合进行各种可能的运算例如:n1+n2,n1-n2,n2-n1,n1*n2,n1/n2,n2/n1等等。
4.把上面组合计算出来的结果存入进对应的数组中例如:组合相加的结果存入add数组,相减的结果存入sub数组……最终将这些数组存入一个list集合中,目的是为了方便通过循环遍历出每一种组合。
5.通过循环去遍历每一种组合,把这些组合在一起进行相加,相减等运算,记录结果为24的表达式。在这里需要注意的是,因为数组得值为两个数字的运算结果,所以需要根据当前循环变量的值和list集合以及数组存入数据的顺序去把表达式格式化成四个数字组成的表达式,否则表达式只有两个数字。

  • 需要注意的是:在遍历集合的过程中,由于集合中存入的数组的数据为两个数据组合的形式,所以遍历是只需要控制好下标,使的每一个表达式中只有n1,n2,n3,n4这四个数据,而不会出现类似于n1,n2,n1,n3 这种组合的方式。
  • 具体的流程图入下图所示:

玩家运算基本思路

在java中使用Timer和Canender即可实现定时的功能,而判断表达式是否正确,在java中使用Script引擎调用eval方法即可判断表达式的值是否正确,具体思路如下:

1.初始化生命值,和分数
2.由系统给出四个数字
3.玩家给出答案
4.判断给出的答案中的数字和系统给出的数字是否吻合,如果吻合进入5,否则,生命值减一。
5.借助Timer类的schedule()判断是否超时,如果没有超时,进入6,否则,生命值减一。
6.借助script引擎的eval()方法可以判断表达式是否正确,如果正确,分数加一,否则,生命值减一。
当生命值大于0时执行2,3,4,5,6操做,否则将当前分数写入文件。

流程图如下图所示

编码

Game类,主要实现由系统随机生成数据,并计算可能的表达式

为了避免除零异常采用了float类型的数组进行存储

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.util.Set;

/**
 * 
 * Title: Test Description: 1. 采用随机数生成4个符合要求的数据,假设四个数据为n1,n2,n3,n4 。
 * 2.把数据相互组合可以得到如下组合:n1和n2 ,n1和n3,n1和n4,n2和n3,n2和n4。
 * 3.将上面的组合进行各种可能的运算例如:n1+n2,n1-n2,n2-n1,n1*n2,n1/n2,n2/n1等等。 
 * 4.把上面组合计算出来的结果存入进对应的数组中例如:组合相加的结果存入add数组,相减的结果存入sub数组……最终将这些数组存入一个list集合中,目的是为了方便通过循环遍历出每一种组合。
 * 5.通过循环去遍历每一种组合,把这些组合在一起进行相加,相减等运算,记录结果为24的表达式
 * @author jianglei
 */
public class Game {
 static Set set = new HashSet();// 使用Set存储算式表达式可以避免有重复的结果
 float[] data = new float[4];// 存放数据的集合
 float[] add = new float[6];// 存放组合相加的结果的集合
 float[] sub1 = new float[6];// 存放相减的结果(两个数相减的结果存在两种可能)
 float[] sub2 = new float[6];// 存放相减的结果
 float[] mul = new float[6];// 存放相乘
 float[] div1 = new float[6];// 存放相除(两个数相除的结果存在两种可能)
 float[] div2 = new float[6];// 存放相除
 List list = new ArrayList();// 存放组合结果运算的集合

 /**
 * 
 * Title: combine
 * 

* Description: 该方法用来获取每两个数字的组合组合, 用1代表第一个数字,2代表第二个数字....共有六种组合方式,分别如下: * 1和2,1和3,1和 4,2和 3,2和 4,3和 4 在上面的组合中,每一种组合都对应着 加减乘除 这四种运算 * 将上述的组合的每种计算结果存入上面声明的集合 */ public void conbine(float n1, float n2, float n3, float n4) { add[0] = n1 + n2; add[1] = n1 + n3; add[2] = n1 + n4; add[3] = n2 + n3; add[4] = n2 + n4; add[5] = n3 + n4; sub1[0] = n1 - n2; sub1[1] = n1 - n3; sub1[2] = n1 - n4; sub1[3] = n2 - n3; sub1[4] = n2 - n4; sub1[5] = n3 - n4; sub1[5] = n3 + n4; sub2[0] = n2 - n1; sub2[1] = n3 - n1; sub2[2] = n4 - n1; sub2[3] = n3 - n2; sub2[4] = n4 - n2; sub2[5] = n4 - n3; mul[0] = n2 * n1; mul[1] = n3 * n1; mul[2] = n4 * n1; mul[3] = n3 * n2; mul[4] = n4 * n2; mul[5] = n4 * n3; div1[0] = n1 / n2; div1[1] = n1 / n3; div1[2] = n1 / n4; div1[3] = n2 / n3; div1[4] = n2 / n4; div1[5] = n3 / n4; div2[0] = n2 / n1; div2[1] = n3 / n1; div2[2] = n4 / n1; div2[3] = n3 / n2; div2[4] = n4 / n2; div2[5] = n4 / n3; list.add(add);// 把各种组合加入到list集合中,方便通过循环来遍历每一种组合方式 list.add(sub1); list.add(sub2); list.add(mul); list.add(div1); list.add(div2); } public void getData() { Random r = new Random(); // 获取1——13的的数字的集合 data[0] = r.nextInt(12) + 1; data[1] = r.nextInt(12) + 1; data[2] = r.nextInt(12) + 1; data[3] = r.nextInt(12) + 1; System.out.print("四个数字为:"); for (float f : data) switch ((int) f) {// 将11,12,13,1变成J,Q,K,A case 1: System.out.print("A" + " "); break; case 11: System.out.print("J" + " "); break; case 12: System.out.print("O" + " "); break; case 13: System.out.print("K" + " "); break; default: System.out.print((int) f + " "); break; } System.out.println(); boolean flag = false;// 通过该变量去判断是否存在表达式 conbine(data[0], data[1], data[2], data[3]); for (int a = 0; a <3; a++) {// 有种组合方式,分别遍历每一种组合方法 for (int b = 0; b <6; b++) {// 穷举每一个组合和他们之间的运算 for (int c = 0; c <6; c++) {// 判断每一种组合的每一种运算结果是否等于24 if ((list.get(b)[a] + list.get(c)[5 - a]) == 24) { DataFormat.judge(a, b, c, data, "+", set); flag = true; } // 减法 if ((list.get(b)[a] - list.get(c)[5 - a]) == 24) { DataFormat.judge(a, b, c, data, "-", set); } if ((list.get(b)[5 - a] - list.get(c)[a]) == 24) { DataFormat.judge(a, b, c, data, "-", set); flag = true; } // 乘法 if ((list.get(b)[a] * list.get(c)[5 - a]) == 24) { DataFormat.judge(a, b, c, data, "*", set); flag = true; } // 除法 if ((list.get(b)[a] / list.get(c)[5 - a]) == 24) { DataFormat.judge(a, b, c, data, "/", set); flag = true; } if ((list.get(b)[5 - a] / list.get(c)[a]) == 24) { DataFormat.judge(a, b, c, data, "/", set); flag = true; } } } } if (!flag) System.out.println("没有表达式满足条件"); }

AutoGame类主要实现由系统给定数值,用户输入表达式来根据结过进行计分,并将分数写入文件

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class AutoGame {
 static boolean flag = true;//该变量标识是否超时
 static int life = 3;//初始化生命值
 static int score=0;//初始化分数

 /**
 *开始游戏的方法,该方法通过当前生命值判断是否结束 
 */
 public void start() throws IOException {
 Calendar date = Calendar.getInstance();//实例化Calendar对象
 while(life>0) {//当生命值大于0才会进行
 flag=true;//初始化分数标记
 date.setTime(new Date());
 date.add(Calendar.SECOND, 20);//设置限定时间
 Timer timer = new Timer();
 //当达到限定时间将会执行run()方法,即把全局变量flag变为false
 timer.schedule(new RemindTask(), date.getTime());
 int answer = answer();
 switch(answer) {
 case -1:
 System.out.println("表达式错误!! 当前生命值为"+life+" 分数为:"+score);
 break;
 case -2:
 System.out.println("输入超时!! 当前生命值为"+life+" 分数为:"+score);
 break;
 case -3:
 System.out.println("结果错误!! 当前生命值为"+life+" 分数为:"+score);
 break;
 case 1: 
 System.out.println("正确,得到1分奖励!! 当前生命值为"+life+" 分数为:"+score);
 break;
 }
 System.out.println("----------");
 }
 System.out.println("游戏结束……分数为: "+score);//循环结束也就是生命值为0,打印游戏结束
 saveScore(score);//将玩家当前分数存入文件
 return;
 }
/**
 * 
 * Title: getData

* Description:给定任意的数据 * @return */ private float[] getData() { float[] data = new float[4]; Random r = new Random();//随机生成四个数据存入数组中 data[0] = r.nextInt(12) + 1; data[1] = r.nextInt(12) + 1; data[2] = r.nextInt(12) + 1; data[3] = r.nextInt(12) + 1; System.out.print("四个数字为:"); for (float f : data) switch ((int) f) { case 1: System.out.print("A" + " "); break; case 11: System.out.print("J" + " "); break; case 12: System.out.print("O" + " "); break; case 13: System.out.print("K" + " "); break; default: System.out.print((int) f + " "); break; } System.out.println("请开始作答,时间20秒"); return data; } /** * * Title: answer

* Description:根据用户输入返回false或true * 1.输入不含给定值,返回FALSE * 2.输入超时,返回false * 3.输入表达式的值不为24,返回false * 否则,返回true * @return -1代表输入的表达式与系统给出的数字不吻合 * @return -2代表用户计算结果超时 * @return -3代表结果错误 * @return 1代表用户计算正确 */ public int answer() { Scanner sc = new Scanner(System.in); float[] data = getData();//获取给定的数据 //获取script引擎,调用eval()方法来判断表达式是否正确 ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn"); String exper = sc.next(); try { String res = String.valueOf(scriptEngine.eval(exper)); for (int i = 0; i * Description: 该方法表示将玩家当前分数存入TopList.txt文件 * @param score 需要存入的分数 * @throws IOException */ public static void saveScore(int score) throws IOException { FileOutputStream fos = new FileOutputStream("e:/TopList.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write((score+"").getBytes());//把分数写入文件 bos.close(); } public static void main(String[] args) throws IOException { saveScore(1); } } /** * * Title: RemindTask * Description:该TimerTask并且重写run()可以实现在指定的定时时间执行run方法的内容 * @author jianglei */ class RemindTask extends TimerTask { @Override public void run() { AutoGame.flag = false;//当超时会把全局变量flag变为false } }

DataFormat类根据a b c是三个循环变量将两个组合数字的运算格式化成四个数字的表达式

由于代码比较长,在这里只留一种情况的,其余的情况与它类似

import java.util.Set;
/**
 * 
* Title: GetFoamat
* Description: 该类通过在循环中的a b c的值判断出当前所参与运算的值与参加运算的符号,假设四个值为n0,n1,n2,n3
* 形参 a、b、c为循环变量,形参n数组为参与运算的四个数字,形参op表示当前进行的运算类型,形参set为存储结果的容器

 */
public class DataFormat {
 public static void judge(int a,int b,int c,float[]n,String op,Set set) {
 StringBuilder sb = new StringBuilder();
 if(a==0) {//n0和n1 与n2和n3之间的运算
 if(b==0) {//n0+n1
 if(c==0) {//n2+n3
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("+").append(n[3]).append(")").append("=24");
 }if(c==1) {//n2-n3
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("-").append(n[3]).append(")").append("=24");
 }if(c==2) {//n3-n2
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[3]).append("-").append(n[2]).append(")").append("=24");
 }if(c==3) {// n2*n3
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("*").append(n[3]).append(")").append("=24");
 }if(c==4) {// n2/n3
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("/").append(n[3]).append(")").append("=24");
 }if(c==5) {// n3/n2
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[3]).append("/").append(n[2]).append(")").append("=24");
 }
 //将运算表达式存入容器
 set.add(sb.toString());
 //将sb清空
 sb = new StringBuilder();
 }if(b==1) {//n0-n1
 //由于这种代码篇幅比较长,在这里省略了,思路和上面的一致
 }

测试

import java.io.IOException;
import java.util.Scanner;

public class Test {
 public static void main(String[] args) throws IOException {
 Scanner sc = new Scanner(System.in);
 Game t = new Game();
 System.out.println("----------");
 System.out.println("1.随机生成数判断");
 System.out.println("2.用户输入运算式");
 System.out.println("请选择");
 char op = sc.next().charAt(0);
 switch (op) {
 case '1':
 t.getData();
 for (String str : t.set) {
 System.out.println(str.replaceAll(".0", ""));
 }
 break;
 case '2':
 AutoGame a = new AutoGame();
 a.start();
 break;
 default:
 System.out.println("输入错误");
 }
 }
}

运行结果

以下用户输入表达式的运行结果

测试过程中在该情况下的测试数据是由自己给出的为1 1 12 12这四个数字

分数存入文件

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 处理docker容器时间和宿主机时间不一致问题的方法
    本文介绍了处理docker容器时间和宿主机时间不一致问题的方法,包括复制主机的localtime到容器、处理报错情况以及重启容器的步骤。通过这些方法,可以解决docker容器时间和宿主机时间不一致的问题。 ... [详细]
  • 集合的遍历方式及其局限性
    本文介绍了Java中集合的遍历方式,重点介绍了for-each语句的用法和优势。同时指出了for-each语句无法引用数组或集合的索引的局限性。通过示例代码展示了for-each语句的使用方法,并提供了改写为for语句版本的方法。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • position属性absolute与relative的区别和用法详解
    本文详细解读了CSS中的position属性absolute和relative的区别和用法。通过解释绝对定位和相对定位的含义,以及配合TOP、RIGHT、BOTTOM、LEFT进行定位的方式,说明了它们的特性和能够实现的效果。同时指出了在网页居中时使用Absolute可能会出错的原因,即以浏览器左上角为原始点进行定位,不会随着分辨率的变化而变化位置。最后总结了一些使用这两个属性的技巧。 ... [详细]
  • 开发笔记:Docker 上安装启动 MySQL
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Docker上安装启动MySQL相关的知识,希望对你有一定的参考价值。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 本文介绍了Java的公式汇总及相关知识,包括定义变量的语法格式、类型转换公式、三元表达式、定义新的实例的格式、引用类型的方法以及数组静态初始化等内容。希望对读者有一定的参考价值。 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • 本文介绍了一种图片处理应用,通过固定容器来实现缩略图的功能。该方法可以实现等比例缩略、扩容填充和裁剪等操作。详细的实现步骤和代码示例在正文中给出。 ... [详细]
  • C++语言入门:数组的基本知识和应用领域
    本文介绍了C++语言的基本知识和应用领域,包括C++语言与Python语言的区别、C++语言的结构化特点、关键字和控制语句的使用、运算符的种类和表达式的灵活性、各种数据类型的运算以及指针概念的引入。同时,还探讨了C++语言在代码效率方面的优势和与汇编语言的比较。对于想要学习C++语言的初学者来说,本文提供了一个简洁而全面的入门指南。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 本文介绍了Python函数的定义与调用的方法,以及函数的作用,包括增强代码的可读性和重用性。文章详细解释了函数的定义与调用的语法和规则,以及函数的参数和返回值的用法。同时,还介绍了函数返回值的多种情况和多个值的返回方式。通过学习本文,读者可以更好地理解和使用Python函数,提高代码的可读性和重用性。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
author-avatar
平凡无琦世界
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有