From e173225b6e682033d243f7bb25fb54932fc0bc20 Mon Sep 17 00:00:00 2001 From: Branden J Brown Date: Sat, 20 Jan 2024 22:52:44 -0600 Subject: [PATCH] second commit, too busy flowing to isolate work --- game/game.go | 52 ++++++++++++++++++++++++++++++++++++++++++-------- game/item.go | 41 +++++++++++++++++++++++++++++++++++++++ game/player.go | 43 ++++++++++++++++++++++++++++++----------- 3 files changed, 117 insertions(+), 19 deletions(-) diff --git a/game/game.go b/game/game.go index 6cd64ad..84151c1 100644 --- a/game/game.go +++ b/game/game.go @@ -4,22 +4,34 @@ type Game struct { RNG RNG PP [2]Player Shells []bool - Round int - Turn int + HP int8 + Round uint + Group uint + Turn uint Damage int8 + Reveal bool // Backing storage for shells. ShellArray [8]bool } func NewGame() *Game { - return &Game{RNG: NewRNG()} + return &Game{ + RNG: NewRNG(), + Damage: 1, + } } func (g *Game) StartRound() { + g.PP[0].StartRound() + g.PP[1].StartRound() +} + +func (g *Game) StartGroup() { items := g.RNG.Intn(4) + 1 - g.PP[0].StartRound(&g.RNG, items) - g.PP[1].StartRound(&g.RNG, items) + g.HP = int8(g.RNG.Intn(3) + 2) + g.PP[0].StartGroup(&g.RNG, g.HP, items) + g.PP[1].StartGroup(&g.RNG, g.HP, items) shells := g.RNG.Intn(6) + 2 for i := 0; i < shells/2; i++ { g.ShellArray[i] = true @@ -29,7 +41,31 @@ func (g *Game) StartRound() { } g.Shells = g.ShellArray[:shells] ShuffleSlice(&g.RNG, g.Shells) - g.Round++ - g.Turn = 0 - g.Damage = 1 + g.Group++ +} + +// CurrentPlayer gets the index of the current player, either 0 or 1. +func (g *Game) CurrentPlayer() uint { + return g.Turn % 2 +} + +// Opponent returns the player who is not the current player. +func (g *Game) Opponent() *Player { + return &g.PP[1^g.CurrentPlayer()] +} + +// Apply uses an item by index for the current player. +func (g *Game) Apply(item int) { +} + +// PopShell removes a shell from the shotgun. +// This may cause the shotgun to be empty, but does not start the next group +// if so. +func (g *Game) PopShell() { + g.Shells = g.Shells[1:] +} + +// Empty returns whether the shotgun is empty. +func (g *Game) Empty() bool { + return len(g.Shells) == 0 } diff --git a/game/item.go b/game/item.go index c984580..d0ed602 100644 --- a/game/item.go +++ b/game/item.go @@ -14,3 +14,44 @@ const ( func NewItem(rng *RNG) Item { return Item(rng.Intn(5)) + 1 } + +func (i Item) Apply(g *Game) bool { + switch i { + case ItemNone: + return false + case ItemLens: + if g.Reveal { + return false + } + g.Reveal = true + return true + case ItemCig: + cur := &g.PP[g.CurrentPlayer()] + if cur.HP < g.HP { + cur.HP++ + return true + } + return false + case ItemBeer: + g.PopShell() + if g.Empty() { + g.StartGroup() + } + return true + case ItemCuff: + opp := g.Opponent() + if opp.Cuffs != Uncuffed { + return false + } + opp.Cuffs = Cuffed + return true + case ItemKnife: + if g.Damage != 1 { + return false + } + g.Damage = 2 + return true + default: + panic("shotgun: unknown item") + } +} diff --git a/game/player.go b/game/player.go index b33988b..b15d796 100644 --- a/game/player.go +++ b/game/player.go @@ -1,17 +1,38 @@ package game +import "slices" + +// PlayerID is a unique ID for a player. +// May just be IPv6 (or IPv4-in-6) of their connection, or a UUID. +type PlayerID [16]byte + type Player struct { - HP int8 - Items [8]Item - Skip bool - Cuffed bool + ID PlayerID + HP int8 + Items [8]Item + Cuffs CuffState } -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 +func (p *Player) StartRound() { + clear(p.Items[:]) } + +func (p *Player) StartGroup(rng *RNG, hp int8, items int) { + p.HP = hp + for i := 0; i < items; i++ { + k := slices.Index(p.Items[:], ItemNone) + if k < 0 { + break + } + p.Items[k] = NewItem(rng) + } + p.Cuffs = Uncuffed // TODO(zeph): or is this startround? +} + +type CuffState uint8 + +const ( + Uncuffed CuffState = iota + Cuffed + CuffedSkip +)