aboutsummaryrefslogtreecommitdiff
path: root/go
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2023-02-08 12:06:18 +0100
committerFlorian Fischer <florian.fischer@muhq.space>2025-08-20 15:50:09 +0200
commitbba94a6dbd5a5f0695e36c5fcb7a06a961321d82 (patch)
tree9e8b087981b6c8d25f5c8beae20538651bcd1220 /go
parenta1f257846d6e496cd9c5ba36eff1624e52821d7d (diff)
downloadmuhqs-game-bba94a6dbd5a5f0695e36c5fcb7a06a961321d82.tar.gz
muhqs-game-bba94a6dbd5a5f0695e36c5fcb7a06a961321d82.zip
implement TargetSelection and card targeting
Diffstat (limited to 'go')
-rw-r--r--go/game/action.go10
-rw-r--r--go/game/targets.go127
2 files changed, 104 insertions, 33 deletions
diff --git a/go/game/action.go b/go/game/action.go
index fbcad0a7..a283bbfb 100644
--- a/go/game/action.go
+++ b/go/game/action.go
@@ -40,6 +40,16 @@ func (*HandCardSelection) Resolve(*State) {}
func (*HandCardSelection) String() string { return "hand card selection" }
func NewHandCardSelection(cards []*Card) Action { return &HandCardSelection{cards} }
+type TargetSelection struct{ targets *Targets }
+
+func (*TargetSelection) Source() interface{} { return nil }
+func (sel *TargetSelection) Targets() *Targets { return sel.targets }
+func (sel *TargetSelection) CheckTargets(s *State) error { return sel.targets.CheckTargets(s) }
+func (*TargetSelection) PayCosts(*State) bool { return true }
+func (*TargetSelection) Resolve(*State) {}
+func (*TargetSelection) String() string { return "target selection" }
+func NewTargetSelection(targets *Targets) Action { return &TargetSelection{targets} }
+
type ActionBase struct {
source interface{}
Card *Card
diff --git a/go/game/targets.go b/go/game/targets.go
index 7803c2c8..eb429c8c 100644
--- a/go/game/targets.go
+++ b/go/game/targets.go
@@ -121,6 +121,8 @@ func targetConstraint(desc string, s *State, action Action) TargetConstraintFunc
constraints = append(constraints, parseArtifactTargetConstraint(desc, s, action)...)
} else if strings.Contains(desc, "tile") {
constraints = append(constraints, parseTileTargetConstraint(desc, s, action)...)
+ } else if strings.Contains(desc, "card") {
+ constraints = append(constraints, parseCardTargetConstraint(desc, s, action)...)
// } else if strings.Contains("action") {
// constraints = append(constraints, parseActionTargetConstraint(desc, s, action)...)
// } else if strings.Contains("spell") {
@@ -199,14 +201,24 @@ func rangeTargetConstraint(source interface{}, r int) TargetConstraintFunc {
}
}
-var permanentTargetConstraint TargetConstraintFunc = func(t interface{}) (err error) {
- _, ok := t.(Permanent)
- if !ok {
- err = fmt.Errorf("target is %T not Permanent", t)
+func typeTargetConstrain[T any](typeDesc string) TargetConstraintFunc {
+ return func(t interface{}) (err error) {
+ _, ok := t.(T)
+ if !ok {
+ err = fmt.Errorf("unexpected target type %T not %s", t, typeDesc)
+ }
+ return
}
- return
}
+var (
+ permanentTargetConstraint TargetConstraintFunc = typeTargetConstrain[Permanent]("Permanent")
+ unitTargetConstraint TargetConstraintFunc = typeTargetConstrain[*Unit]("*Unit")
+ tileTargetConstraint TargetConstraintFunc = typeTargetConstrain[*Tile]("*Tile")
+ artifactTargetConstraint TargetConstraintFunc = typeTargetConstrain[*Artifact]("*Artifact")
+ cardTargetConstraint TargetConstraintFunc = typeTargetConstrain[*Card]("*Card")
+)
+
func parsePermanentTargetConstraint(desc string, s *State, action Action) []TargetConstraintFunc {
constraints := []TargetConstraintFunc{permanentTargetConstraint}
@@ -224,20 +236,12 @@ func parsePermanentTargetConstraint(desc string, s *State, action Action) []Targ
if err != nil {
log.Fatalf("Invalid range %s in target constraint %s", tokens[1], desc)
}
- constraints = append(constraints, rangeTargetConstraint(action, r))
+ constraints = append(constraints, rangeTargetConstraint(action.Source(), r))
}
return constraints
}
-var unitTargetConstraint TargetConstraintFunc = func(t interface{}) (err error) {
- _, ok := t.(*Unit)
- if !ok {
- err = fmt.Errorf("target is %T not *Unit", t)
- }
- return
-}
-
func parseUnitTargetConstraint(desc string, s *State, action Action) []TargetConstraintFunc {
constraints := []TargetConstraintFunc{unitTargetConstraint}
@@ -251,20 +255,12 @@ func parseUnitTargetConstraint(desc string, s *State, action Action) []TargetCon
if err != nil {
log.Fatalf("Invalid range %s in target constraint %s", tokens[1], desc)
}
- constraints = append(constraints, rangeTargetConstraint(action, r))
+ constraints = append(constraints, rangeTargetConstraint(action.Source(), r))
}
return constraints
}
-var artifactTargetConstraint TargetConstraintFunc = func(t interface{}) (err error) {
- _, ok := t.(*Artifact)
- if !ok {
- err = fmt.Errorf("target is %T not *Artifact", t)
- }
- return
-}
-
func parseArtifactTargetConstraint(constraint string, s *State, action Action) []TargetConstraintFunc {
constraints := []TargetConstraintFunc{artifactTargetConstraint}
return constraints
@@ -289,14 +285,6 @@ func relaxedTileTarget(action Action, t interface{}) *Tile {
return nil
}
-var tileTargetConstraint TargetConstraintFunc = func(t interface{}) (err error) {
- _, ok := t.(*Tile)
- if !ok {
- err = fmt.Errorf("target is %T not *Tile", t)
- }
- return
-}
-
func parseTileTargetConstraint(desc string, s *State, action Action) []TargetConstraintFunc {
constraints := []TargetConstraintFunc{}
@@ -338,7 +326,7 @@ func parseTileTargetConstraint(desc string, s *State, action Action) []TargetCon
if slices.Contains(s.AvailableSpawnTiles(player, card), tile) {
return nil
}
- return fmt.Errorf("tile %s is no spawn tile", tile)
+ return fmt.Errorf("tile %v is no spawn tile", tile)
})
}
@@ -353,7 +341,80 @@ func parseTileTargetConstraint(desc string, s *State, action Action) []TargetCon
if tile.IsAvailableForCard(card) {
return nil
}
- return fmt.Errorf("tile %s is not available for %s", tile, card.Name)
+ return fmt.Errorf("tile %v is not available for %s", tile, card.Name)
+ })
+ }
+
+ if strings.Contains(desc, "water") {
+ constraints = append(constraints, func(t interface{}) (err error) {
+ tile := t.(*Tile)
+ if tile.Water {
+ return nil
+ }
+ return fmt.Errorf("tile %v is not a water tile", tile)
+ })
+ }
+
+ if strings.Contains(desc, "adjacent") {
+ constraints = append(constraints, rangeTargetConstraint(action.Source(), 1))
+ }
+
+ return constraints
+}
+
+func parseCardTargetConstraint(desc string, s *State, action Action) []TargetConstraintFunc {
+ constraints := []TargetConstraintFunc{cardTargetConstraint}
+
+ player := action.Source().(*Player)
+ origins := []*Player{player}
+ originDesc := player.Name + "'s"
+
+ if strings.Contains(desc, "opponent") {
+ originDesc = "a opponent's"
+ origins = []*Player{}
+ for _, p := range s.Players {
+ if p.IsEnemy(player) {
+ origins = append(origins, p)
+ }
+ }
+ }
+
+ if strings.Contains(desc, "hand") || strings.Contains(desc, "store") ||
+ strings.Contains(desc, "discard pile") {
+
+ if player == nil {
+ log.Fatalf("Not implemented PileOfCards constraint for %T", action)
+ }
+
+ var pocs []PileOfCards
+ pocDesc := ""
+ if strings.Contains(desc, "hand") {
+ pocDesc = "hand"
+ } else if strings.Contains(desc, "store") {
+ pocDesc = "store"
+ } else if strings.Contains(desc, "discard pile") {
+ pocDesc = "discard pile"
+ }
+
+ for _, p := range origins {
+ switch pocDesc {
+ case "hand":
+ pocs = append(pocs, p.Hand)
+ case "store":
+ pocs = append(pocs, p.Store)
+ case "discard pile":
+ pocs = append(pocs, p.DiscardPile)
+ }
+ }
+
+ constraints = append(constraints, func(t interface{}) (err error) {
+ c := t.(*Card)
+ for _, poc := range pocs {
+ if poc.Contains(c) {
+ return nil
+ }
+ }
+ return fmt.Errorf("card %s is not in %s %s", c.Name, originDesc, pocDesc)
})
}