思考游戏王决斗链接中抽卡概率问题

我比较喜欢玩游戏王决斗链接这个游戏,但作为一名程序员有时也会思考游戏中的功能是如何实现的,因为也想成为一名游戏服务端工程师,这篇文章分享本人对其中用宝石抽卡抽到卡片类型的概率探讨与模拟实现
在这里插入图片描述

这个游戏抽到的卡类型有四种,超凡卡,稀有卡,珍贵卡,普通卡,我们让这四种类型的卡片抽到的概率加起来为100%,各为多少当然由策划配置了,开发直接读取配置表就好。既然加起来为100%,那么就用1~100的整数分别代表各种卡片类型的概率的范围,例如:抽到超凡卡的概率为3%,那么概率范围就是:1~3;抽到稀有卡的概率为5%,那么概率范围就是:4~8;抽到珍贵卡的概率为20%,那么概率范围就是:9~28;抽到普通卡的概率为72%,那么概率范围就是:29~100;每抽一张卡的时候就随机产生一个1~100之间的整数,这个整数在哪个范围就是抽到哪种卡了

@Data
public class CardType {
    private String type; //卡牌类型
    private int probability;//抽卡概率
    private int min;//概率范围最小值
    private int max;//概率范围最大值

    public CardType(String type, int probability) {
        this.type = type;
        this.probability = probability;
    }
}

游戏本身有趣的就是随机性,但是有时为了留住用户也会人为随机,比如:有的玩家运气好的时候有可能抽10次卡就能抽到好几张超凡卡,有的玩家运气不好连抽100次都抽不到超凡那么游戏就可能流失这个玩家了,因此可以人为的干扰概率:例如,1:设置一个超凡卡的概率保底次数,若玩家连续抽卡没有抽到超凡卡的次数累计达到此保底次数,则系统强制玩家获得,之后保底次数重置;2:设置抽卡n次里获得超凡卡的最大次数,比如抽100次卡,但设置超凡卡的保底次数为10,用户则可获得10张超凡卡,感觉用户赚了,若规定抽100次最多获得5张超凡卡,即可不受保底次数的影响了。个人认为规则1一般针对一次抽卡次数较少的用户,规则2一般是针对那些比较土豪的;不管怎样我们做成灵活的方法即可,以下为自己所想的模拟实现:

/**
 * 模拟实现游戏王决斗链接中的抽卡概率问题
 */
public class RateRandomNumber {

    //使用LinkedHashMap原因,确保概率最小的排在第一(逻辑需要)
    public static Map<String,CardType> cardTypes = new LinkedHashMap<>();

    /**
    * @description: 初始化数据
    * @return:
    * @author: Ming
    * @time: 2022/6/9
    */
    static {
        cardTypes.put("超凡",new CardType("超凡",3));
        cardTypes.put("稀有",new CardType("稀有",5));
        cardTypes.put("珍贵",new CardType("珍贵",20));
        cardTypes.put("普通",new CardType("普通",72));
        setCardProbabilityRang();
    }


    /**
    * @description: 根据概率设置概率范围
     * 说明:
     * 抽卡就是随机生成1到100之间的整数,因为各种卡类型抽到的概率加起来一共是100%,这里就以1~100的数字表示各种卡类型的概率范围,
     * 例如:超凡卡概率%3,则概率范围为1~3,珍贵卡概率%5,则概率范围为4~8,以此类推,最后随机生成的整数在哪个范围就是抽到哪种类型的卡
    * @return:
    * @author: Ming
    * @time: 2022/6/9
    */
    public static void setCardProbabilityRang(){
        int preMax = 0;//前一个元素概率范围数值最大值
        for (Map.Entry<String,CardType> m: cardTypes.entrySet()){
            CardType cardType = m.getValue();
            int max = cardType.getProbability()+preMax;//当前卡概率范围数值最大值就是:当前卡的概率+前一个元素概率范围数值最大值
            cardType.setMax(max);
            cardType.setMin(preMax+1);//当前卡概率范围数值最小值就是:前一个元素概率范围数值最大值+1
            preMax = max;
        }
    }


