All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.neko233.toolchain.game.draw.WeightDrawCardBox Maven / Gradle / Ivy

package com.neko233.toolchain.game.draw;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * 权重抽卡盒子
 *
 * @param  抽取的卡
 */
public class WeightDrawCardBox implements Serializable, Cloneable {

    private final Map weightCardMap;
    private final int totalWeight;

    public WeightDrawCardBox(Map weightCardMap) {
        this(weightCardMap, weightCardMap.values().stream().mapToInt(i -> i).sum());
    }

    private WeightDrawCardBox(Map weightCardMap, int totalWeight) {
        this.weightCardMap = weightCardMap;
        this.totalWeight = totalWeight;
        assert !isEmpty();
    }

    public WeightDrawCardBox clone() {
        return new WeightDrawCardBox<>(this.weightCardMap);
    }


    public CARD randomInRepeat() {
        Map tempMap = this.weightCardMap;
        if (tempMap.isEmpty()) {
            return null;
        }
        float index = (ThreadLocalRandom.current().nextFloat() * this.totalWeight);
        for (Map.Entry entry : tempMap.entrySet()) {
            index -= entry.getValue();
            if (index < 0) {
                return entry.getKey();
            }
        }
        throw new RuntimeException("WeightDrawCardBox totalWeight has gone crazy! currentIndex:" + index);
    }


    public CARD randomOne() {
        return randomInRepeat();
    }


    public List randomInMutex(int times, Function extraHandleFunction) {
        if (times <= 0 || times > this.weightCardMap.size()) {
            throw new RuntimeException("WeightDrawCardBox randomRepeatedlyMutex not enough currentSize=" + this.weightCardMap.size() + ",require times=" + times);
        }
        int totalWeight = this.totalWeight;
        Set result = new HashSet<>(times);
        while (result.size() < times) {
            int index = (int) (ThreadLocalRandom.current().nextDouble() * totalWeight);
            for (Map.Entry entry : this.weightCardMap.entrySet()) {
                index -= entry.getValue();
                if (index <= 0) {
                    CARD key = entry.getKey();
                    if (result.contains(key)) {
                        continue;
                    }
                    if (extraHandleFunction != null) {
                        result.add(extraHandleFunction.apply(key));
                        break;
                    }
                    result.add(key);
                    break;
                }
            }
        }
        return new ArrayList<>(result);
    }

    public List randomRepeatedly(int times) {
        List result = new ArrayList<>(times);
        for (int i = 0; i < times; i++) {
            result.add(randomInRepeat());
        }
        return result;
    }

    public List randomInMutex(int times) {
        return randomInMutex(times, null);
    }


    /**
     * 过滤条件下,返回一个新的盒子
     *
     * @return 新的盒子,内部都是符合条件的卡牌
     */
    public WeightDrawCardBox generateNewBox(Predicate filter) {
        return this.filter(filter).orElse(null);
    }

    /**
     * 返回新的 RandomBox。若新的 RandomBox 内元素为空,则返回 Option.empty()
     *
     * @param filterFunc 过滤
     * @return 可能为空的新盒子
     */
    public Optional> filter(Predicate filterFunc) {
        Map weightCardMap = new HashMap<>(this.weightCardMap.size(), 1.0f);
        int totalWeight = 0;
        for (Map.Entry entry : this.weightCardMap.entrySet()) {
            CARD key = entry.getKey();
            if (filterFunc == null || filterFunc.test(key)) {
                continue;
            }
            weightCardMap.put(entry.getKey(), entry.getValue());
            totalWeight += entry.getValue();
        }

        if (totalWeight == 0 || this.weightCardMap.isEmpty()) {
            return Optional.empty();
        } else {
            return Optional.of(new WeightDrawCardBox<>(weightCardMap, totalWeight));
        }
    }

    public Integer getWeight(CARD card) {
        return this.weightCardMap.get(card);
    }

    public boolean isEmpty() {
        return totalWeight <= 0 || weightCardMap.isEmpty();
    }

    public int getCardCount() {
        return weightCardMap.size();
    }

    public Set getKeys() {
        return weightCardMap.keySet();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy