use math/rand/v2 for randomness
This commit is contained in:
		
							
								
								
									
										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] | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user