unexport game state fields
This commit is contained in:
parent
bc1685d5ee
commit
46563f9115
120
game/game.go
120
game/game.go
@ -8,28 +8,28 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Game struct {
|
type Game struct {
|
||||||
RNG RNG
|
rng RNG
|
||||||
PP [2]Player
|
players [2]Player
|
||||||
Shells []bool
|
shells []bool
|
||||||
Round uint
|
round uint
|
||||||
Group uint
|
group uint
|
||||||
Turn uint
|
turn uint
|
||||||
HP int8
|
hp int8
|
||||||
Damage int8
|
damage int8
|
||||||
Reveal bool
|
reveal bool
|
||||||
Prev *bool
|
prev *bool
|
||||||
|
|
||||||
// Backing storage for shells.
|
// Backing storage for shells.
|
||||||
ShellArray [8]bool
|
shellArray [8]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new game started at round 1.
|
// New creates a new game started at round 1.
|
||||||
func New(dealer, challenger player.ID) *Game {
|
func New(dealer, challenger player.ID) *Game {
|
||||||
g := &Game{
|
g := &Game{
|
||||||
RNG: NewRNG(),
|
rng: NewRNG(),
|
||||||
PP: [2]Player{
|
players: [2]Player{
|
||||||
{ID: dealer},
|
{id: dealer},
|
||||||
{ID: challenger},
|
{id: challenger},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
g.StartRound()
|
g.StartRound()
|
||||||
@ -38,42 +38,42 @@ func New(dealer, challenger player.ID) *Game {
|
|||||||
|
|
||||||
// StartRound starts the next round of a game.
|
// StartRound starts the next round of a game.
|
||||||
func (g *Game) StartRound() {
|
func (g *Game) StartRound() {
|
||||||
g.HP = int8(g.RNG.Intn(3) + 2)
|
g.hp = int8(g.rng.Intn(3) + 2)
|
||||||
g.PP[0].StartRound(g.HP)
|
g.players[0].StartRound(g.hp)
|
||||||
g.PP[1].StartRound(g.HP)
|
g.players[1].StartRound(g.hp)
|
||||||
g.Round++
|
g.round++
|
||||||
g.Group = 0
|
g.group = 0
|
||||||
g.StartGroup()
|
g.StartGroup()
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartGroup starts the next shell group of a round.
|
// StartGroup starts the next shell group of a round.
|
||||||
func (g *Game) StartGroup() {
|
func (g *Game) StartGroup() {
|
||||||
items := g.RNG.Intn(4) + 1
|
items := g.rng.Intn(4) + 1
|
||||||
g.PP[0].StartGroup(&g.RNG, items)
|
g.players[0].StartGroup(&g.rng, items)
|
||||||
g.PP[1].StartGroup(&g.RNG, items)
|
g.players[1].StartGroup(&g.rng, items)
|
||||||
shells := g.RNG.Intn(6) + 2
|
shells := g.rng.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
|
||||||
}
|
}
|
||||||
for i := shells / 2; i < shells; i++ {
|
for i := shells / 2; i < shells; i++ {
|
||||||
g.ShellArray[i] = false
|
g.shellArray[i] = false
|
||||||
}
|
}
|
||||||
g.Shells = g.ShellArray[:shells]
|
g.shells = g.shellArray[:shells]
|
||||||
ShuffleSlice(&g.RNG, g.Shells)
|
ShuffleSlice(&g.rng, g.shells)
|
||||||
g.Group++
|
g.group++
|
||||||
g.Turn = 0
|
g.turn = 0
|
||||||
g.Prev = nil
|
g.prev = nil
|
||||||
g.NextTurn()
|
g.NextTurn()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextTurn advances the turn.
|
// NextTurn advances the turn.
|
||||||
func (g *Game) NextTurn() {
|
func (g *Game) NextTurn() {
|
||||||
g.Turn++
|
g.turn++
|
||||||
g.Damage = 1
|
g.damage = 1
|
||||||
g.Reveal = false
|
g.reveal = false
|
||||||
cur := g.CurrentPlayer()
|
cur := g.CurrentPlayer()
|
||||||
skip := cur.Cuffs == CuffedSkip
|
skip := cur.cuffs == CuffedSkip
|
||||||
cur.Cuffs = cur.Cuffs.NextState()
|
cur.cuffs = cur.cuffs.NextState()
|
||||||
if skip {
|
if skip {
|
||||||
g.NextTurn()
|
g.NextTurn()
|
||||||
}
|
}
|
||||||
@ -81,12 +81,12 @@ func (g *Game) NextTurn() {
|
|||||||
|
|
||||||
// CurrentPlayer gets the index of the current player, either 0 or 1.
|
// CurrentPlayer gets the index of the current player, either 0 or 1.
|
||||||
func (g *Game) CurrentPlayer() *Player {
|
func (g *Game) CurrentPlayer() *Player {
|
||||||
return &g.PP[g.Turn%2]
|
return &g.players[g.turn%2]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opponent returns the player who is not the current player.
|
// Opponent returns the player who is not the current player.
|
||||||
func (g *Game) Opponent() *Player {
|
func (g *Game) Opponent() *Player {
|
||||||
return &g.PP[g.Turn%2^1]
|
return &g.players[g.turn%2^1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply uses an item by index for the current player.
|
// Apply uses an item by index for the current player.
|
||||||
@ -94,14 +94,14 @@ func (g *Game) Opponent() *Player {
|
|||||||
// Returns ErrWrongTurn if id does not correspond to the current player.
|
// Returns ErrWrongTurn if id does not correspond to the current player.
|
||||||
func (g *Game) Apply(id player.ID, item int) error {
|
func (g *Game) Apply(id player.ID, item int) error {
|
||||||
cur := g.CurrentPlayer()
|
cur := g.CurrentPlayer()
|
||||||
if cur.ID != id {
|
if cur.id != id {
|
||||||
return ErrWrongTurn
|
return ErrWrongTurn
|
||||||
}
|
}
|
||||||
if item < 0 || item >= len(cur.Items) {
|
if item < 0 || item >= len(cur.items) {
|
||||||
return errors.New("item index out of bounds")
|
return errors.New("item index out of bounds")
|
||||||
}
|
}
|
||||||
if cur.Items[item].Apply(g) {
|
if cur.items[item].Apply(g) {
|
||||||
cur.Items[item] = ItemNone
|
cur.items[item] = ItemNone
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -110,32 +110,32 @@ func (g *Game) Apply(id player.ID, item int) error {
|
|||||||
// This may cause the shotgun to be empty, but does not start the next group
|
// This may cause the shotgun to be empty, but does not start the next group
|
||||||
// if so.
|
// if so.
|
||||||
func (g *Game) PopShell() bool {
|
func (g *Game) PopShell() bool {
|
||||||
g.Prev = &g.Shells[0]
|
g.prev = &g.shells[0]
|
||||||
g.Shells = g.Shells[1:]
|
g.shells = g.shells[1:]
|
||||||
return *g.Prev
|
return *g.prev
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peek returns the current turn's shell if it is revealed for the player with
|
// Peek returns the current turn's shell if it is revealed for the player with
|
||||||
// the given ID, or nil otherwise.
|
// the given ID, or nil otherwise.
|
||||||
func (g *Game) Peek(id player.ID) *bool {
|
func (g *Game) Peek(id player.ID) *bool {
|
||||||
if len(g.Shells) == 0 || id != g.CurrentPlayer().ID || !g.Reveal {
|
if len(g.shells) == 0 || id != g.CurrentPlayer().id || !g.reveal {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &g.Shells[0]
|
return &g.shells[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty returns whether the shotgun is empty.
|
// Empty returns whether the shotgun is empty.
|
||||||
func (g *Game) Empty() bool {
|
func (g *Game) Empty() bool {
|
||||||
return len(g.Shells) == 0
|
return len(g.shells) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Winner returns the player who won, or nil if the round is not over.
|
// Winner returns the player who won, or nil if the round is not over.
|
||||||
func (g *Game) Winner() *Player {
|
func (g *Game) Winner() *Player {
|
||||||
if g.PP[0].HP <= 0 {
|
if g.players[0].hp <= 0 {
|
||||||
return &g.PP[1]
|
return &g.players[1]
|
||||||
}
|
}
|
||||||
if g.PP[1].HP <= 0 {
|
if g.players[1].hp <= 0 {
|
||||||
return &g.PP[0]
|
return &g.players[0]
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -146,7 +146,7 @@ func (g *Game) Winner() *Player {
|
|||||||
// Returns ErrWrongTurn if id does not correspond to the current player.
|
// Returns ErrWrongTurn if id does not correspond to the current player.
|
||||||
func (g *Game) Shoot(id player.ID, self bool) error {
|
func (g *Game) Shoot(id player.ID, self bool) error {
|
||||||
cur := g.CurrentPlayer()
|
cur := g.CurrentPlayer()
|
||||||
if cur.ID != id {
|
if cur.id != id {
|
||||||
return ErrWrongTurn
|
return ErrWrongTurn
|
||||||
}
|
}
|
||||||
target := g.Opponent()
|
target := g.Opponent()
|
||||||
@ -155,7 +155,7 @@ func (g *Game) Shoot(id player.ID, self bool) error {
|
|||||||
}
|
}
|
||||||
live := g.PopShell()
|
live := g.PopShell()
|
||||||
if live {
|
if live {
|
||||||
target.HP -= g.Damage
|
target.hp -= g.damage
|
||||||
g.NextTurn()
|
g.NextTurn()
|
||||||
} else if !self {
|
} else if !self {
|
||||||
g.NextTurn()
|
g.NextTurn()
|
||||||
@ -167,20 +167,20 @@ func (g *Game) Shoot(id player.ID, self bool) error {
|
|||||||
func (g *Game) DTO(id player.ID) serve.Game {
|
func (g *Game) DTO(id player.ID) serve.Game {
|
||||||
return serve.Game{
|
return serve.Game{
|
||||||
Players: [2]serve.Player{
|
Players: [2]serve.Player{
|
||||||
g.PP[0].DTO(),
|
g.players[0].DTO(),
|
||||||
g.PP[1].DTO(),
|
g.players[1].DTO(),
|
||||||
},
|
},
|
||||||
Round: g.Round,
|
Round: g.round,
|
||||||
Damage: g.Damage,
|
Damage: g.damage,
|
||||||
Shell: g.Peek(id),
|
Shell: g.Peek(id),
|
||||||
Previous: g.Prev,
|
Previous: g.prev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShellCounts returns the number of live and blank shells.
|
// ShellCounts returns the number of live and blank shells.
|
||||||
func (g *Game) ShellCounts() serve.ShellCounts {
|
func (g *Game) ShellCounts() serve.ShellCounts {
|
||||||
var counts serve.ShellCounts
|
var counts serve.ShellCounts
|
||||||
for _, s := range g.Shells {
|
for _, s := range g.shells {
|
||||||
if s {
|
if s {
|
||||||
counts.Live++
|
counts.Live++
|
||||||
} else {
|
} else {
|
||||||
|
16
game/item.go
16
game/item.go
@ -20,15 +20,15 @@ func (i Item) Apply(g *Game) bool {
|
|||||||
case ItemNone:
|
case ItemNone:
|
||||||
return false
|
return false
|
||||||
case ItemLens:
|
case ItemLens:
|
||||||
if g.Reveal {
|
if g.reveal {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
g.Reveal = true
|
g.reveal = true
|
||||||
return true
|
return true
|
||||||
case ItemCig:
|
case ItemCig:
|
||||||
cur := g.CurrentPlayer()
|
cur := g.CurrentPlayer()
|
||||||
if cur.HP < g.HP {
|
if cur.hp < g.hp {
|
||||||
cur.HP++
|
cur.hp++
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -40,16 +40,16 @@ func (i Item) Apply(g *Game) bool {
|
|||||||
return true
|
return true
|
||||||
case ItemCuff:
|
case ItemCuff:
|
||||||
opp := g.Opponent()
|
opp := g.Opponent()
|
||||||
if opp.Cuffs != Uncuffed {
|
if opp.cuffs != Uncuffed {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
opp.Cuffs = Cuffed
|
opp.cuffs = Cuffed
|
||||||
return true
|
return true
|
||||||
case ItemKnife:
|
case ItemKnife:
|
||||||
if g.Damage != 1 {
|
if g.damage != 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
g.Damage = 2
|
g.damage = 2
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
panic("shotgun: unknown item")
|
panic("shotgun: unknown item")
|
||||||
|
@ -8,35 +8,35 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Player struct {
|
type Player struct {
|
||||||
ID player.ID
|
id player.ID
|
||||||
HP int8
|
hp int8
|
||||||
Items [8]Item
|
items [8]Item
|
||||||
Cuffs CuffState
|
cuffs CuffState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) StartRound(hp int8) {
|
func (p *Player) StartRound(hp int8) {
|
||||||
p.HP = hp
|
p.hp = hp
|
||||||
clear(p.Items[:])
|
clear(p.items[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) StartGroup(rng *RNG, items int) {
|
func (p *Player) StartGroup(rng *RNG, 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(rng)
|
||||||
}
|
}
|
||||||
p.Cuffs = Uncuffed
|
p.cuffs = Uncuffed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) DTO() serve.Player {
|
func (p *Player) DTO() serve.Player {
|
||||||
r := serve.Player{
|
r := serve.Player{
|
||||||
HP: p.HP,
|
HP: p.hp,
|
||||||
Items: make([]string, 0, 8),
|
Items: make([]string, 0, 8),
|
||||||
Cuffs: p.Cuffs != Uncuffed,
|
Cuffs: p.cuffs != Uncuffed,
|
||||||
}
|
}
|
||||||
for _, i := range p.Items {
|
for _, i := range p.items {
|
||||||
s := i.String()
|
s := i.String()
|
||||||
if s == "" {
|
if s == "" {
|
||||||
continue
|
continue
|
||||||
|
Loading…
Reference in New Issue
Block a user