use math/rand/v2 for randomness
This commit is contained in:
parent
e25c952bcd
commit
29a14960f4
16
game/game.go
16
game/game.go
@ -11,6 +11,7 @@ package game
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand/v2"
|
||||
"time"
|
||||
|
||||
"git.sunturtle.xyz/studio/shotgun/player"
|
||||
@ -18,8 +19,6 @@ import (
|
||||
)
|
||||
|
||||
type Match struct {
|
||||
// rng is the PRNG state used for this match.
|
||||
rng xoshiro
|
||||
// players are the players in the match. The first element is the dealer
|
||||
// and the second is the challenger.
|
||||
players [2]playerState
|
||||
@ -50,7 +49,6 @@ type Match struct {
|
||||
// New creates a new match started at round 1.
|
||||
func New(dealer, challenger player.ID) *Match {
|
||||
g := &Match{
|
||||
rng: newRNG(),
|
||||
players: [2]playerState{
|
||||
{id: dealer},
|
||||
{id: challenger},
|
||||
@ -62,7 +60,7 @@ func New(dealer, challenger player.ID) *Match {
|
||||
|
||||
// NextRound starts the next round of a match.
|
||||
func (g *Match) NextRound() {
|
||||
g.hp = int8(g.rng.Intn(3) + 2)
|
||||
g.hp = int8(rand.IntN(3) + 2)
|
||||
g.players[0].startRound(g.hp)
|
||||
g.players[1].startRound(g.hp)
|
||||
g.round++
|
||||
@ -71,10 +69,10 @@ func (g *Match) NextRound() {
|
||||
|
||||
// NextGame starts the next game of a round.
|
||||
func (g *Match) NextGame() {
|
||||
items := g.rng.Intn(4) + 1
|
||||
g.players[0].startGame(&g.rng, items)
|
||||
g.players[1].startGame(&g.rng, items)
|
||||
shells := g.rng.Intn(6) + 2
|
||||
items := rand.IntN(4) + 1
|
||||
g.players[0].startGame(items)
|
||||
g.players[1].startGame(items)
|
||||
shells := rand.IntN(6) + 2
|
||||
for i := 0; i < shells/2; i++ {
|
||||
g.shellArray[i] = true
|
||||
}
|
||||
@ -82,7 +80,7 @@ func (g *Match) NextGame() {
|
||||
g.shellArray[i] = false
|
||||
}
|
||||
g.shells = g.shellArray[:shells]
|
||||
shuffle(&g.rng, g.shells)
|
||||
shuffle(g.shells)
|
||||
g.turn = 0
|
||||
g.prev = nil
|
||||
g.nextTurn()
|
||||
|
@ -1,5 +1,7 @@
|
||||
package game
|
||||
|
||||
import "math/rand/v2"
|
||||
|
||||
type item int8
|
||||
|
||||
const (
|
||||
@ -11,8 +13,8 @@ const (
|
||||
itemKnife
|
||||
)
|
||||
|
||||
func newItem(rng *xoshiro) item {
|
||||
return item(rng.Intn(5)) + 1
|
||||
func newItem() item {
|
||||
return item(rand.IntN(5)) + 1
|
||||
}
|
||||
|
||||
func (i item) apply(g *Match) bool {
|
||||
|
@ -19,13 +19,13 @@ func (p *playerState) startRound(hp int8) {
|
||||
clear(p.items[:])
|
||||
}
|
||||
|
||||
func (p *playerState) startGame(rng *xoshiro, items int) {
|
||||
func (p *playerState) startGame(items int) {
|
||||
for i := 0; i < items; i++ {
|
||||
k := slices.Index(p.items[:], itemNone)
|
||||
if k < 0 {
|
||||
break
|
||||
}
|
||||
p.items[k] = newItem(rng)
|
||||
p.items[k] = newItem()
|
||||
}
|
||||
p.cuffs = uncuffed
|
||||
}
|
||||
|
61
game/rng.go
61
game/rng.go
@ -1,65 +1,10 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"math/bits"
|
||||
)
|
||||
import "math/rand/v2"
|
||||
|
||||
// xoshiro is a random number generator for shotgun.
|
||||
//
|
||||
// Currently xoshiro256**. Subject to change.
|
||||
type xoshiro struct {
|
||||
w, x, y, z uint64
|
||||
}
|
||||
|
||||
// newRNG produces a new, uniquely seeded RNG.
|
||||
func newRNG() xoshiro {
|
||||
r := xoshiro{}
|
||||
b := make([]byte, 8*4)
|
||||
// Loop to ensure the state is never all-zero, which is an invalid state
|
||||
// for xoshiro.
|
||||
for r.w == 0 && r.x == 0 && r.y == 0 && r.z == 0 {
|
||||
rand.Read(b)
|
||||
r.w = binary.LittleEndian.Uint64(b)
|
||||
r.x = binary.LittleEndian.Uint64(b[8:])
|
||||
r.y = binary.LittleEndian.Uint64(b[16:])
|
||||
r.z = binary.LittleEndian.Uint64(b[24:])
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Uint64 produces a 64-bit pseudo-random value.
|
||||
func (rng *xoshiro) Uint64() uint64 {
|
||||
w, x, y, z := rng.w, rng.x, rng.y, rng.z
|
||||
r := bits.RotateLeft64(x*5, 7) * 9
|
||||
t := x << 17
|
||||
y ^= w
|
||||
z ^= x
|
||||
x ^= y
|
||||
w ^= z
|
||||
y ^= t
|
||||
z = bits.RotateLeft64(z, 45)
|
||||
rng.w, rng.x, rng.y, rng.z = w, x, y, z
|
||||
return r
|
||||
}
|
||||
|
||||
// Intn produces an int in [0, n). Panics if n <= 0.
|
||||
func (rng *xoshiro) Intn(n int) int {
|
||||
if n <= 0 {
|
||||
panic("shotgun: rng.Intn max below zero")
|
||||
}
|
||||
bad := ^uint(0) - ^uint(0)%uint(n)
|
||||
x := uint(rng.Uint64())
|
||||
for x > bad {
|
||||
x = uint(rng.Uint64())
|
||||
}
|
||||
return int(x % uint(n))
|
||||
}
|
||||
|
||||
func shuffle[E any, S ~[]E](rng *xoshiro, s S) {
|
||||
func shuffle[E any, S ~[]E](s S) {
|
||||
for i := len(s) - 1; i > 0; i-- {
|
||||
j := rng.Intn(i + 1)
|
||||
j := rand.IntN(i + 1)
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user