Files
card_game/src/Game.Core/Packs.cs
T
chenmoranzhiandCursor ae13f1d06a 落地无头规则引擎与局内内容,便于命令行复现对战。
规则、卡包与测试放在同一套核心里,避免表现层自行结算。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-09 02:06:23 +08:00

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
};
}
}