24点游戏

  • 前言
  • 1、 算法分析
    •  1 .1 接收玩家结果输入与结果判定。
    •  1.2 工具类TimeUtils、CardUtils。
    •  1.3 数据生成与结果计算。
  • 2、 概要设计
    • 2.1 结构设计
    • 2.2 算法流程
  • 3、 测试
  • 4、 调试
  • 总结

前言

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

1、 算法分析

 1 .1 接收玩家结果输入与结果判定。

将玩家的输入保存到一个string变量中,与计算机自动产生的数据进行匹配,如果结果包含则认为用户答对,将用户积分递增1,如果输入为空或null或者不匹配则认为玩家答案错误,将玩家血量递减1。

 1.2 工具类TimeUtils、CardUtils。

TimeUtils负责整个游戏的定时计算,是一个后台线程,可以调用主线程中的数据进行分析,看是否达到退出游戏的条件,如果满足则直接进行调用主线程的退出方法,进行线程的关闭并结束进程。否则查看当前的时间计数单位是否超时,如果超时,则调用主线程的outTime()方法进行玩家血量的递减,否则继续进行游戏数据的监听更新。
CardUtils有两个字典映射num2card、card2num,负责转换牌面 1-K 对应的数字,方便游戏的计算

 1.3 数据生成与结果计算。

由generateNumbers()方法对数据进行生成,先生成 1-13 的4个数字再将数字转换为对应的牌面对用户进行展示,如果当前的4个数不能满足24点的规律则会从新生成,直到至少有一个答案为止。
calculateResult()方法对生成的4个随机数进行穷举所有可能,并计算相应的结果,如果满足24点规律则将当前的排列进行保存,否则舍弃掉。运算规则是先从4个数中抽取两个数进行四则运算,再将结果和剩下的数据进行合并再次计算,直到只有一个数据为止,防止出现数据重合的现象,采取不回头的方式进行,从左到右开始数据的选取,如果已经有了数据的组合,则后面的运算就不在进行。结果生成之后进行清洗,去除多余的括号,并检查相似的结构将其提出。

2、 概要设计

2.1 结构设计

App类,为算法的入口类

