24点游戏---java编写

Posted 易小顺

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了24点游戏---java编写相关的知识,希望对你有一定的参考价值。

前言

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负责存储游戏中需要使用的(+、-、*、/)四则运算,通过下标即可访问相应的运算符,提供一个私有构造方法不允许外部进行对象的实例化,所有变量通过类名直接进行数据的引用。
24点游戏(dfs)

python实现24点游戏(地球上最短的24点游戏代码?)

24点游戏

第四次作业--结对编程

基于Android的24点游戏设计app

「游戏引擎 浅入浅出」4.3 片段着色器