基于java的博饼各种情况的概率

1.背景

作为一个在厦门工作的程序员,特别喜欢闽南的中秋博饼文化,但是年年博饼都与状元擦肩而过,特写此篇,计算博饼各种情况出现的概率,期待下一次可以抽到状元。
状元插金花

2.规则

科举常用名表达式备注
状元六杯红4 4 4 4 4 4
状元遍地锦1 1 1 1 1 1
状元六杯黑A A A A A AA∈{2,3,5,6}
状元五红4 4 4 4 4 _
状元五子登科A A A A A _A∈{1,2,3,5,6}
状元状元插金花4 4 4 4 1 1
状元四红4 4 4 4 _ _
榜眼对堂1 2 3 4 5 6
探花三红4 4 4 _ _ _
进士四进A A A A _ _A∈{1,2,3,5,6}
举人二举4 4 _ _ _ _
秀才一秀4 _ _ _ _ _
落榜落榜_ _ _ _ _ _

3.代码

1.科举枚举

package bobing;

public enum EnumKeJu {

    六杯红("状元", "六杯红", "444444"),
    遍地锦("状元", "遍地锦", "111111"),
    六杯黑("状元", "六杯黑", "AAAAAA"),
    五红("状元", "五红", "44444_"),
    五子登科("状元", "五子登科", "AAAAA_"),
    状元插金花("状元", "状元插金花", "444411"),
    四红("状元", "四红", "4444__"),
    对堂("榜眼", "对堂", "123456"),
    三红("探花", "三红", "444___"),
    四进("进士", "四进", "AAAA__"),
    二举("举人", "二举", "44____"),
    一秀("秀才", "一秀", "4_____"),
    落榜("落榜", "落榜", "______"),
    ;

    private final String parentName;
    private final String childName;
    private final String expression;

    EnumKeJu(String parentName, String childName, String expression) {
        this.parentName = parentName;
        this.childName = childName;
        this.expression = expression;
    }

    public String getParentName() {
        return parentName;
    }

    public String getChildName() {
        return childName;
    }

    public String getExpression() {
        return expression;
    }

    @Override
    public String toString() {
        return parentName + "-" + childName;
    }
}

2.骰子投掷类

package bobing;

import java.util.Random;

public class Roll {

    private final int[] times = new int[7];  // 下标代表点数值,代表出现次数,index=0不用
    private String sameIndex = ""; // 重复的点数
    private Integer sameTimes = 0; // 重复的次数
    private EnumKeJu enumKeJu; // 计算得到的科举

    public Roll() {
        // 随机骰子
        this.setTimes();
        this.setSameIndexAndTimes();
        this.setEnumKeJu();
    }

    public Roll(int[] dots) {
        // 传入骰子
        for (int dot : dots) {
            this.times[dot]++;
        }
        this.setSameIndexAndTimes();
        this.setEnumKeJu();
    }

    private void setTimes() {
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            int dot = random.nextInt(6) + 1;
            this.times[dot]++;
        }
    }

    private void setSameIndexAndTimes() {
        for (int i = 1; i < this.times.length; i++) {
            int time = this.times[i];
            if (time == 0 || time < sameTimes) {
                continue;
            }
            if (time == sameTimes) {
                if (sameIndex.equals("4")) {
                    continue;
                }
            } else {
                sameTimes = time;
            }
            sameIndex = String.valueOf(i);
            if (sameTimes >= 4) {
                return;
            }
        }
    }

    private void setEnumKeJu() {
        switch (sameTimes) {
            case 6:
                this.enumKeJu = getEnumKeJu6();
                break;
            case 5:
                this.enumKeJu = getEnumKeJu5();
                break;
            case 4:
                this.enumKeJu = getEnumKeJu4();
                break;
            case 3:
            case 2:
                this.enumKeJu = getEnumKeJu3AndEnumKeJu2();
                break;
            default:
                this.enumKeJu = getEnumKeJu1();
        }
    }

    private EnumKeJu getEnumKeJu1() {
        return EnumKeJu.对堂;
    }

    private EnumKeJu getEnumKeJu3AndEnumKeJu2() {
        if (times[4] == 3) {
            return EnumKeJu.三红;
        }
        if (times[4] == 2) {
            return EnumKeJu.二举;
        }
        if (times[4] == 1) {
            return EnumKeJu.一秀;
        }
        return EnumKeJu.落榜;
    }

    private EnumKeJu getEnumKeJu4() {
        if (sameIndex.equals("4")) {
            if (times[1] == 2) {
                return EnumKeJu.状元插金花;
            }
            return EnumKeJu.四红;
        }
        return EnumKeJu.四进;
    }

    private EnumKeJu getEnumKeJu5() {
        if (sameIndex.equals("4")) {
            return EnumKeJu.五红;
        }
        return EnumKeJu.五子登科;
    }

    private EnumKeJu getEnumKeJu6() {
        switch (sameIndex) {
            case "4":
                return EnumKeJu.六杯红;
            case "1":
                return EnumKeJu.遍地锦;
            default:
                return EnumKeJu.六杯黑;
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i< this.times.length; i++) {
            int time = this.times[i];
            for (int j = 0; j < time; j++) {
                sb.append(i);
            }
        }
        sb.append("\t奖励:");
        sb.append(enumKeJu);
        sb.append("\t相同点数:");
        sb.append(sameIndex);
        sb.append("\t相同次数:");
        sb.append(sameTimes);
        return sb.toString();
    }

    public EnumKeJu getEnumKeJu() {
        return enumKeJu;
    }
}

