规则、卡包与测试放在同一套核心里,避免表现层自行结算。 Co-authored-by: Cursor <cursoragent@cursor.com>
85 lines
2.9 KiB
C#
85 lines
2.9 KiB
C#
using CardGame.Core;
|
|
using Xunit;
|
|
|
|
namespace Game.Core.Tests;
|
|
|
|
public sealed class PhaseBTests
|
|
{
|
|
private static GameState NewMatch(CardDefinition card, int count = 10) =>
|
|
MatchSetup.Create(11, Cards.Repeat(card, count), Cards.Repeat(card, count), Cards.Catalog, shuffle: false);
|
|
|
|
[Fact]
|
|
public void Opening_draw_and_base_supply()
|
|
{
|
|
var state = NewMatch(Cards.Wisp);
|
|
Assert.Equal(4, state.Players[0].Hand.Count);
|
|
Assert.Equal(3, state.Players[1].Hand.Count);
|
|
Assert.Equal(1, state.Players[0].Energy);
|
|
}
|
|
|
|
[Fact]
|
|
public void Play_creature_pays_current_cost()
|
|
{
|
|
var state = NewMatch(Cards.Wisp);
|
|
var wisp = state.Players[0].Hand[0];
|
|
state = RulesEngine.Execute(state, new PlayCardAction(0, wisp.Id));
|
|
Assert.Equal(0, state.Players[0].Energy);
|
|
Assert.Contains(state.Board, e => e.Id == wisp.Id && e.Zone == Zone.Board);
|
|
Assert.Equal(0, state.Find(wisp.Id)!.AttacksRemaining);
|
|
}
|
|
|
|
[Fact]
|
|
public void Spell_damages_and_goes_to_graveyard()
|
|
{
|
|
var state = NewMatch(Cards.Spark);
|
|
var spark = state.Players[0].Hand[0];
|
|
state = RulesEngine.Execute(state, new PlayCardAction(0, spark.Id, new PlayerTarget(1)));
|
|
Assert.Equal(19, state.Players[1].Life);
|
|
Assert.Contains(state.Players[0].Graveyard, e => e.Id == spark.Id);
|
|
}
|
|
|
|
[Fact]
|
|
public void Creature_attacks_after_summoning_sickness()
|
|
{
|
|
var state = NewMatch(Cards.Wisp, 20);
|
|
var wisp = state.Players[0].Hand[0];
|
|
state = RulesEngine.Execute(state, new PlayCardAction(0, wisp.Id));
|
|
Assert.DoesNotContain(RulesEngine.GetLegalActions(state), a => a is AttackAction);
|
|
|
|
state = RulesEngine.Execute(state, new EndTurnAction(0));
|
|
state = RulesEngine.Execute(state, new EndTurnAction(1));
|
|
|
|
var attacker = state.Board.Single(e => e.ControllerIndex == 0 && e.Definition.Id == Cards.Wisp.Id);
|
|
state = RulesEngine.Execute(state, new AttackAction(0, attacker.Id, new PlayerTarget(1)));
|
|
Assert.Equal(19, state.Players[1].Life);
|
|
}
|
|
|
|
[Fact]
|
|
public void Shared_board_caps_at_ten()
|
|
{
|
|
var state = NewMatch(Cards.Wisp, 30);
|
|
for (var turn = 0; turn < 8 && !state.IsOver; turn++)
|
|
{
|
|
while (true)
|
|
{
|
|
var play = RulesEngine.GetLegalActions(state).OfType<PlayCardAction>().FirstOrDefault();
|
|
if (play is null)
|
|
{
|
|
break;
|
|
}
|
|
|
|
state = RulesEngine.Execute(state, play);
|
|
}
|
|
|
|
if (state.IsOver)
|
|
{
|
|
break;
|
|
}
|
|
|
|
state = RulesEngine.Execute(state, new EndTurnAction(state.ActivePlayerIndex));
|
|
}
|
|
|
|
Assert.True(state.Board.Count(e => e.Definition.Type != CardType.FieldCard || !e.IsSystem) <= GameState.BoardCapacity);
|
|
}
|
|
}
|