落地无头规则引擎与局内内容,便于命令行复现对战。
规则、卡包与测试放在同一套核心里,避免表现层自行结算。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user