我的游戲服務(wù)器類庫(kù) -- 按權(quán)重隨機(jī)選擇1個(gè)或n個(gè)對(duì)象
來源:程序員人生 發(fā)布時(shí)間:2014-10-02 08:00:01 閱讀次數(shù):3348次
按權(quán)重選擇
在編寫游戲服務(wù)器的時(shí)候,經(jīng)常會(huì)遇到類似的需求:從列表中隨機(jī)選出1個(gè)或多個(gè)條目,且條目是有權(quán)重的(權(quán)重越大,選中它的可能性就越大)。比如說,砍死一個(gè)怪物可以從一個(gè)裝備列表里掉一個(gè)裝備。這種需求,和現(xiàn)實(shí)生活中的幸運(yùn)大轉(zhuǎn)盤很類似:

算法實(shí)現(xiàn)
因?yàn)檫@種需求很常見,所以我想把它寫的通用一點(diǎn)。首先,接口Weighted表示有權(quán)重值的對(duì)象,getWeight()方法返回權(quán)重值:
public interface Weighted {
public int getWeight();
}
WeightedBase是Weighted接口的抽象實(shí)現(xiàn):
public abstract class WeightedBase implements Weighted {
private final int weight;
public WeightedBase(int weight) {
if (weight <= 0) {
throw new IllegalArgumentException("weight <= 0!");
}
this.weight = weight;
}
@Override
public int getWeight() {
return weight;
}
}
WeightedInt表示擁有權(quán)重值的整數(shù):
public class WeightedInt extends WeightedBase {
private final int value;
public WeightedInt(int weight, int value) {
super(weight);
this.value = value;
}
/**
* 返回整數(shù)值.
* @return
*/
public int getValue() {
return value;
}
}
因?yàn)椴⒉皇敲總€(gè)類都可以實(shí)現(xiàn)Weighted接口或繼承WeightedBase(比如第三方庫(kù)里的類),所以增添了WeightFunction接口來表示權(quán)重計(jì)算函數(shù),apply()方法根據(jù)給定對(duì)象,計(jì)算出其權(quán)重值:
public interface WeightFunction<T> {
public int apply(T t);
}
最后是工具類
WeightUtil,具體的選擇算法在這個(gè)類中實(shí)現(xiàn),下面是這個(gè)類的方法列表:
public class WeightUtil {
public static <T extends Weighted> List<T> select(List<T> list, int n)
public static <T> List<T> select(List<T> list, int n, WeightFunction<T> wf)
public static <T extends Weighted> T selectOne(List<T> list)
public static <T extends Weighted> T selectOne(List<T> list, int randomInt)
public static <T> T selectOne(List<T> list, WeightFunction<T> wf)
public static <T> T selectOne(List<T> list, int randomInt, WeightFunction<T> wf)
}
其中最重要的一個(gè)方法是接收三個(gè)參數(shù)的
selectOne()方法,其他方法都依賴這個(gè)方法,其代碼如下所示:
public static <T> T selectOne(List<T> list, int randomInt, WeightFunction<T> wf) {
if (list.isEmpty()) {
throw new IllegalArgumentException("empty list!");
}
if (randomInt < 0) {
throw new IllegalArgumentException("negative randomInt: " + randomInt);
}
if (list.size() == 1) {
return list.get(0);
}
int weightSum = 0;
for (T obj : list) {
weightSum += wf.apply(obj);
if (weightSum > randomInt) {
return obj;
}
}
String msg = String.format("total weight (%d) <= randomInt (%d)", weightSum, randomInt);
throw new IllegalArgumentException(msg);
}
GitHub項(xiàng)目
想要完整的代碼,可以clone我的GitHub項(xiàng)目。此文章只是一個(gè)開始,希望以后可以把更多的代碼放到這個(gè)項(xiàng)目里。
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)