|
|
@@ -4,7 +4,6 @@ import com.izouma.nineth.domain.*;
|
|
|
import com.izouma.nineth.dto.CollectionDTO;
|
|
|
import com.izouma.nineth.dto.CreateBlindBox;
|
|
|
import com.izouma.nineth.dto.PageQuery;
|
|
|
-import com.izouma.nineth.dto.UserDTO;
|
|
|
import com.izouma.nineth.enums.CollectionType;
|
|
|
import com.izouma.nineth.exception.BusinessException;
|
|
|
import com.izouma.nineth.repo.*;
|
|
|
@@ -12,6 +11,8 @@ import com.izouma.nineth.utils.JpaUtils;
|
|
|
import com.izouma.nineth.utils.SecurityUtils;
|
|
|
import lombok.AllArgsConstructor;
|
|
|
import org.apache.commons.collections.MapUtils;
|
|
|
+import org.apache.commons.lang3.RandomUtils;
|
|
|
+import org.apache.commons.lang3.Range;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.data.domain.Page;
|
|
|
import org.springframework.data.domain.PageImpl;
|
|
|
@@ -21,15 +22,13 @@ import org.springframework.data.jpa.domain.Specification;
|
|
|
import org.springframework.scheduling.annotation.Scheduled;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
-import javax.persistence.criteria.CriteriaBuilder;
|
|
|
-import javax.persistence.criteria.CriteriaQuery;
|
|
|
import javax.persistence.criteria.Predicate;
|
|
|
-import javax.persistence.criteria.Root;
|
|
|
import javax.transaction.Transactional;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.util.ArrayList;
|
|
|
-import java.util.Arrays;
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@Service
|
|
|
@@ -193,4 +192,56 @@ public class CollectionService {
|
|
|
}
|
|
|
collectionRepo.saveAll(collections);
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ public BlindBoxItem draw(Long collectionId) {
|
|
|
+ List<BlindBoxItem> items = blindBoxItemRepo.findByBlindBoxId(collectionId);
|
|
|
+
|
|
|
+ Map<BlindBoxItem, Range<Integer>> randomRange = new HashMap<>();
|
|
|
+ int c = 0, sum = 0;
|
|
|
+ for (BlindBoxItem item : items) {
|
|
|
+ randomRange.put(item, Range.between(c, c + item.getStock()));
|
|
|
+ c += item.getStock();
|
|
|
+ sum += item.getStock();
|
|
|
+ }
|
|
|
+
|
|
|
+ int retry = 0;
|
|
|
+ BlindBoxItem winItem = null;
|
|
|
+ while (winItem == null) {
|
|
|
+ retry++;
|
|
|
+ int rand = RandomUtils.nextInt(0, sum + 1);
|
|
|
+ for (Map.Entry<BlindBoxItem, Range<Integer>> entry : randomRange.entrySet()) {
|
|
|
+ BlindBoxItem item = entry.getKey();
|
|
|
+ Range<Integer> range = entry.getValue();
|
|
|
+ if (rand >= range.getMinimum() && rand < range.getMaximum()) {
|
|
|
+ int total = items.stream().filter(i -> !i.isRare())
|
|
|
+ .mapToInt(BlindBoxItem::getTotal).sum();
|
|
|
+ int stock = items.stream().filter(i -> !i.isRare())
|
|
|
+ .mapToInt(BlindBoxItem::getStock).sum();
|
|
|
+ if (item.isRare()) {
|
|
|
+ double nRate = stock / (double) total;
|
|
|
+ double rRate = (item.getStock() - 1) / (double) item.getTotal();
|
|
|
+
|
|
|
+ if (Math.abs(nRate - rRate) < (1 / (double) item.getTotal()) || retry > 1 || rRate == 0) {
|
|
|
+ if (!(nRate > 0.1 && item.getStock() == 1)) {
|
|
|
+ winItem = item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ double nRate = (stock - 1) / (double) total;
|
|
|
+ double rRate = item.getStock() / (double) item.getTotal();
|
|
|
+
|
|
|
+ if (Math.abs(nRate - rRate) < 0.2 || retry > 1 || nRate == 0) {
|
|
|
+ winItem = item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (retry > 100 && winItem == null) {
|
|
|
+ throw new BusinessException("盲盒抽卡失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return winItem;
|
|
|
+ }
|
|
|
}
|