commit f0dc3716e8ef15eb71f97cfb09132fd20d859fe2 Author: Branden J Brown Date: Sat Jan 20 22:06:56 2024 -0600 initial commit, game init implemented diff --git a/game/game.go b/game/game.go new file mode 100644 index 0000000..6cd64ad --- /dev/null +++ b/game/game.go @@ -0,0 +1,35 @@ +package game + +type Game struct { + RNG RNG + PP [2]Player + Shells []bool + Round int + Turn int + Damage int8 + + // Backing storage for shells. + ShellArray [8]bool +} + +func NewGame() *Game { + return &Game{RNG: NewRNG()} +} + +func (g *Game) StartRound() { + items := g.RNG.Intn(4) + 1 + g.PP[0].StartRound(&g.RNG, items) + g.PP[1].StartRound(&g.RNG, items) + shells := g.RNG.Intn(6) + 2 + for i := 0; i < shells/2; i++ { + g.ShellArray[i] = true + } + for i := shells / 2; i < shells; i++ { + g.ShellArray[i] = false + } + g.Shells = g.ShellArray[:shells] + ShuffleSlice(&g.RNG, g.Shells) + g.Round++ + g.Turn = 0 + g.Damage = 1 +} diff --git a/game/item.go b/game/item.go new file mode 100644 index 0000000..c984580 --- /dev/null +++ b/game/item.go @@ -0,0 +1,16 @@ +package game + +type Item int8 + +const ( + ItemNone Item = iota + ItemLens + ItemCig + ItemBeer + ItemCuff + ItemKnife +) + +func NewItem(rng *RNG) Item { + return Item(rng.Intn(5)) + 1 +} diff --git a/game/player.go b/game/player.go new file mode 100644 index 0000000..b33988b --- /dev/null +++ b/game/player.go @@ -0,0 +1,17 @@ +package game + +type Player struct { + HP int8 + Items [8]Item + Skip bool + Cuffed bool +} + +func (p *Player) StartRound(rng *RNG, items int) { + p.HP = int8(rng.Intn(3) + 2) + for i := 0; i < items; i++ { + p.Items[i] = NewItem(rng) + } + p.Skip = false + p.Cuffed = false +} diff --git a/game/rng.go b/game/rng.go new file mode 100644 index 0000000..76926c4 --- /dev/null +++ b/game/rng.go @@ -0,0 +1,65 @@ +package game + +import ( + "crypto/rand" + "encoding/binary" + "math/bits" +) + +// RNG is a random number generator for shotgun. +// +// Currently xoshiro256**. Subject to change. +type RNG struct { + w, x, y, z uint64 +} + +// NewRNG produces a new, uniquely seeded RNG. +func NewRNG() RNG { + r := RNG{} + 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 *RNG) 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 *RNG) 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 ShuffleSlice[E any, S ~[]E](rng *RNG, s S) { + for i := len(s) - 1; i > 0; i-- { + j := rng.Intn(i + 1) + s[i], s[j] = s[j], s[i] + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..adba1b7 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.sunturtle.xyz/studio/shotgun + +go 1.21.3