包含10个成员变量(random、faceContent、trueResult、blood、score、playingInfo、flag、timer、timeUtils)分别负责随机数的生成,牌面结果保存,玩家输入结果保存,计算结果保存,玩家的血量和积分,玩家游戏中产生的数据信息,及3个定时器相关变量;
19个成员方法(startGame()、savePlayingInfo()、generateNumbers()、outTime()、calculateResult()、clearn()、calcute()、saveResult)()。。。)分别用于程序的入口,游戏的管理,数据生成,结果计算,游戏数据的本地保存,玩家交互,及各个变量所需的getter、setter方法。
package com.beordie;import com.beordie.utils.CardUtils;
import com.beordie.utils.TimeUtils;import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.*;/*** @Classname App* @Description 游戏实现主类* @Date 2021/5/8 22:30* @Created 30500*/
public class App {// 随机生成器private static Random random = new Random();// 牌面保存private static List<String> faceContent = new ArrayList<>();// 存储用户输入的运算表达式private static String buffer;// 存储正确结果private static List<String> trueResult = new ArrayList<>();// 玩家血量 积分private static int blood = 3;private static int score = 0;// 保存玩家的数据信息private static List<String> playingInfo = new ArrayList<>();// 定时器private static Integer flag = 0;private static Timer timer = new Timer();private static TimeUtils timeUtils = new TimeUtils();/*** @description 入口函数* @author 30500* @date 2021/5/9 9:47* @type [java.lang.String[]]* @return void*/public static void main(String[] args) {// 开始游戏startGame();}/*** @description 游戏控制器* @author 30500* @date 2021/5/9 12:37* @type []* @return void*/public static void startGame() {while (blood > 0) {// 生成随机数generateNumbers();// 定时器初始化if (flag == 0) {timer.schedule(timeUtils, 0 , 1000);flag = 1;}// 玩家输入input();// 检查玩家输入是否正确if (checkInput()) {System.out.println("答对了,加一分");playingInfo.add(buffer + "  正确;");score++;} else {System.out.println("答错了,血量减一");playingInfo.add(buffer + "  错误;");blood--;}timeUtils.setTime(15);}// 取消定时器任务timer.cancel();exit();}/*** @description 追加添加玩家的游戏信息*              一行表示一个玩家记录* @author 30500* @date 2021/5/9 13:03* @type []* @return void*/public static void savePlayingInfo() {try{BufferedWriter br = new BufferedWriter(new FileWriter("src/TopList.txt", true));       //数据保存在本地for(int i = 0;i< playingInfo.size();i++){br.write(playingInfo.get(i)+"\t");}br.write("\n");br.close();}catch(Exception e){e.printStackTrace();}finally {// 游戏结束直接释放所有任务System.exit(0);}}/*** @description 生成四个代表牌面的随机数* @author 30500* @date 2021/5/8 22:51* @type []* @return void*/public static void generateNumbers() {faceContent.clear();// 保存随机数临时变量int[] num = new int[4];// 生成四个随机数for (int i = 0; i < 4; i++) {// 生成 1-13 的随机数num[i] = random.nextInt(13) + 1;// 将随机数对应的牌面保存faceContent.add((String) CardUtils.num2card.get(num[i]));}// 输出结果给用户calculateResult(num[0], num[1], num[2], num[3]);// 判断当前牌面是否可解if (trueResult.size() > 0) {print();saveResult();return;}// 不可解重新递归生成generateNumbers();}/*** @description 输出牌面结果给用户* @author 30500* @date 2021/5/8 23:06* @type []* @return void*/public static void print() {System.out.println("扑克牌牌面为");for (String key : faceContent) {System.out.printf("%-8s", key);}System.out.println();}/*** @description 接收用户输入* @author 30500* @date 2021/5/8 23:06* @type []* @return void*/public static void input() {// 输入设备句柄Scanner input = new Scanner(System.in);// 接收用户输入System.out.println("请输入:");buffer = input.nextLine();}/*** @description 游戏超时更新数据* @author 30500* @date 2021/5/9 12:40* @type []* @return void*/public static void outTime() {blood--;playingInfo.add("******" + "  超时;");System.out.println("游戏超时,血量减一");}/*** @description 计算可能性结果*              采取不回头的方法进行,每个数据从头到尾,一次展开,不回头计算* @author 30500* @date 2021/5/9 12:41* @type [int, int, int, int]* @return void*/public static void calculateResult(int num1, int num2, int num3, int num4) {// 表示四个牌面StringBuffer face1 = new StringBuffer(CardUtils.num2card.get(num1));StringBuffer face2 = new StringBuffer(CardUtils.num2card.get(num2));StringBuffer face3 = new StringBuffer(CardUtils.num2card.get(num3));StringBuffer face4 = new StringBuffer(CardUtils.num2card.get(num4));int resultNum = 0;for (int i = 0; i < 4; i++) {// 取出运算符char operator1 = CardUtils.arithmetic[i];// 第1次计算,先从4个数中任意选择2个进行计算,将计算结果再次参加运算// 先选第一,和第二个数进行计算int firstResult = calcute(num1, num2, operator1);// 先选第二和第三两个数进行计算int secondResult = calcute(num2, num3, operator1);// 先选第三和第四俩个数进行计算int thirdResult = calcute(num3, num4, operator1);for (int j = 0; j < 4; j++) {// 取出运算符char operator2 = CardUtils.arithmetic[j];// 第2次计算,从3个数中选择2个进行计算int firstMidResult = calcute(firstResult, num3, operator2);int firstTailResult = calcute(num3, num4, operator2);int midFirstResult = calcute(num1, secondResult, operator2);int midTailResult = calcute(secondResult, num4, operator2);int tailMidResult = calcute(num2, thirdResult, operator2);for (int k = 0; k < 4; k++) {// 取出运算符char operator3 = CardUtils.arithmetic[k];//第3次计算,计算两个数的结果if(calcute(firstMidResult, num4, operator3) == 24)trueResult.add("((" + face1 + operator1 + face2 + ")" + operator2 + face3 + ")" + operator3 + face4);if(calcute(firstResult, firstTailResult, operator3) == 24)trueResult.add("(" + face1 + operator1 + face2 + ")" + operator3 + "(" + face3 + operator2 + face4 + ")");if(calcute(midFirstResult, num4, operator3) == 24)trueResult.add("(" + face1 + operator2 + "(" + face2 + operator1 + face3 + "))" + operator3 + face4);if(calcute(num1,midTailResult, operator3) == 24)trueResult.add("" + face1 + operator3 + "((" + face2 + operator1 + face3 + ")" + operator2 + face4 + ")");if(calcute(num1,tailMidResult,operator3) == 24)trueResult.add("" + face1 + operator3 + "(" + face2 + operator2 + "(" + face3 + operator1 + face4 + "))");}}}// 进行数据清洗clearn();}/*** @description 清洗多余的数据结果* @author 30500* @date 2021/5/9 12:43* @type []* @return void*/private static void clearn() {List<String> tempResult = new ArrayList<>();String temp = null;// 清除数据结构中多余的()符号for (int i = 0; i < trueResult.size(); i++) {temp = trueResult.get(i);if ((temp.indexOf('-') == -1 && temp.indexOf('+') == -1) || (temp.indexOf('*') == -1 && temp.indexOf('/') == -1)) {temp = temp.replaceAll("[()]", "");}if (tempResult.indexOf(temp) == -1) {tempResult.add(temp);}}trueResult.clear();trueResult = tempResult;}/*** @description 判断用户输入是否正确* @author 30500* @date 2021/5/9 9:03* @type []* @return boolean*/public static boolean checkInput() {// 检查数据是否合理if (buffer == null) {return false;}// 判断是否是正确答案if (trueResult.indexOf(buffer.trim()) == -1) {return false;}return true;}/*** @description 两个数之间的四则运算* @author 30500* @date 2021/5/9 9:46* @type [int, int, char]* @return int*/public static int calcute(int count1, int count2, char operator) {// 加if (operator == '+') {return count1 + count2;}// 减else if (operator == '-') {return count1 - count2;}// 乘else if (operator == '*') {return count1 * count2;}// 除else if (operator == '/' && count2 != 0)  {return count1 / count2;}return -1;}/*** @description 保存当前牌面的正确结果* @author 30500* @date 2021/5/9 12:43* @type []* @return void*/public static void saveResult() {try{BufferedWriter br = new BufferedWriter(new FileWriter("src/result.txt"));       //数据保存在本地for(int i = 0;i< trueResult.size();i++){br.write(trueResult.get(i)+"\n");}br.close();}catch(Exception e){e.printStackTrace();}}public static void exit() {System.out.println("游戏结束,玩家得分:" + score);savePlayingInfo();}public static int getBlood() {return blood;}public static void setBlood(int blood) {App.blood = blood;}public static int getScore() {return score;}public static void setScore(int score) {App.score = score;}public static Integer getFlag() {return flag;}public static void setFlag(Integer flag) {App.flag = flag;}
}
CardUtils类是游戏的工具类,负责数字与牌面点数的转换,主要有三个静态成员变量num2card、card2num保存数据间的映射关系,arithmetic负责存储游戏中需要使用的(+、-、*、/)四则运算,通过下标即可访问相应的运算符,提供一个私有构造方法不允许外部进行对象的实例化,所有变量通过类名直接进行数据的引用。
package com.beordie.utils;import java.util.HashMap;
import java.util.Map;/*** @Classname Cards* @Description 实现扑克牌点数的类* @Date 2021/5/8 22:32* @Created 30500*/
public class CardUtils {// 存储 A-K 13张牌面public static Map<Integer, String> num2card = new HashMap<>();// 存储 1-13 13个牌面点public static Map<String, Integer> card2num = new HashMap<>();// 四则运算表达式public static char[] arithmetic;static {arithmetic = new char[]{'+', '-', '*', '/'};num2card.put(1, "A");num2card.put(2, "2");num2card.put(3, "3");num2card.put(4, "4");num2card.put(5, "5");num2card.put(6, "6");num2card.put(7, "7");num2card.put(8, "8");num2card.put(9, "9");num2card.put(10, "10");num2card.put(11, "J");num2card.put(12, "Q");num2card.put(13, "K");card2num.put("A", 1);card2num.put("2", 2);card2num.put("3", 3);card2num.put("4", 4);card2num.put("5", 5);card2num.put("6", 6);card2num.put("7", 7);card2num.put("8", 8);card2num.put("9", 9);card2num.put("10", 10);card2num.put("11", 11);card2num.put("12", 12);card2num.put("13", 13);}/*** @description 构造方法私有,不允许外部进行类的实例化* @author 30500* @date 2021/5/8 22:38* @type []* @return*/private CardUtils() {};
}
TimeUtils类是游戏的计数线程,继承TimerTask类,作为App类的一个成员变量使用,包含一个成员变量用于设定游戏的规则时间,run()方法实现计数的功能并进行游戏的时间检查,每次调用该后台线程时将时间计数减一,当其小于等于0时,认为当前游戏时间已经结束,玩家的生命递减一但是不影响玩家的继续答题,当然如果玩家的生命已经低于1时将控制全部交给主线程进行管理,退出当前的游戏并保存相关的游戏信息和打印相关的游戏数据。
package com.beordie.utils;import com.beordie.App;import java.util.TimerTask;/*** @Classname TimeUtils* @Description 定时器计算时间* @Date 2021/5/9 10:04* @Created 30500*/
public class TimeUtils extends TimerTask {// 游戏时长 15sprivate Integer time;// 结束标记private Boolean exit;@Overridepublic void run() {// 每隔一秒时间减一this.time--;if (this.time <= 0) {// 调用超时方法App.outTime();if (App.getBlood() > 0) {this.time = 15;} else {System.out.println("游戏结束");cancel();App.exit();}}}public TimeUtils() {this.time = 15;this.exit = false;}@Overridepublic boolean cancel() {return super.cancel();}public void setExit(Boolean exit) {this.exit = exit;}public void setTime(Integer time) {this.time = time;}
}