3.主方法

package bobing;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {

    private static final int TRY_TIMES = (int) Math.pow(6, 6);

    public static void main(String[] args) {
//        Map<EnumKeJu, List<Roll>> randomMap = getRandomMap();
//        printResult(randomMap);
        Map<EnumKeJu, List<Roll>> sequenceMap = getSequenceMap();
        printResult(sequenceMap);
   }

    // 随机投掷骰子
    public static Map<EnumKeJu, List<Roll>> getRandomMap() {
        Map<EnumKeJu, List<Roll>> map = new HashMap<>();
        for (int i = 0; i < TRY_TIMES; i++) {
            Roll roll = new Roll();
            List<Roll> rolls = map.computeIfAbsent(roll.getEnumKeJu(), k -> new ArrayList<>());
            rolls.add(roll);
        }
        return map;
    }

    // 列举所有骰子情况
    public static Map<EnumKeJu, List<Roll>> getSequenceMap() {
        Map<EnumKeJu, List<Roll>> map = new HashMap<>();
        int[] dots = new int[]{1, 1, 1, 1, 1, 1};
        while (dots[0] != -1) {
            Roll roll = new Roll(dots);
            List<Roll> rolls = map.computeIfAbsent(roll.getEnumKeJu(), k -> new ArrayList<>());
            rolls.add(roll);
            getNextDots(dots, 5);
        }
        return map;
    }

    public static void getNextDots(int[] dots, int index) {
        if (dots[index] != 6) {
            dots[index] += 1;
            return;
        }
        if (index != 0) {
            dots[index] = 1;
            getNextDots(dots, index - 1);
            return;
        }
        dots[index] = -1;
    }

    public static void printResult(Map<EnumKeJu, List<Roll>> map) {
        System.out.printf("%s\t%8s\t%8s\t%8s\t%8s\n", "科举", "常用名", "次数", "频率", "表达式");
        int zhuangYuanCount = 0;
        for (EnumKeJu enumKeJu : EnumKeJu.values()) {
            List<Roll> rolls = map.get(enumKeJu);
            int count = rolls != null ? rolls.size() : 0;
            double rate = count / (double) TRY_TIMES;
            System.out.printf("%s\t%8s\t%8s\t%8s\t%8s\n",
                    enumKeJu.getParentName(),
                    enumKeJu.getChildName(),
                    count,
                    String.format("%.5f", rate),
                    enumKeJu.getExpression());
            if ("状元".equals(enumKeJu.getParentName())) {
                zhuangYuanCount += count;
            }
        }
        System.out.printf("%-8s\t\t%8s\t%8s\n", "状元汇总",
                zhuangYuanCount, String.format("%.5f", zhuangYuanCount / (double) TRY_TIMES));
    }
}

4.计算结果

科举	     常用名	    次数	   频率	      表达式
状元	     六杯红	       1	 0.00002	  444444
状元	     遍地锦	       1	 0.00002	  111111
状元	     六杯黑	       4	 0.00009	  AAAAAA
状元	      五红	      30	 0.00064	  44444_
状元	    五子登科	     150	 0.00322	  AAAAA_
状元	   状元插金花	  15	 0.00032	  444411
状元	      四红	     360	 0.00772	  4444__
榜眼	      对堂	     720	 0.01543	  123456
探花	      三红	    2500	 0.05358	  444___
进士	      四进	    1875	 0.04019	  AAAA__
举人	      二举	    9300	 0.19933	  44____
秀才	      一秀	   17400	 0.37294	  4_____
落榜	      落榜	   14300	 0.30650	  ______
状元汇总    		         561	 0.01202
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值