From 844f349fdf24d93e846f5a0b7f779116733a3c93 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Fri, 15 Aug 2025 16:51:07 +0200 Subject: improve timing of declared actions --- go/game/action.go | 1 + go/game/state.go | 48 ++++++++++++++++++++++++++++++------------------ go/game/state_test.go | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 20 deletions(-) (limited to 'go/game') diff --git a/go/game/action.go b/go/game/action.go index d2c46928..1b89265d 100644 --- a/go/game/action.go +++ b/go/game/action.go @@ -226,6 +226,7 @@ func (a *PileDropAction) String() string { return s[:len(s)-1] + " ]" } +func (*PileDropAction) Speed() ActionSpeed { return fast } func (*PileDropAction) PayCosts(*LocalState) bool { return true } func newPileDropAction(perm Permanent, tile *Tile, pile []Permanent) *PileDropAction { diff --git a/go/game/state.go b/go/game/state.go index b72da192..fd79b114 100644 --- a/go/game/state.go +++ b/go/game/state.go @@ -357,7 +357,6 @@ func (s *LocalState) isValidBuy(a *BuyAction) error { return fmt.Errorf("%s' controls no unit on a store containing %s", a.player.Name, card.Name) } - } else if !slices.Contains(a.player.Store.cards, card) { return fmt.Errorf("%s's store does not contain %s", a.player.Name, card.Name) } @@ -458,35 +457,48 @@ func (s *LocalState) pushAction(a Action) { s.stack.push(a) } -type ErrDeclareSlowAction struct { +type ErrDeclareAction struct { reason string } -func (err ErrDeclareSlowAction) Error() string { +func (err ErrDeclareAction) Error() string { return err.reason } +var ( + ErrDeclareActionWrongPhase = ErrDeclareAction{"wrong phase"} + ErrDeclareActionStackNotEmpty = ErrDeclareAction{"stack not empty"} +) + +func (s *LocalState) checkActionTiming(a Action) error { + switch a.(type) { + case *BuyAction: + if s.activePhase != Phases.BuyPhase || s.activePlayerId != a.Controller().Id { + return ErrDeclareActionWrongPhase + } + case *UpkeepAction: + if s.activePhase != Phases.UpkeepPhase || s.activePlayerId != a.Controller().Id { + return ErrDeclareActionWrongPhase + } + default: + if a.Speed() == ActionSpeeds.Slow { + if !s.stack.IsEmpty() { + return ErrDeclareActionStackNotEmpty + } else if s.activePlayerId != a.Controller().Id || s.activePhase != Phases.ActionPhase { + return ErrDeclareActionWrongPhase + } + } + } + return nil +} + func (s *LocalState) declareAction(a Action) { var err error err = a.CheckTargets(s) if err == nil { - switch a.(type) { - case *BuyAction: - if s.activePhase != Phases.BuyPhase { - err = errors.New("cards can only be bought during one's buy phase") - } - case *FreeAction: - default: - if a.Speed() == ActionSpeeds.Slow { - if !s.stack.IsEmpty() { - err = ErrDeclareSlowAction{"stack not empty"} - } else if s.activePlayerId != a.Controller().Id || s.activePhase != Phases.ActionPhase { - err = ErrDeclareSlowAction{"not action phase"} - } - } - } + err = s.checkActionTiming(a) } if err == nil { diff --git a/go/game/state_test.go b/go/game/state_test.go index ad7fdca7..6a9d6eb8 100644 --- a/go/game/state_test.go +++ b/go/game/state_test.go @@ -6,17 +6,47 @@ import ( func TestDeclareActions(t *testing.T) { s := NewLocalState() - s.SetMap(newEmpty2x2Map()) + m := newEmpty2x2Map() + s.SetMap(m) + p := s.AddNewPlayer("p", NewDeck()) + p.Store.AddCard(NewCard("base/sword")) p.Ctrl = newMockPlayerControl(p) o := s.AddNewPlayer("o", NewDeck()) o.Ctrl = newMockPlayerControl(o) + a := s.addNewUnit(NewCard("base/archer"), Position{0, 0}, p) k := s.addNewUnit(NewCard("base/knight"), Position{1, 1}, o) + sa := NewAttackAction(a) sa.Target().AddSelection(k) s.declareAction(sa) if !s.stack.IsEmpty() { - t.Fatal("declared slow action during upkeep") + t.Fatal("declared attack action during upkeep") + } + + ma := NewMoveAction(a) + ma.Target().AddSelection(m.TileAt(Position{1, 0})) + s.declareAction(ma) + if !s.stack.IsEmpty() { + t.Fatal("declared move action during upkeep") + } + + ba := newBuyAction(p) + ba.Target().AddSelection(p.Store.Cards()[0]) + s.declareAction(ba) + if !s.stack.IsEmpty() { + t.Fatal("declared buy action during upkeep") + } + + s.activePhase = Phases.ActionPhase + s.declareAction(sa) + if s.stack.IsEmpty() { + t.Fatal("attack action not declared") + } + + s.declareAction(ma) + if len(s.stack.Actions) == 2 { + t.Fatal("declared move action with non empty stack") } } -- cgit v1.2.3