2.2 算法流程

流程图


3、 测试

针对算法的回答超时、回答错误、回答正确三个交互功能进行测试

超时输入 错误输入 正确输入

4、 调试

定时器跟踪 数据跟踪

总结

  最大的难点是对结果的计算,采取暴力穷举的办法对所有可能性进行一次计算,从中取出结果正确的排列组合,也有的数字组合去掉相应的括号之后是重复的也需要进行数据的筛除检查。通过对定时器的使用来达到整个算法的计时功能,增加了对多线程工作的理解。

24点游戏---java编写相关推荐

  1. 24点游戏 java实现_java实现24点纸牌游戏

    本文题目为大家分享了java实现24点纸牌游戏的具体代码,供大家参考,具体内容如下 题目 24点游戏是经典的纸牌益智游戏. 常见游戏规则: 从扑克中每次取出4张牌.使用加减乘除,第一个能得出24者为赢 ...

  2. 24点游戏java代码 中国开源社区_编程之美 1.16 24点游戏

    24点游戏大家都知道:4张牌,可以进行+ - * / 四种运算,可以使用括号,每个牌用一次,任意组合构造表达式使结果为24. 扩展问题:n个整数,四种运算,可使用括号,每个数字使用一次,使表达式结果为 ...

  3. 24点游戏java代码 中国开源社区_编程实现一个有GUI的24点游戏

    24点是指从去除大小王后的52张扑克牌中任取 4 张,通过「加.减.乘.除」四则运算得到 24.是一个历史悠久的趣味小游戏. <数据化管理>书中在测试数据敏感度章节提到一个细节" ...

  4. java编写2048小游戏

    java版2048小游戏 java编写2048小游戏 java编写2048小游戏 // An highlighted block /*** */ package games;/*** @author ...

  5. Java黑皮书课后题第3章:**3.24(游戏:抽牌)编写程序,模拟从一副52张的牌中抽一张牌,程序应显示牌的大小、花色

    **3.24(游戏:抽牌)编写程序,模拟从一副52张的牌中抽一张牌,程序应显示牌的大小.花色 题目 题目概述 运行示例 破题 代码 题目 题目概述 **3.24(游戏:抽牌)编写程序,模拟从一副52张 ...

  6. 24点游戏java_使用java编写计算24点游戏程序

    初学java,编写了一个计算24点的程序,时间有限,有些粗糙,不过可以使用. //-------------Cal24.java--------------- //计算24点程序 //作者:徒步天下( ...

  7. 【项目展示】一个有点难度的猜数字小游戏(Java编写)

    (声明:本文部分图片来自网络,如有侵权请联系,将第一时间删除或更换图片) 本文目录 1.前言 2.规格说明 3.源代码 4.运行结果 5.感想 1.前言 我在自己的博客里上传了一些本科时编过.最近又改 ...

  8. Java编写的五子棋小游戏

    看书的时候看到一个不完整的Java编写的一个五子棋小游戏,为了恢复一下编程能力刚刚把这个小程序完成了. 实现的功能很简单,两人对下五子棋,程序自动回判断输赢.在ubuntu下搞得,没有装什么高端的输入 ...

  9. main java game,playgame 一个JAVA编写的飞行小游戏,有基本完整的 框架,适合初学者参照学习 Other s 其他 238万源代码下载- www.pudn.com...

    文件名称: playgame下载 收藏√  [ 5  4  3  2  1 ] 开发工具: Java 文件大小: 7050 KB 上传时间: 2013-06-06 下载次数: 3 提 供 者: Lyq ...

