battleroyale.gno
1.57 Kb · 58 lines
1package payout
2
3// BattleRoyale is the winner-takes-all rule. The pot is every stake; the fee is
4// taken from it, and the rest goes to:
5//
6// - the last player in;
7// - when the clock ran out with several in, the one of them with the most
8// kills, and players still in with as many kills share it equally;
9// - and when everyone is out, the player who went out last.
10//
11// It is won by staying in the air, not by scoring: the kill target is
12// ignored, and the arena realm refuses a battle-royale spec that has one.
13//
14// What the split leaves over goes to the fee.
15type BattleRoyale struct{}
16
17var _ Rule = BattleRoyale{}
18
19func (BattleRoyale) Mode() string { return ModeBattleRoyale }
20
21func (BattleRoyale) Settle(g Game, players []address, deaths []Death) (Result, error) {
22 t, err := check(g, players, deaths)
23 if err != nil {
24 return Result{}, err
25 }
26 // The most kills among the players still in.
27 best := int64(-1)
28 for i := range players {
29 if !t.out(i, g.Lives) && t.kills[i] > best {
30 best = t.kills[i]
31 }
32 }
33 won := make([]bool, len(players))
34 winners := int64(0)
35 for i := range players {
36 if !t.out(i, g.Lives) && t.kills[i] == best {
37 won[i] = true
38 winners++
39 }
40 }
41 if winners == 0 {
42 won[t.lastOut] = true
43 winners = 1
44 }
45
46 pot := g.Stake * int64(len(players))
47 share := afterFee(pot, g.FeeBps) / winners
48 res := Result{Fee: pot - share*winners}
49 if share == 0 {
50 return res, nil // a pot too small to split: nobody is paid
51 }
52 for i, p := range players {
53 if won[i] {
54 res.Payouts = append(res.Payouts, Payout{Address: p, Amount: share})
55 }
56 }
57 return res, nil
58}