transmit game actions and winner in dto
This commit is contained in:
35
game/action.go
Normal file
35
game/action.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package game
|
||||
|
||||
type action uint8
|
||||
|
||||
const (
|
||||
actStart action = iota // start of match
|
||||
|
||||
actShoot // fired, note prev indicates whether the shell was live
|
||||
actGameEnd // end of game but not round
|
||||
actBeerGameEnd // used a beer to end the game
|
||||
actChallengerWins // challenger wins the round
|
||||
actDealerWins // dealer wins the match
|
||||
|
||||
// current player uses an item
|
||||
actLens
|
||||
actCig
|
||||
actBeer // note prev indicates whether the shell was live
|
||||
actCuff
|
||||
actKnife
|
||||
|
||||
actDealerConcedes // dealer concedes
|
||||
actChallengerConcedes // challenger concedes
|
||||
)
|
||||
|
||||
//go:generate go run golang.org/x/tools/cmd/stringer@v0.17.0 -type=action -trimprefix=act
|
||||
|
||||
// gameStart returns whether the action indicates the start of a game.
|
||||
func (a action) gameStart() bool {
|
||||
switch a {
|
||||
case actStart, actGameEnd, actBeerGameEnd, actChallengerWins:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
35
game/action_string.go
Normal file
35
game/action_string.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// Code generated by "stringer -type=action -trimprefix=act"; DO NOT EDIT.
|
||||
|
||||
package game
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[actStart-0]
|
||||
_ = x[actShoot-1]
|
||||
_ = x[actGameEnd-2]
|
||||
_ = x[actBeerGameEnd-3]
|
||||
_ = x[actChallengerWins-4]
|
||||
_ = x[actDealerWins-5]
|
||||
_ = x[actLens-6]
|
||||
_ = x[actCig-7]
|
||||
_ = x[actBeer-8]
|
||||
_ = x[actCuff-9]
|
||||
_ = x[actKnife-10]
|
||||
_ = x[actDealerConcedes-11]
|
||||
_ = x[actChallengerConcedes-12]
|
||||
}
|
||||
|
||||
const _action_name = "StartShootGameEndBeerGameEndChallengerWinsDealerWinsLensCigBeerCuffKnifeDealerConcedesChallengerConcedes"
|
||||
|
||||
var _action_index = [...]uint8{0, 5, 10, 17, 28, 42, 52, 56, 59, 63, 67, 72, 86, 104}
|
||||
|
||||
func (i action) String() string {
|
||||
if i >= action(len(_action_index)-1) {
|
||||
return "action(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _action_name[_action_index[i]:_action_index[i+1]]
|
||||
}
|
19
game/game.go
19
game/game.go
@@ -39,6 +39,8 @@ type Match struct {
|
||||
// prev is a pointer to the element of shellArray which was fired last this
|
||||
// game, or nil if none has been.
|
||||
prev *bool
|
||||
// action is a description of the previous action.
|
||||
action action
|
||||
|
||||
// shellArray is the backing storage for shells and prev.
|
||||
shellArray [8]bool
|
||||
@@ -188,18 +190,22 @@ func (g *Match) Shoot(id player.ID, self bool) error {
|
||||
target = g.CurrentPlayer()
|
||||
}
|
||||
live := g.popShell()
|
||||
g.action = actShoot
|
||||
if live {
|
||||
target.hp -= g.damage
|
||||
if target.hp <= 0 {
|
||||
target.hp = 0 // in case it goes negative
|
||||
g.action = actChallengerWins
|
||||
// If the target is the challenger, the match is over as well.
|
||||
if target == &g.players[1] {
|
||||
g.action = actDealerWins
|
||||
g.round = 3
|
||||
}
|
||||
return ErrRoundEnded
|
||||
}
|
||||
}
|
||||
if g.Empty() {
|
||||
g.action = actGameEnd
|
||||
return ErrGameEnded
|
||||
}
|
||||
if !self || live {
|
||||
@@ -214,8 +220,10 @@ func (g *Match) Shoot(id player.ID, self bool) error {
|
||||
func (g *Match) Concede(id player.ID) error {
|
||||
switch id {
|
||||
case g.players[0].id:
|
||||
g.action = actDealerConcedes
|
||||
g.players[0].hp = 0
|
||||
case g.players[1].id:
|
||||
g.action = actChallengerConcedes
|
||||
g.players[1].hp = 0
|
||||
default:
|
||||
return ErrWrongTurn
|
||||
@@ -227,15 +235,24 @@ func (g *Match) Concede(id player.ID) error {
|
||||
// DTO returns the current match state as viewed by the given player.
|
||||
func (g *Match) DTO(id player.ID) serve.Game {
|
||||
var live, blank int
|
||||
if g.turn == 1 {
|
||||
if g.action.gameStart() {
|
||||
live = len(g.shells) / 2
|
||||
blank = len(g.shells) - live
|
||||
}
|
||||
w := serve.NoWinner
|
||||
switch g.RoundWinner() {
|
||||
case &g.players[0]:
|
||||
w = serve.DealerWins
|
||||
case &g.players[1]:
|
||||
w = serve.ChallengerWins
|
||||
}
|
||||
return serve.Game{
|
||||
Players: [2]serve.Player{
|
||||
g.players[0].DTO(),
|
||||
g.players[1].DTO(),
|
||||
},
|
||||
Action: g.action.String(),
|
||||
Winner: w,
|
||||
Round: g.round,
|
||||
Dealer: g.CurrentPlayer() == &g.players[0],
|
||||
Damage: g.damage,
|
||||
|
@@ -446,6 +446,7 @@ func TestGameDTO(t *testing.T) {
|
||||
g.players[0].DTO(),
|
||||
g.players[1].DTO(),
|
||||
},
|
||||
Action: "Start",
|
||||
Round: g.round,
|
||||
Dealer: false,
|
||||
Damage: g.damage,
|
||||
@@ -471,6 +472,7 @@ func TestGameDTO(t *testing.T) {
|
||||
g.players[0].DTO(),
|
||||
g.players[1].DTO(),
|
||||
},
|
||||
Action: "Shoot",
|
||||
Round: g.round,
|
||||
Dealer: true,
|
||||
Damage: g.damage,
|
||||
@@ -489,6 +491,7 @@ func TestGameDTO(t *testing.T) {
|
||||
t.Errorf("observer sees the wrong thing:\nwant %+v\ngot %+v", want, got)
|
||||
}
|
||||
}
|
||||
// TODO(zeph): many more tests about actions
|
||||
}
|
||||
|
||||
func deref[T any, P ~*T](p P) (x T) {
|
||||
|
15
game/item.go
15
game/item.go
@@ -20,9 +20,8 @@ func (i Item) Apply(g *Match) bool {
|
||||
case ItemNone:
|
||||
return false
|
||||
case ItemLens:
|
||||
if g.reveal {
|
||||
return false
|
||||
}
|
||||
// Lenses are always used, even if they have no effect.
|
||||
g.action = actLens
|
||||
g.reveal = true
|
||||
return true
|
||||
case ItemCig:
|
||||
@@ -31,10 +30,13 @@ func (i Item) Apply(g *Match) bool {
|
||||
cur.hp++
|
||||
// Cigs are always used, even if they have no effect.
|
||||
}
|
||||
g.action = actCig
|
||||
return true
|
||||
case ItemBeer:
|
||||
g.popShell()
|
||||
g.action = actBeer
|
||||
if g.Empty() {
|
||||
g.action = actBeerGameEnd
|
||||
g.NextGame()
|
||||
}
|
||||
return true
|
||||
@@ -43,12 +45,14 @@ func (i Item) Apply(g *Match) bool {
|
||||
if opp.cuffs != Uncuffed {
|
||||
return false
|
||||
}
|
||||
g.action = actCuff
|
||||
opp.cuffs = Cuffed
|
||||
return true
|
||||
case ItemKnife:
|
||||
if g.damage != 1 {
|
||||
return false
|
||||
}
|
||||
g.action = actKnife
|
||||
g.damage = 2
|
||||
return true
|
||||
default:
|
||||
@@ -56,7 +60,8 @@ func (i Item) Apply(g *Match) bool {
|
||||
}
|
||||
}
|
||||
|
||||
var itemNames = [...]string{"", "🔍", "🚬", "🍺", "👮", "🔪"}
|
||||
|
||||
func (i Item) String() string {
|
||||
s := [...]string{"", "🔍", "🚬", "🍺", "👮", "🔪"}
|
||||
return s[i]
|
||||
return itemNames[i]
|
||||
}
|
||||
|
Reference in New Issue
Block a user