diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2023-02-08 12:06:18 +0100 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2025-08-20 15:50:09 +0200 |
| commit | bba94a6dbd5a5f0695e36c5fcb7a06a961321d82 (patch) | |
| tree | 9e8b087981b6c8d25f5c8beae20538651bcd1220 | |
| parent | a1f257846d6e496cd9c5ba36eff1624e52821d7d (diff) | |
| download | muhqs-game-bba94a6dbd5a5f0695e36c5fcb7a06a961321d82.tar.gz muhqs-game-bba94a6dbd5a5f0695e36c5fcb7a06a961321d82.zip | |
implement TargetSelection and card targeting
| -rw-r--r-- | go/game/action.go | 10 | ||||
| -rw-r--r-- | go/game/targets.go | 127 |
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) }) } |
