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