年末项目组需要做一个抽奖活动,奖品池有很多奖品,运营可以配置每个奖品的爆率,这篇文章给出一个简单的实现。

抽奖

首先有个必要条件是,奖品池的奖品总概率不能超过 1。

算法步骤:

  1. 把所有奖品放在一个数组内;
  2. 把奖品的概率分配到 0~1 的区间内;
  3. 生成一个 0~1 的随机数;
  4. 如果随机数落在区间内,则中奖,反之亦然。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class Lottery {

public static void main(String[] args) {
List<Prize> prizes = new ArrayList<>();
prizes.add(new Prize(0.00001, "手机"));
prizes.add(new Prize(0.00000001, "电脑"));

printPrize(prizes);

int count = 0;
for (int i = 0; i < 10000000; i++) {
if (doLottery(prizes)) count++;
}

System.out.println("中奖次数:" + count);
}

private static boolean doLottery(List<Prize> prizes) {
double num = Math.random();

double start = 0;
for (Prize p : prizes) {
double end = start + p.possibility;
if (num > start && num < end) {
System.out.println(" 中奖:" + p.name + " " + double2String(num));

return true;
}

start = end;
}

return false;
}

private static class Prize {

double possibility;

String name;

private Prize(double possibility, String name) {
this.possibility = possibility;
this.name = name;
}
}

private static void printPrize(List<Prize> prizes) {
double start = 0;
for (Prize p : prizes) {
double end = start + p.possibility;
System.out.println(p.name + ": [ " + double2String(start) + " - " + double2String(end) + " ]");
start = end;
}
}

private static String double2String(double d) {
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
df.setMaximumFractionDigits(10);
return df.format(d);
}
}

执行结果:

1
2
3
4
5
手机: [ 0 - 0.0000001 ]
电脑: [ 0.0000001 - 0.0000002 ]
中奖:电脑 0.0000001615
中奖:手机 0.0000000219
中奖次数:2