package game import ( "strings" "testing" "muhq.space/muhqs-game/go/utils" ) func TestTileTargets(t *testing.T) { mapDef := `map: |+1 HSTS HSFS TSWD symbols: T: tower H: house F: farm S: street W: deep water D: docks ` s := NewLocalState() m, _ := readMap(strings.NewReader(mapDef)) s.SetMap(m) p := s.AddNewPlayer("player", NewDeck()) u := s.addNewUnit(NewCard("base/archer"), Position{1, 1}, p) s.addNewUnit(NewCard("base/cavalry"), Position{1, 2}, p) a := newFullAction(u, func(Action) ActionResolveFunc { var f ActionResolveFunc; return f }, "mock full action") tDesc := newTargetDesc("tile") trgt := newTarget(s, tDesc, a) opts := trgt.Options() if len(opts) != 12 { t.Fatal("expexted 12 candidates not:", len(opts)) } tDesc = newTargetDesc("water tile") trgt = newTarget(s, tDesc, a) opts = trgt.Options() if len(opts) != 1 { t.Fatal("expected 1 water candidates not:", len(opts)) } tDesc = newTargetDesc("free tile") trgt = newTarget(s, tDesc, a) opts = trgt.Options() if len(opts) != 10 { t.Fatal("expected 10 free candidates not:", len(opts)) } tDesc = newTargetDesc("available tile") trgt = newTarget(s, tDesc, a) opts = trgt.Options() if len(opts) != 9 { t.Fatal("expected 9 available candidates not:", len(opts)) } tDesc = newTargetDesc("adjacent tile") trgt = newTarget(s, tDesc, a) opts = trgt.Options() if len(opts) != 9 { t.Fatal("expected 9 available candidates not:", len(opts)) } tDesc = newTargetDesc("adjacent available tile") trgt = newTarget(s, tDesc, a) opts = trgt.Options() if len(opts) != 6 { t.Fatal("expected 6 available candidates not:", len(opts)) } fisher := NewCard("nautics/fisher") p.Hand.AddCard(fisher) pa := NewPlayAction(p, fisher) opts = pa.Target().Options() if len(opts) != 1 { t.Fatal("expected 1 available candidates not:", len(opts)) } } func TestSpawnTargets(t *testing.T) { s := NewLocalState() m, _ := GetMap("the-kraken") s.SetMap(m) s.activePhase = actionPhase p := s.AddNewPlayer("player", NewDeck()) ctrl := newMockPlayerControl(p) ctrl.actionToSend = NewPassPriority(p) p.Ctrl = ctrl p.gainResource(2) farmer := NewCard("misc/farmer") p.Hand.AddCard(farmer) fisher := NewCard("nautics/fisher") p.Hand.AddCard(fisher) pa := NewPlayAction(p, farmer) if !pa.Target().RequireSelection() { t.Fatal("playing farmer has not require selection") } if !pa.Target().AllowSelection() { t.Fatal("playing farmer has no valid targets") } farmerPos := Position{3, 13} err := pa.Target().AddSelection(m.TileAt(farmerPos)) if err != nil { t.Fatal("Not allowed to play farmer at:", farmerPos) } s.declareAction(pa) if s.stack.IsEmpty() { t.Fatal("farmer play action not declared") } s.stack.resolve() pa2 := NewPlayAction(p, fisher) if !pa2.Target().RequireSelection() { t.Fatal("playing fisher has not require selection") } if !pa2.Target().AllowSelection() { t.Fatal("playing fisher has no valid targets") } fisherPos := Position{3, 10} pa2.Target().AddSelection(m.TileAt(fisherPos)) if err != nil { t.Fatal("Not allowed to play fisher at:", fisherPos) } s.declareAction(pa2) if s.stack.IsEmpty() { t.Fatal("fisher play action not declared") } s.stack.resolve() } func TestFlexAttackTargets(t *testing.T) { mapDef := `map: |+1 HSTS HSFS TSWS symbols: T: tower H: house F: farm S: street W: deep water ` s := NewLocalState() m, _ := readMap(strings.NewReader(mapDef)) s.SetMap(m) p := s.AddNewPlayer("player", NewDeck()) o := s.AddNewPlayer("oponent", NewDeck()) u := s.addNewUnit(NewCard("base/pikeman"), Position{1, 1}, p) s.addNewUnit(NewCard("base/pikeman"), Position{0, 0}, o) s.addNewUnit(NewCard("base/pikeman"), Position{3, 1}, o) s.addNewUnit(NewCard("base/cavalry"), Position{3, 2}, o) a := NewAttackAction(u) opts := a.Target().Options() if len(opts) != 2 { t.Fatal("expected 2 attackable options") } } func TestDisjunction(t *testing.T) { mapDef := `map: |+1 HST HSF TSW symbols: T: tower H: house F: farm S: street W: deep water ` s := NewLocalState() m, _ := readMap(strings.NewReader(mapDef)) s.SetMap(m) p := s.AddNewPlayer("player", NewDeck()) pioneer := NewUnit(NewCard("base/pioneer"), s.Map().TileAt(Position{1, 1}), p) s.addPermanent(pioneer) sword := newEquipmentFromPath("base/sword", s.Map().TileAt(Position{0, 1}), p) s.addPermanent(sword) fa := pioneer.FullActions[0] targets := fa.Targets() if err := targets.AddSelection(s.Map().TileAt(Position{1, 1})); err != nil { t.Fatalf("TileAt(1,1) not a valid target for %v", fa) } if err := targets.CheckTargets(s); err != nil { t.Fatalf("TileAt(1,1) not a valid target for %v", fa) } targets.ClearSelections() if err := targets.AddSelection(sword); err != nil { t.Fatalf("%v not a valid target for %v", sword, fa) } if err := targets.CheckTargets(s); err != nil { t.Fatalf("%v not a valid target for %v", sword, fa) } } func TestUnitConstraint(t *testing.T) { s, _, p, o := newMockState() a := s.addNewUnit(NewCard("base/archer"), Position{0, 0}, p) oa := s.addNewUnit(NewCard("base/archer"), Position{1, 1}, o) desc := newTargetDesc("enemy unit") // Use a dummy pass action to pass the player to the target constraints target := newTarget(s, desc, NewPassPriority(p)) options := target.Options() if !utils.InterfaceSliceContains(options, oa) { t.Fatal("enemy units does not contain opponent's archer") } if utils.InterfaceSliceContains(options, a) { t.Fatal("enemy units contain own archer") } desc = newTargetDesc("allied unit") // Use a dummy pass action to pass the player to the target constraints target = newTarget(s, desc, NewPassPriority(p)) options = target.Options() if utils.InterfaceSliceContains(options, oa) { t.Fatal("'allied units' does contain opponent's archer") } if !utils.InterfaceSliceContains(options, a) { t.Fatal("'allied units' does not contain own archer") } // Test for controlled units oa.changeController(p) desc = newTargetDesc("unit you control") target = newTarget(s, desc, NewPassPriority(p)) options = target.Options() if !utils.InterfaceSliceContains(options, oa) { t.Fatal("'units you control' does not contain controlled archer owned by the oponent") } if !utils.InterfaceSliceContains(options, a) { t.Fatal("'units you control' does not contain own archer") } } func TestSpellConstraint(t *testing.T) { s, _, p, _ := newMockState() spellInDiscard := NewCard("magic/more!") p.DiscardPile.AddCard(spellInDiscard) p.Resource = 3 declaredSpell := NewPlayAction(p, NewCard("magic/ritual!")) s.declareAction(declaredSpell) unit := NewPlayAction(p, NewCard("base/archer")) desc := newTargetDesc("spell") target := newTarget(s, desc, NewPassPriority(p)) if err := target.AddSelection(declaredSpell); err == nil { t.Fatal("could target declared spell") } if err := target.AddSelection(spellInDiscard); err != nil { t.Fatal("failed to target spell:", err) } if err := target.AddSelection(unit); err == nil { t.Fatal("could target unit play action:", err) } desc = newTargetDesc("declared spell") target = newTarget(s, desc, NewPassPriority(p)) if !utils.InterfaceSliceContains(target.Options(), declaredSpell) { t.Fatal("options does not contain the declared spell") } if err := target.AddSelection(declaredSpell); err != nil { t.Fatal("failed to target spell:", err) } if err := target.AddSelection(spellInDiscard); err == nil { t.Fatal("spell in discard pile is not declared:", err) } if err := target.AddSelection(unit); err == nil { t.Fatal("could target unit play action:", err) } }