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 (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"math/rand/v2"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.sunturtle.xyz/studio/shotgun/player"
|
"git.sunturtle.xyz/studio/shotgun/player"
|
||||||
@ -18,8 +19,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Match struct {
|
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
|
// players are the players in the match. The first element is the dealer
|
||||||
// and the second is the challenger.
|
// and the second is the challenger.
|
||||||
players [2]playerState
|
players [2]playerState
|
||||||
@ -50,7 +49,6 @@ type Match struct {
|
|||||||
// New creates a new match started at round 1.
|
// New creates a new match started at round 1.
|
||||||
func New(dealer, challenger player.ID) *Match {
|
func New(dealer, challenger player.ID) *Match {
|
||||||
g := &Match{
|
g := &Match{
|
||||||
rng: newRNG(),
|
|
||||||
players: [2]playerState{
|
players: [2]playerState{
|
||||||
{id: dealer},
|
{id: dealer},
|
||||||
{id: challenger},
|
{id: challenger},
|
||||||
@ -62,7 +60,7 @@ func New(dealer, challenger player.ID) *Match {
|
|||||||
|
|
||||||
// NextRound starts the next round of a match.
|
// NextRound starts the next round of a match.
|
||||||
func (g *Match) NextRound() {
|
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[0].startRound(g.hp)
|
||||||
g.players[1].startRound(g.hp)
|
g.players[1].startRound(g.hp)
|
||||||
g.round++
|
g.round++
|
||||||
@ -71,10 +69,10 @@ func (g *Match) NextRound() {
|
|||||||
|
|
||||||
// NextGame starts the next game of a round.
|
// NextGame starts the next game of a round.
|
||||||
func (g *Match) NextGame() {
|
func (g *Match) NextGame() {
|
||||||
items := g.rng.Intn(4) + 1
|
items := rand.IntN(4) + 1
|
||||||
g.players[0].startGame(&g.rng, items)
|
g.players[0].startGame(items)
|
||||||
g.players[1].startGame(&g.rng, items)
|
g.players[1].startGame(items)
|
||||||
shells := g.rng.Intn(6) + 2
|
shells := rand.IntN(6) + 2
|
||||||
for i := 0; i < shells/2; i++ {
|
for i := 0; i < shells/2; i++ {
|
||||||
g.shellArray[i] = true
|
g.shellArray[i] = true
|
||||||
}
|
}
|
||||||
@ -82,7 +80,7 @@ func (g *Match) NextGame() {
|
|||||||
g.shellArray[i] = false
|
g.shellArray[i] = false
|
||||||
}
|
}
|
||||||
g.shells = g.shellArray[:shells]
|
g.shells = g.shellArray[:shells]
|
||||||
shuffle(&g.rng, g.shells)
|
shuffle(g.shells)
|
||||||
g.turn = 0
|
g.turn = 0
|
||||||
g.prev = nil
|
g.prev = nil
|
||||||
g.nextTurn()
|
g.nextTurn()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
|
import "math/rand/v2"
|
||||||
|
|
||||||
type item int8
|
type item int8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -11,8 +13,8 @@ const (
|
|||||||
itemKnife
|
itemKnife
|
||||||
)
|
)
|
||||||
|
|
||||||
func newItem(rng *xoshiro) item {
|
func newItem() item {
|
||||||
return item(rng.Intn(5)) + 1
|
return item(rand.IntN(5)) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i item) apply(g *Match) bool {
|
func (i item) apply(g *Match) bool {
|
||||||
|
@ -19,13 +19,13 @@ func (p *playerState) startRound(hp int8) {
|
|||||||
clear(p.items[:])
|
clear(p.items[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *playerState) startGame(rng *xoshiro, items int) {
|
func (p *playerState) startGame(items int) {
|
||||||
for i := 0; i < items; i++ {
|
for i := 0; i < items; i++ {
|
||||||
k := slices.Index(p.items[:], itemNone)
|
k := slices.Index(p.items[:], itemNone)
|
||||||
if k < 0 {
|
if k < 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p.items[k] = newItem(rng)
|
p.items[k] = newItem()
|
||||||
}
|
}
|
||||||
p.cuffs = uncuffed
|
p.cuffs = uncuffed
|
||||||
}
|
}
|
||||||
|
61
game/rng.go
61
game/rng.go
@ -1,65 +1,10 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
import (
|
import "math/rand/v2"
|
||||||
"crypto/rand"
|
|
||||||
"encoding/binary"
|
|
||||||
"math/bits"
|
|
||||||
)
|
|
||||||
|
|
||||||
// xoshiro is a random number generator for shotgun.
|
func shuffle[E any, S ~[]E](s S) {
|
||||||
//
|
|
||||||
// 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) {
|
|
||||||
for i := len(s) - 1; i > 0; i-- {
|
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]
|
s[i], s[j] = s[j], s[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user