mirror of
https://github.com/Luzifer/twitch-bot.git
synced 2024-12-30 08:31:16 +00:00
64 lines
1.2 KiB
Go
64 lines
1.2 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
|
|
if _, err := rand.Read(b[:]); err != nil {
|
|
return -1
|
|
}
|
|
// mask off sign bit to ensure positive number
|
|
return int64(binary.LittleEndian.Uint64(b[:]) & (1<<63 - 1)) //#nosec:G115 - Masking ensures conversion is fine
|
|
}
|
|
|
|
// We're using a non-seedable source
|
|
func (cryptRandSrc) Seed(int64) {}
|