规则、卡包与测试放在同一套核心里,避免表现层自行结算。 Co-authored-by: Cursor <cursoragent@cursor.com>
91 lines
2.9 KiB
C#
91 lines
2.9 KiB
C#
using System.Collections.Immutable;
|
|
|
|
namespace CardGame.Core;
|
|
|
|
public sealed class RunStats
|
|
{
|
|
public int HealReceived { get; set; }
|
|
public int AttacksDeclared { get; set; }
|
|
public int FriendlyDestroyed { get; set; }
|
|
public int FatigueTicks { get; set; }
|
|
public Dictionary<string, int> KillsByTag { get; } = new(StringComparer.Ordinal);
|
|
|
|
public int Kills(string tag) => KillsByTag.GetValueOrDefault(tag);
|
|
|
|
public RunStats Clone()
|
|
{
|
|
var copy = new RunStats
|
|
{
|
|
HealReceived = HealReceived,
|
|
AttacksDeclared = AttacksDeclared,
|
|
FriendlyDestroyed = FriendlyDestroyed,
|
|
FatigueTicks = FatigueTicks
|
|
};
|
|
foreach (var (key, value) in KillsByTag)
|
|
{
|
|
copy.KillsByTag[key] = value;
|
|
}
|
|
|
|
return copy;
|
|
}
|
|
}
|
|
|
|
public enum PackConditionKind
|
|
{
|
|
HealReceivedAtLeast,
|
|
AttacksAtLeast,
|
|
FriendlyDestroyedAtLeast,
|
|
FatigueAtLeast,
|
|
DeckTagAtLeast,
|
|
KillTagAtLeast
|
|
}
|
|
|
|
public sealed record PackCondition(PackConditionKind Kind, int Amount = 0, string? Tag = null);
|
|
|
|
public sealed record PackDefinition(
|
|
string Id,
|
|
string Name,
|
|
bool Base,
|
|
ImmutableArray<string> CoreActions,
|
|
ImmutableArray<string> Cards,
|
|
ImmutableArray<PackCondition> AllOf);
|
|
|
|
public static class Packs
|
|
{
|
|
public static bool IsUnlocked(GameState state, int playerIndex, PackDefinition pack)
|
|
{
|
|
if (pack.Base)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return pack.AllOf.All(c => Met(state, playerIndex, c));
|
|
}
|
|
|
|
public static IReadOnlyList<PackDefinition> Unlocked(GameState state, int playerIndex, IEnumerable<PackDefinition> catalog) =>
|
|
catalog.Where(p => IsUnlocked(state, playerIndex, p)).ToList();
|
|
|
|
public static int CountTag(GameState state, int playerIndex, string tag)
|
|
{
|
|
var player = state.Players[playerIndex];
|
|
return player.Deck.Concat(player.Hand).Concat(player.Graveyard)
|
|
.Concat(state.Board.Where(e => e.ControllerIndex == playerIndex))
|
|
.Count(e => e.Definition.HasTag(tag));
|
|
}
|
|
|
|
private static bool Met(GameState state, int playerIndex, PackCondition condition)
|
|
{
|
|
var run = state.Players[playerIndex].Run;
|
|
return condition.Kind switch
|
|
{
|
|
PackConditionKind.HealReceivedAtLeast => run.HealReceived >= condition.Amount,
|
|
PackConditionKind.AttacksAtLeast => run.AttacksDeclared >= condition.Amount,
|
|
PackConditionKind.FriendlyDestroyedAtLeast => run.FriendlyDestroyed >= condition.Amount,
|
|
PackConditionKind.FatigueAtLeast => run.FatigueTicks >= condition.Amount,
|
|
PackConditionKind.DeckTagAtLeast => CountTag(state, playerIndex, condition.Tag ?? "") >= condition.Amount,
|
|
PackConditionKind.KillTagAtLeast => run.Kills(condition.Tag ?? "") >= condition.Amount,
|
|
_ => false
|
|
};
|
|
}
|
|
}
|