    /**
    * @description: 抽卡
    * @param aGuaranteed 超凡保底次数,若连续n-1次没有抽到超凡,则第n次强制获得
     * @param aGetMax 参数times次最多只能抽到多少张超凡卡(限制运气较好的用户)
     * @param times 用户抽卡次数
    * @return:
    * @author: Ming
    * @time: 2022/6/9
    */
    private static void drawCard(int aGuaranteed, int aGetMax, int times){
        Random random = new Random();
        CardType a = cardTypes.get("超凡");
        CardType b = cardTypes.get("稀有");
        CardType c = cardTypes.get("珍贵");
        int aGetTimes = 0;
        int bGetTimes = 0;
        int cGetTimes = 0;
        int dGetTimes = 0;
        int notTimes = 0; //没有抽中超凡的累计次数
        //开始抽卡
        for (int i = 0; i < times; i++) {
            //随机生成1到100之间的整数,因为各种卡的概率加起来一共是100%,这里就以1~100的数字表示各种卡类型的概率范围,
            //例如:超凡概率%3,则概率范围为1~3,珍贵卡概率%5,则概率范围为4~8,以此类推
            int num = random.nextInt(100)+1;
            if(notTimes == aGuaranteed && aGetTimes < aGetMax){
                System.out.println("系统强制发放超凡卡");
                aGetTimes++;
                notTimes = 0;//重置
            }else {
                notTimes++;
                if(num <= a.getMax() && aGetTimes < aGetMax){
                    System.out.println("抽中超凡卡");
                    aGetTimes++;
                    notTimes = 0;
                }else if(num <= b.getMax()){
                    System.out.println("抽中稀有卡");
                    bGetTimes++;
                }else if(num <= c.getMax()){
                    System.out.println("抽中珍贵卡");
                    cGetTimes++;
                }else{
                    System.out.println("抽中普通卡");
                    dGetTimes++;
                }
            }
        }
        System.out.println("本次抽到超凡卡数量:"+aGetTimes);
        System.out.println("本次抽到稀有卡数量:"+bGetTimes);
        System.out.println("本次抽到珍贵卡数量:"+cGetTimes);
        System.out.println("本次抽到普通卡数量:"+dGetTimes);
    }


    public static void main(String[] args) {
        drawCard(20,3,100);
    }

}



测试结果
在这里插入图片描述

以上就是简单实现,实际开发中,一些基数都是服务器启动时读取配置,数据预先加载到内存的,例如:卡类型的概率,还有卡组等,比如抽到超凡卡,系统就随机从内存分配一张超凡卡id给用户。实际网易实现的概率算法要复杂得多,这里只是作为自己问题的思考,探讨,实现;有错希望大家多多指正

主要电子书格式:ePub(包括ePub3的主要功能),PDF,Kindle azw3(mobipocket),fb2(.zip)。其他受支持的格式:漫画书(CBR / CBZ),RTF,doc(MS Word),html,纯文本文本。 升级到此流行的电子书阅读器的高级版。 此高级版本提供的功能: * Google / Yandex翻译集成 *对PDF和漫画格式的内置支持 *缩略图库视图 为了帮助您阅读外语,请使用FBReader的词典集成来查找单词或短语。您可以从多种外部词典中进行选择。 在FBReader Premium中,您可以使用集成的Google或Yandex转换器翻译句子而无需离开应用程序。(警告:此功能的日常使用可能受到限制。) FBReader支持与基于Google Drive™的云服务FBReader图书网络(https://books.fbreader.org/)同步您的图书馆和/或阅读位置。默认情况下禁用同步;要启用和配置它,请使用首选项对话框。 FBReader快速且高度可自定义–它可以使用外部TrueType / OpenType字体和自定义背景,可以在阅读时调整屏幕亮度(沿屏幕左边缘向上/向下滑动手指),并且可以选择不同的昼/夜配色方案。 该阅读器还包括一个浏览器/下载器,用于访问不同的网络电子书目录和商店。包括几个流行的英语,法语,俄语,中文和波兰语库。还支持自定义OPDS目录。 另外,您可以手动下载书籍,然后将其保存在设备上的/ sdcard / Books中。 此外,该阅读器已针对34种语言进行了本地化,并包括24种语言的连字符模式。该应用程序是开源(GPL)。 什么是新的 2.7.2: *修复了“返回”项目的行为(在“后退”按钮菜单中) *修复了Android 4.0 / 4.1上的首选项崩溃 *修复了“支持的文件格式”首选项 2.7.1: *每本书有多个文件 *文件更改通知 *解决了阅读进度问题 *轻松访问SD卡上的书籍 * Android 6:FBReader从外部应用程序打开ePub / PDF文件(尚不支持fb2) *不再错误的“丢失书籍”通知 *末尾的“推文您所读内容”链接书本 *用于PDF和漫画的Autocrop选项
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值