Browse Source

根据权重随机

toby 1 year ago
parent
commit
2893c348d7

+ 23 - 4
logic/equip-logic/src/main/java/com/iohao/mmo/equip/service/EquipEntryTemplateService.java

@@ -23,6 +23,8 @@ import com.iohao.mmo.common.provide.item.ItemTypeIdConst;
 import com.iohao.mmo.equip.entity.*;
 import com.iohao.mmo.equip.enums.PropertyNameEnum;
 import lombok.AllArgsConstructor;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
 import org.springframework.data.mongodb.core.MongoTemplate;
 import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.Query;
@@ -136,10 +138,27 @@ public class EquipEntryTemplateService {
      * @return
      */
     public List<EquipEntry> randomEquipBatch(int level,String position,int count){
-//        List<EquipEntry> equipEntryList = itemTypeIdList.stream()
-//                .map(itemTypeId -> randomEquip(itemTypeId,userId))
-//                .toList();
-//        return equipEntryList;
+        // 创建条件对象
+        Criteria criteria = new Criteria();
+
+        criteria.and("levelMin").gte(level);
+        criteria.and("levelMax").gte(level);
+        criteria.and("positionList").is(position);
+
+        Query query = new Query();
+        query.addCriteria(criteria);
+
+//        // 总记录数
+//        long total = mongoTemplate.count(query, EquipEntryTemplate.class);
+//        //查询返回指定字段 (自定义列表)
+//        query.fields().include("name", "code");
+//        // 分页
+//        query.with(PageRequest.of(bo.getPageNum() - 1, bo.getPageSize(),
+//        // 排序
+//        Sort.by(Sort.Order.desc("code"))));
+
+        List<EquipEntryTemplate> equipEntryList = mongoTemplate.find(query,EquipEntryTemplate.class);
+
         return null;
     }
 

+ 160 - 0
logic/equip-logic/src/main/java/com/iohao/mmo/equip/service/MathRandom.java

@@ -0,0 +1,160 @@
+package com.iohao.mmo.equip.service;
+
+/**
+ * @author 唐斌
+ * @date 2023-08-31
+ * @description:
+ */
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * JAVA 返回随机数,并根据概率、比率
+ *
+ */
+public class MathRandom {
+
+    private static Log logger = LogFactory.getLog(MathRandom.class);
+
+    /**
+     * Math.random()产生一个double型的随机数,判断一下 每个奖品出现的概率
+     *
+     * @return int
+     *
+     */
+    public int PercentageRandom(List<RewardPrize> prizes) {
+        DecimalFormat df = new DecimalFormat("######0.00");
+        int random = -2;
+        try{
+            double sumWeight = 0;
+            //计算总权重
+            for(RewardPrize rp_1 : prizes){
+                sumWeight += rp_1.getPrize_weight();
+            }
+            double randomNumber;
+            randomNumber = Math.random();
+//            System.out.println("randomNumber是:" + randomNumber);
+            double d1 = 0;
+            double d2 = 0;
+
+            for(int i=0;i<prizes.size();i++){
+                d2 += Double.parseDouble(String.valueOf(prizes.get(i).getPrize_weight()))/sumWeight;
+                if(i==0){
+                    d1 = 0;
+                }else{
+                    d1 +=Double.parseDouble(String.valueOf(prizes.get(i-1).getPrize_weight()))/sumWeight;
+                }
+                if(randomNumber >= d1 && randomNumber <= d2){
+                    random = i;
+//                    System.out.println("d1是:" + d1);
+//                    System.out.println("d2是:" + d2);
+                    break;
+                }
+            }
+        }catch(Exception e){
+            System.out.println(e.getMessage());
+            logger.error("生成抽奖随机数出错,出错原因:" + e.getMessage());
+            random = -1;
+        }
+        return random;
+    }
+
+    /**
+     * 测试主程序
+     *
+     * @param agrs
+     */
+    public static void main(String[] agrs) {
+        int i = 0;
+        MathRandom a = new MathRandom();
+        List<RewardPrize> prizes = new ArrayList();
+        prizes.add(new RewardPrize(10000,"一等奖",1,5));
+        prizes.add(new RewardPrize(10001,"二等奖",1,10));
+        prizes.add(new RewardPrize(10002,"四等奖",1,30));
+        prizes.add(new RewardPrize(10003,"三等奖",1,20));
+        prizes.add(new RewardPrize(10004,"安慰奖",1,35));
+//        for(int m=0;m<100;m++){
+//            RewardPrize rp = new RewardPrize();
+//            rp.setPrize_amount(10);//每个奖品数量设置10个
+//            rp.setPrize_weight(1);//每个奖品的权重都设置成1,也就是每个奖品被抽到的概率相同(可根据情况自行设置权重)
+//            prizes.add(rp);
+//        }
+        int num1Count = 0;
+        int num2Count = 0;
+        int num3Count = 0;
+        int num4Count = 0;
+        int num5Count = 0;
+        for (i = 0; i <= 1000000; i++)// 打印100个测试概率的准确性
+        {
+//            System.out.println(a.PercentageRandom(prizes));
+            int index = a.PercentageRandom(prizes);
+            if(index==0){
+                num1Count++;
+            }else if(index==1){
+                num2Count++;
+            }else if(index==2){
+                num3Count++;
+            }else if(index==3){
+                num4Count++;
+            }else if(index==4){
+                num5Count++;
+            }
+        }
+        System.out.println(num1Count+"---"+num2Count+"---"+num3Count+"---"+num4Count+"---"+num5Count);
+
+    }
+    public static class RewardPrize  {
+        private int rewardId;//奖励id
+        private String rewardName;//奖励名称
+        private int prize_amount;//数量
+        private int prize_weight;//权重
+
+        public int getRewardId() {
+            return rewardId;
+        }
+
+        public void setRewardId(int rewardId) {
+            this.rewardId = rewardId;
+        }
+
+        public String getRewardName() {
+            return rewardName;
+        }
+
+        public void setRewardName(String rewardName) {
+            this.rewardName = rewardName;
+        }
+
+        public int getPrize_amount() {
+            return prize_amount;
+        }
+
+        public void setPrize_amount(int prize_amount) {
+            this.prize_amount = prize_amount;
+        }
+
+        public int getPrize_weight() {
+            return prize_weight;
+        }
+
+        public void setPrize_weight(int prize_weight) {
+            this.prize_weight = prize_weight;
+        }
+
+        public RewardPrize() {
+        }
+
+        public RewardPrize(int rewardId, String rewardName, int prize_amount, int prize_weight) {
+            this.rewardId = rewardId;
+            this.rewardName = rewardName;
+            this.prize_amount = prize_amount;
+            this.prize_weight = prize_weight;
+        }
+    }
+}
+

+ 170 - 0
logic/equip-logic/src/main/java/com/iohao/mmo/equip/service/WeightRandomTemplate.java

@@ -0,0 +1,170 @@
+package com.iohao.mmo.equip.service;
+
+/**
+ * @author 唐斌
+ * @date 2023-08-31
+ * @description:
+ */
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * @author:linxu
+ * @Date:2020-7-24 00:09:54
+ */
+public class WeightRandomTemplate {
+
+    public static void main(String[] args) {
+        List<DefaultWeightWrap> rewardWraps = new ArrayList<>();
+        rewardWraps.add(new RewardWrap(12881, "一等奖", 1, 1, 5));
+        rewardWraps.add(new RewardWrap(12882, "二等奖", 1, 2, 10));
+        rewardWraps.add(new RewardWrap(12883, "三等奖", 1, 3, 25));
+        //默认奖励,如果抽不到奖,默认抽中安慰奖【参与奖】
+        RewardWrap rewardWrap = new RewardWrap(12884, "安慰奖", 1, 4, 60);
+        rewardWraps.add(rewardWrap);
+
+        WeightRandom<DefaultWeightWrap> weightRandom = new WeightRandom<>(rewardWraps);
+        int num1Count = 0;
+        int num2Count = 0;
+        int num3Count = 0;
+        int num4Count = 0;
+        //模拟抽奖二十次【第一种方式调用】
+        for (int i = 0; i < 1000000; i++) {
+            RewardWrap rewardWrapRandom = (RewardWrap) weightRandom.randomWeightWrap();
+            if(rewardWrapRandom.rank==1){
+                num1Count++;
+            }else if(rewardWrapRandom.rank==2){
+                num2Count++;
+            }else if(rewardWrapRandom.rank==3){
+                num3Count++;
+            }else if(rewardWrapRandom.rank==4){
+                num4Count++;
+            }
+        }
+        System.out.println(num1Count+"---"+num2Count+"---"+num3Count+"---"+num4Count);
+        int num11Count = 0;
+        int num12Count = 0;
+        int num13Count = 0;
+        int num14Count = 0;
+        //模拟抽奖二十次【第二种方式调用】
+        for (int i = 0; i < 1000000; i++) {
+            RewardWrap rewardWrapRandom = (RewardWrap) weightRandom(new IWeightRandom<DefaultWeightWrap>() {
+                @Override
+                public List<DefaultWeightWrap> applyWraps() {
+                    return rewardWraps;
+                }
+                @Override
+                public DefaultWeightWrap applyDefaultWrap() {
+                    return rewardWrap;
+                }
+            });
+            if(rewardWrapRandom.rank==1){
+                num11Count++;
+            }else if(rewardWrapRandom.rank==2){
+                num12Count++;
+            }else if(rewardWrapRandom.rank==3){
+                num13Count++;
+            }else if(rewardWrapRandom.rank==4){
+                num14Count++;
+            }
+//            System.out.println(rewardWrapRandom.toString());
+        }
+        System.out.println(num11Count+"----"+num12Count+"----"+num13Count+"----"+num14Count);
+
+    }
+
+    //测试实现类
+    public static class RewardWrap extends DefaultWeightWrap {
+        private int rewardId;//奖励id
+        private String rewardName;//奖励名称
+        private int rewardValue;//数量
+        private int rank;//奖励排名1等奖,2等奖
+        public RewardWrap(int rewardId, String rewardName, int rewardValue, int rank, int weight) {
+            this.rewardName = rewardName;
+            this.rewardValue = rewardValue;
+            this.rewardId = rewardId;
+            this.rank = rank;
+            this.weight = weight;
+        }
+        public int getRewardId() {
+            return rewardId;
+        }
+        public void setRewardId(int rewardId) {
+            this.rewardId = rewardId;
+        }
+        public int getRank() {
+            return rank;
+        }
+        public void setRank(int rank) {
+            this.rank = rank;
+        }
+        @Override
+        public String toString() {
+            return "Reward{" +
+                    "rewardId=" + rewardId +
+                    ", rewardName='" + rewardName + '\'' +
+                    ", rewardValue=" + rewardValue +
+                    ", rank=" + rank +
+                    '}';
+        }
+    }
+
+    /**
+     * 方式1【创建对象调用的方式】
+     *
+     * @param <T>
+     */
+    public static class WeightRandom<T extends DefaultWeightWrap> {
+        private List<T> content;//目标集合数据
+
+        public WeightRandom(List<T> content) {
+            this.content = content;
+        }
+
+        public T randomWeightWrap() {
+            int s = content.stream().mapToInt(DefaultWeightWrap::getWeight).sum();
+            int r = ThreadLocalRandom.current().nextInt(s);
+            Optional<T> o = content.stream().filter(t -> {
+                int result = r - t.getWeight();
+                return result < 0;
+            }).findFirst();
+            return o.orElse(null);
+        }
+    }
+    /**
+     * 方式2【静态方法,内部实现接口方式的调用】
+     *
+     * @param iWeightRandom
+     * @param <T>
+     * @return
+     */
+    public static <T extends DefaultWeightWrap> T weightRandom(IWeightRandom<T> iWeightRandom) {
+        int s = iWeightRandom.applyWraps().stream().mapToInt(DefaultWeightWrap::getWeight).sum();
+        int r = ThreadLocalRandom.current().nextInt(s);
+        Optional<T> o = iWeightRandom.applyWraps().stream().filter(t -> { int result = r - t.getWeight();return result < 0; }).findFirst();
+        return o.orElse(iWeightRandom.applyDefaultWrap());
+    }
+    public interface IWeightRandom<T extends WeightRandomTemplate.DefaultWeightWrap> {
+        List<T> applyWraps();//目标集合数据
+
+        T applyDefaultWrap();//默认返回值【参与奖励】
+    }
+
+    //权重包装基类
+    public static abstract class DefaultWeightWrap {
+        public int weight;//权重
+
+        public int getWeight() {
+            return weight;
+        }
+
+        @Override
+        public String toString() {
+            return "DefaultWeightWrap{" +
+                    "weight=" + weight +
+                    '}';
+        }
+    }
+}

+ 172 - 0
logic/equip-logic/src/main/java/com/iohao/mmo/equip/service/WeightRandomTemplate2.java

@@ -0,0 +1,172 @@
+package com.iohao.mmo.equip.service;
+
+/**
+ * @author 唐斌
+ * @date 2023-08-31
+ * @description:
+ */
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * @author:linxu
+ * @Date:2020-7-24 00:09:54
+ */
+public class WeightRandomTemplate2 {
+
+    public static void main(String[] args) {
+        List<DefaultWeightWrap> rewardWraps = new ArrayList<>();
+        rewardWraps.add(new RewardWrap(12881, "一等奖", 1, 1, 5));
+        rewardWraps.add(new RewardWrap(12882, "二等奖", 1, 2, 10));
+        rewardWraps.add(new RewardWrap(12883, "三等奖", 1, 3, 25));
+        //默认奖励,如果抽不到奖,默认抽中安慰奖【参与奖】
+        RewardWrap rewardWrap = new RewardWrap(12884, "安慰奖", 1, 4, 60);
+        rewardWraps.add(rewardWrap);
+
+        WeightRandom<DefaultWeightWrap> weightRandom = new WeightRandom<>(rewardWraps, rewardWrap);
+        int num1Count = 0;
+        int num2Count = 0;
+        int num3Count = 0;
+        int num4Count = 0;
+        //模拟抽奖二十次【第一种方式调用】
+        for (int i = 0; i < 1000000; i++) {
+            RewardWrap rewardWrapRandom = (RewardWrap) weightRandom.randomWeightWrap();
+            if(rewardWrapRandom.rank==1){
+                num1Count++;
+            }else if(rewardWrapRandom.rank==2){
+                num2Count++;
+            }else if(rewardWrapRandom.rank==3){
+                num3Count++;
+            }else if(rewardWrapRandom.rank==4){
+                num4Count++;
+            }
+        }
+        System.out.println(num1Count+"---"+num2Count+"---"+num3Count+"---"+num4Count);
+        int num11Count = 0;
+        int num12Count = 0;
+        int num13Count = 0;
+        int num14Count = 0;
+        //模拟抽奖二十次【第二种方式调用】
+        for (int i = 0; i < 1000000; i++) {
+            RewardWrap rewardWrapRandom = (RewardWrap) weightRandom(new IWeightRandom<DefaultWeightWrap>() {
+                @Override
+                public List<DefaultWeightWrap> applyWraps() {
+                    return rewardWraps;
+                }
+                @Override
+                public DefaultWeightWrap applyDefaultWrap() {
+                    return rewardWrap;
+                }
+            });
+            if(rewardWrapRandom.rank==1){
+                num11Count++;
+            }else if(rewardWrapRandom.rank==2){
+                num12Count++;
+            }else if(rewardWrapRandom.rank==3){
+                num13Count++;
+            }else if(rewardWrapRandom.rank==4){
+                num14Count++;
+            }
+//            System.out.println(rewardWrapRandom.toString());
+        }
+        System.out.println(num11Count+"----"+num12Count+"----"+num13Count+"----"+num14Count);
+
+    }
+
+    //测试实现类
+    public static class RewardWrap extends DefaultWeightWrap {
+        private int rewardId;//奖励id
+        private String rewardName;//奖励名称
+        private int rewardValue;//数量
+        private int rank;//奖励排名1等奖,2等奖
+        public RewardWrap(int rewardId, String rewardName, int rewardValue, int rank, int weight) {
+            this.rewardName = rewardName;
+            this.rewardValue = rewardValue;
+            this.rewardId = rewardId;
+            this.rank = rank;
+            this.weight = weight;
+        }
+        public int getRewardId() {
+            return rewardId;
+        }
+        public void setRewardId(int rewardId) {
+            this.rewardId = rewardId;
+        }
+        public int getRank() {
+            return rank;
+        }
+        public void setRank(int rank) {
+            this.rank = rank;
+        }
+        @Override
+        public String toString() {
+            return "Reward{" +
+                    "rewardId=" + rewardId +
+                    ", rewardName='" + rewardName + '\'' +
+                    ", rewardValue=" + rewardValue +
+                    ", rank=" + rank +
+                    '}';
+        }
+    }
+
+    /**
+     * 方式1【创建对象调用的方式】
+     *
+     * @param <T>
+     */
+    public static class WeightRandom<T extends DefaultWeightWrap> {
+        private List<T> content;//目标集合数据
+        private T defaultResult;//默认返回值【参与奖励】
+
+        public WeightRandom(List<T> content, T defaultResult) {
+            this.content = content;
+            this.defaultResult = defaultResult;
+        }
+
+        public T randomWeightWrap() {
+            int s = content.stream().mapToInt(DefaultWeightWrap::getWeight).sum();
+            int r = ThreadLocalRandom.current().nextInt(s);
+            Optional<T> o = content.stream().filter(t -> {
+                int result = r - t.getWeight();
+                return result < 0;
+            }).findFirst();
+            return o.orElse(defaultResult);
+        }
+    }
+    /**
+     * 方式2【静态方法,内部实现接口方式的调用】
+     *
+     * @param iWeightRandom
+     * @param <T>
+     * @return
+     */
+    public static <T extends DefaultWeightWrap> T weightRandom(IWeightRandom<T> iWeightRandom) {
+        int s = iWeightRandom.applyWraps().stream().mapToInt(DefaultWeightWrap::getWeight).sum();
+        int r = ThreadLocalRandom.current().nextInt(s);
+        Optional<T> o = iWeightRandom.applyWraps().stream().filter(t -> { int result = r - t.getWeight();return result < 0; }).findFirst();
+        return o.orElse(iWeightRandom.applyDefaultWrap());
+    }
+    public interface IWeightRandom<T extends WeightRandomTemplate2.DefaultWeightWrap> {
+        List<T> applyWraps();//目标集合数据
+
+        T applyDefaultWrap();//默认返回值【参与奖励】
+    }
+
+    //权重包装基类
+    public static abstract class DefaultWeightWrap {
+        public int weight;//权重
+
+        public int getWeight() {
+            return weight;
+        }
+
+        @Override
+        public String toString() {
+            return "DefaultWeightWrap{" +
+                    "weight=" + weight +
+                    '}';
+        }
+    }
+}

+ 2 - 2
logic/excel-logic/src/main/java/com/iohao/mmo/excel/controller/EquipExcelController.java

@@ -48,13 +48,13 @@ public class EquipExcelController {
     }
 
     /**
-     * 导入数据自定义处理示例
+     * 导入
      * @param file
      * @return
      * @throws Exception
      */
     @PostMapping(value = "importExcel", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
-    @Operation(summary = "导入数据自定义处理示例",description = "导入数据自定义处理示例")
+    @Operation(summary = "导入",description = "导入")
     public Result importExcel(@RequestPart("file") @Parameter(description = "文件")MultipartFile file) throws Exception {
         //自定义读取
         EasyExcel.read(file.getInputStream(), EquipEntryTemplateExcelDTO.class, new EquipEntryTemplateExcelListener<>(equipEntryTemplateExcelService,2)).sheet(0).doRead();

+ 10 - 3
logic/excel-logic/src/main/java/com/iohao/mmo/excel/listener/EquipEntryTemplateExcelListener.java

@@ -18,6 +18,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -62,14 +63,20 @@ public class EquipEntryTemplateExcelListener<E, T> extends AnalysisEventListener
     public void invoke(T data, AnalysisContext context) {
         LOGGER.info("解析到一条数据:{}", JSONObject.toJSONString(data));
         EquipEntryTemplateExcelDTO excel = ConvertKit.sourceToTarget(data, EquipEntryTemplateExcelDTO.class);
+        // 这里对数据做自定义设置,如果一级类字段不为空,则一级类取本条数据新导入的,反之取缓存里面的
         if(StringUtils.isNotBlank(excel.getCode())){
-            // 这里对数据做自定义设置
+            //拷贝一级类属性
             nowEquipEntryTemplate = ConvertKit.sourceToTarget(excel, EquipEntryTemplate.class);
-
+            //一级类自定义属性
+            if(StringUtils.isNotBlank(excel.getPositionStrs())) {
+                nowEquipEntryTemplate.setPositionList(Arrays.stream(excel.getPositionStrs().split("-")).toList());
+            }
+            //将一级类加入缓存list
             equipEntryTemplateList.add(nowEquipEntryTemplate);
         }
-
+        //拷贝二级类属性
         EquipEntryProperty equipEntryProperty = ConvertKit.sourceToTarget(excel, EquipEntryProperty.class);
+        //把二级类放入一级类的子列表中
         List<EquipEntryProperty> lastPropertyList = nowEquipEntryTemplate.getEntryPropertyList();
         if(lastPropertyList==null){
             lastPropertyList = new ArrayList<>();

+ 3 - 0
logic/excel-logic/src/main/java/com/iohao/mmo/excel/service/impl/EquipEntryTemplateExcelServiceImpl.java

@@ -48,6 +48,9 @@ public class EquipEntryTemplateExcelServiceImpl extends BaseServiceImpl<EquipEnt
             //如果userId是主键,必须使用setOnInsert()
             update.set("name",data.getName());
             update.set("description",data.getDescription());
+            update.set("hitProb",data.getHitProb());
+            update.set("positionList",data.getPositionList());
+            update.set("maxExist",data.getMaxExist());
             update.set("entryPropertyList",data.getEntryPropertyList());
 
             Pair<Query, Update> updatePair = Pair.of(query, update);