namespace Vanguard.Board3D
{
///
/// Локальные правила раскладки для UX. Сервер остаётся авторитарным:
/// эти проверки нужны для подсветки и drag&drop, а не для начисления
/// результата.
///
public static class BoardPlacementRules
{
public static bool CanRide(BoardZone zone, int slot) =>
zone == BoardZone.Vanguard && slot == PlaymatLayout.VanguardSlot;
public static bool CanCall(int slot, bool occupied) =>
slot >= 0
&& slot < PlaymatLayout.RearGuardCount
&& !occupied;
public static bool CanGuard(BoardZone zone) =>
zone == BoardZone.Guardian;
public static bool CanMove(int fromSlot, int toSlot) =>
fromSlot >= 0
&& fromSlot < PlaymatLayout.RearGuardCount
&& toSlot >= 0
&& toSlot < PlaymatLayout.RearGuardCount
&& fromSlot != toSlot
&& SameColumn(fromSlot, toSlot);
public static bool CanAttack(int attackerSlot, int targetSlot) =>
attackerSlot >= PlaymatLayout.VanguardSlot
&& attackerSlot < PlaymatLayout.RearGuardCount
&& targetSlot >= PlaymatLayout.VanguardSlot
&& targetSlot < PlaymatLayout.RearGuardCount;
/// Колонки Classic: левая 0↔3, правая 2↔4; у центра пары нет.
public static bool SameColumn(int fromSlot, int toSlot) =>
(fromSlot, toSlot) is (0, 3) or (3, 0) or (2, 4) or (4, 2);
/// Call и Ride входят стоя и открытыми.
public static CardState3D EnterFromHand(CircleAttribute circle) => circle switch
{
CircleAttribute.Vanguard => CardState3D.FaceUpStand,
CircleAttribute.RearGuard => CardState3D.FaceUpStand,
CircleAttribute.Guardian => CardState3D.FaceUpStand,
_ => CardState3D.FaceUpStand,
};
/// Перемещение RC→RC сохраняет Rest и открытость.
public static CardState3D PreserveOnMove(CardState3D state) => state;
public static BoardZone ZoneOfSlot(int slot) =>
slot == PlaymatLayout.VanguardSlot
? BoardZone.Vanguard
: BoardZone.RearGuard;
}
}