mirror of
https://github.com/Luzifer/twitch-bot.git
synced 2024-11-09 00:30:02 +00:00
63 lines
1.1 KiB
Go
63 lines
1.1 KiB
Go
|
package raffle
|
||
|
|
||
|
import (
|
||
|
"crypto/rand"
|
||
|
"encoding/binary"
|
||
|
mathRand "math/rand"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
cryptRandSrc struct{}
|
||
|
)
|
||
|
|
||
|
var errNoCandidatesLeft = errors.New("no candidates left")
|
||
|
|
||
|
func pickWinnerFromRaffle(r raffle) (winner raffleEntry, err error) {
|
||
|
var maxScore float64
|
||
|
for _, re := range r.Entries {
|
||
|
if re.WasPicked {
|
||
|
// We skip previously picked winners and pretend they
|
||
|
// don't exist
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
maxScore += re.Multiplier
|
||
|
}
|
||
|
|
||
|
if maxScore == 0 {
|
||
|
return winner, errNoCandidatesLeft
|
||
|
}
|
||
|
|
||
|
winnerPoint := mathRand.New(cryptRandSrc{}).Float64() * maxScore //#nosec:G404 - RNG is using a secure source
|
||
|
|
||
|
for i := range r.Entries {
|
||
|
re := r.Entries[i]
|
||
|
|
||
|
if re.WasPicked {
|
||
|
// We skip previously picked winners and pretend they
|
||
|
// don't exist
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
winnerPoint -= re.Multiplier
|
||
|
if winnerPoint < 0 {
|
||
|
winner = re
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return winner, nil
|
||
|
}
|
||
|
|
||
|
func (cryptRandSrc) Int63() int64 {
|
||
|
var b [8]byte
|
||
|
rand.Read(b[:])
|
||
|
// mask off sign bit to ensure positive number
|
||
|
return int64(binary.LittleEndian.Uint64(b[:]) & (1<<63 - 1))
|
||
|
}
|
||
|
|
||
|
// We're using a non-seedable source
|
||
|
func (cryptRandSrc) Seed(int64) {}
|