最新文章

  1. 【OpenCV 4开发详解】多通道分离与合并
  2. oracle sql判断相等,Oracle PL/SQL判断两个字段相等或不等问题
  3. 使用nodejs实现OData的batch操作在Marketing Cloud里读取contact信息
  4. 手机知识:NFC是什么,有什么用?看完你就明白了!
  5. 黑科技轮胎:有能发电的,脑洞简直不要太大...
  6. 微博air客户端_打磨近十年,接近「完美」的 macOS 第三方微博客户端:Maipo
  7. 数值传热学陶文铨pdf_西安交大陶文铨当选“2019最美科技工作者”
  8. 小甲鱼python课后题简书_Python练习题100道
  9. 开发一个简单的WebPart
  10. linux双括号文本比较,Linux Shell 双括号运算符使用
  11. 转:git设置过滤忽略的文件或文件夹
  12. 【Java】Java文件读写
  13. banner设圆角_Banner设计技巧!
  14. IntelliJ IDEA常用快捷键
  15. android程序填空题,10道android填空题及答案
  16. CMake Error: The current CMakeCache.txt directory is different...
  17. 基于MATLAB的求解线性方程组(附完整代码和例题)
  18. mysql连接navicat premium 15的具体方法 附navicat的官网连接
  19. Python3 parse.urlencode() 与parse.unquote()
  20. SQLServer按照每小时、半小时分组

热门文章

  1. [Spring Boot] 2. Spring Boot 启动过程定制化
  2. ORACLE错误代码对照表
  3. Redis Cluster 添加/删除 完整折腾步骤
  4. 深圳大学计算机专硕和学硕的区别,2021深大考研:学硕专硕的区别
  5. opencv 二维码定位
  6. 第十四届蓝桥杯模拟赛(Python)
  7. ICV:预计到2026年,全球乘用车单车将平均配置3.8颗摄像头
  8. 个人发展分析:SWOT
  9. python自动转换excel格式
  10. 2021支付宝集五福最新最全攻略:万能福沾沾福敬业福