namespace YD_Event.Application.JudgeScore;
///
/// 花样赛内置计分规则定义(车轮跳花样、交互绳花样)。
///
/// 只在初始化/同步规则库时使用;运行期的评分项一律从 ScoreRule / ScoreRuleItem 读取,
/// 后台调整评分项、难度分值、席位配置后无需改代码。
///
///
/// 计分口径(裁判端原型 + 花样跳绳裁判端逻辑与测试验收说明书):
/// 车轮跳花样:DA×2、DB×2、P×2、T×1;dA=(da1+da2)/2、dB=(db1+db2)/2、D=(dA+dB)/2;
/// P=average(p1,p2)×0.05;Q=max(0,1-0.05×规定元素缺失类别数);M=max(0,1-(失误+违例+间歇));
/// 总分 R=max(0, D×(1+P)×Q×M)。
/// 交互绳花样:DJ、DT、P 各可配置 1~2 名裁判,T 固定 1 名;DJ 按全部动作取均值、DT 取最高 20 个动作(分母固定 20);
/// dJ=DJ 裁判分数平均值、dT=DT 裁判分数平均值、D=dJ×1.4+dT;P=P 裁判分数平均值×0.033;
/// M=max(0,1-(失误+违例+空间违例));总分 R=max(0, D×(1+P)×M),不计 Q。
///
///
public static class FreestyleRuleDefinition
{
///
/// 车轮跳花样规则编码
///
public const string WheelRuleCode = "ROPE_FREESTYLE_WHEEL";
///
/// 车轮跳花样规则名称
///
public const string WheelRuleName = "车轮跳花样计分规则";
///
/// 交互绳花样规则编码
///
public const string WireRuleCode = "ROPE_FREESTYLE_WIRE";
///
/// 交互绳花样规则名称
///
public const string WireRuleName = "交互绳花样计分规则";
///
/// 运动员A难度裁判角色类别编码(车轮跳花样)
///
public const string RoleDifficultyA = "DA";
///
/// 运动员B难度裁判角色类别编码(车轮跳花样)
///
public const string RoleDifficultyB = "DB";
///
/// 跳绳运动员难度裁判角色类别编码(交互绳花样,按全部动作取均值)
///
public const string RoleDifficultyJumper = "DJ";
///
/// 摇绳运动员难度裁判角色类别编码(交互绳花样,取最高 20 个动作)
///
public const string RoleDifficultyTurner = "DT";
///
/// 表现裁判角色类别编码
///
public const string RolePerformance = "P";
///
/// 主裁判角色类别编码
///
public const string RoleChief = "T";
///
/// 评分对象:运动员A(车轮跳花样)
///
public const string SubjectA = "A";
///
/// 评分对象:运动员B(车轮跳花样)
///
public const string SubjectB = "B";
///
/// 表现维度的基准分。人工加减与失误自动减都在基准分上调整。
///
public const decimal PerformanceBaseValue = 12m;
///
/// 表现维度分的上限(下限为 0)
///
public const decimal PerformanceMaxValue = 24m;
///
/// 车轮跳花样、精英个人花样的表现因子系数:P = average(p1,p2) × 0.05
///
public const decimal PerformanceFactorWeight = 0.05m;
///
/// 交互绳花样的表现因子系数:P = average(p1,p2) × 0.033
///
public const decimal WirePerformanceFactorWeight = 0.033m;
///
/// 每缺 1 类规定元素的 Q 扣减系数(花样跳绳打分.xmind 明确规定 Fq=2.5%=0.025):Q = max(0, 1 - 0.025 × 缺失类别数)
///
public const decimal RequiredMissingUnit = 0.025m;
///
/// 车轮跳花样每类规定元素的要求完成数量。
///
public const decimal WheelRequiredCountPerElement = 4m;
///
/// 车轮跳花样规定元素应完成总数:4 类 × 每类 4 个。
///
public static decimal WheelRequiredTarget => WheelRequiredElements.Count * WheelRequiredCountPerElement;
///
/// 摇绳运动员难度取用的动作数(少于 20 个动作时分母仍按 20)
///
public const int TurnerTopCount = 20;
///
/// 违例、间歇、空间违例的每次扣减值
///
public const decimal ViolationUnitDeduction = 0.05m;
///
/// 失误的递增扣减序列:第 1 次 0.05、第 2 次 0.075、第 3 次起每次 0.1
///
public static readonly decimal[] FailureStepDeductions = { 0.05m, 0.075m, 0.1m };
///
/// 难度等级分值表。必须查表取值,不得用浮点公式推导。
///
public static IReadOnlyList DifficultyLevels { get; } = new List
{
new("DIFF_LEVEL_0", "0 级", 0m),
new("DIFF_LEVEL_0_5", "0.5 级", 0.12m),
new("DIFF_LEVEL_1", "1 级", 0.15m),
new("DIFF_LEVEL_2", "2 级", 0.23m),
new("DIFF_LEVEL_3", "3 级", 0.34m),
new("DIFF_LEVEL_4", "4 级", 0.51m),
new("DIFF_LEVEL_5", "5 级", 0.76m),
new("DIFF_LEVEL_6", "6 级", 1.14m),
new("DIFF_LEVEL_7", "7 级", 1.71m),
new("DIFF_LEVEL_8", "8 级", 2.56m)
};
///
/// 交互绳跳绳运动员难度等级。间歇单独按0级记录;1~5级均支持减号、标准和加号档。
/// 减号按 x-0.25、加号按 x+0.5 换算,分值为 L(x)=1.5^x,保留4位小数。
///
public static IReadOnlyList WireJumperDifficultyLevels { get; } =
BuildWireDifficultyLevels(includeBreak: true);
///
/// 交互绳摇绳运动员难度等级。1~5级均支持减号、标准和加号档。
///
public static IReadOnlyList WireTurnerDifficultyLevels { get; } =
BuildWireDifficultyLevels(includeBreak: false);
///
/// 表现五维。权重合计必须为 1,页面按此顺序展示。
///
public static IReadOnlyList PerformanceDimensions { get; } = new List
{
new("MUSIC", "音乐", 0.20m),
new("QUALITY", "完成质量", 0.25m),
new("ENTERTAINMENT", "娱乐", 0.25m),
new("CREATIVITY", "创意", 0.15m),
new("VARIETY", "多样性", 0.15m)
};
///
/// 取消比赛资格原因,与裁判端原型逐字一致
///
public static IReadOnlyList DisqualifyReasons { get; } = new List
{
new("DQ_DISCIPLINE", "违反赛场纪律"),
new("DQ_MEMBER_COUNT", "参赛人员不符合规定(不足或超过)"),
new("DQ_NO_ROPE_SHOES", "未穿跳绳鞋"),
new("DQ_EXTERNAL_AID", "使用外部助力器材"),
new("DQ_UNCIVILIZED", "比赛中嚼口香糖/不文明用语等"),
new("DQ_ANTI_OLYMPIC", "有悖奥林匹克精神的元素(描绘暴力、战争、宗教、色情有关的元素)"),
new("DQ_LATE_60S", "运动员(队)被叫超过60秒未上场"),
new("DQ_TATTOO", "显露纹身")
};
///
/// 车轮跳花样的规定元素类别,只要该类别有动作即计一类完成
///
public static IReadOnlyList WheelRequiredElements { get; } = new List
{
new("REQ_STRENGTH_GYMNASTICS", "力量和体操"),
new("REQ_MULTIPLE_ROPE", "多摇"),
new("REQ_ROPE_MANIPULATION", "绳子运用"),
new("REQ_INTERACTION", "互动配合")
};
///
/// 个人花样/同步花样裁判席位配置:DP/DM/DR 难度裁判各 1~2 人、表现裁判 1~2 人、主裁 1 人
///
public const string SingleJudgeRoleSchemaJson = """
[{"title":"主裁判","slots":[{"code":"T","name":"主裁判-T","min":1,"max":1}]},{"title":"难度裁判","slots":[{"code":"DP","name":"难度裁判-DP(力量体操裁判)","min":1,"max":2},{"code":"DM","name":"难度裁判-DM(多摇裁判)","min":1,"max":2},{"code":"DR","name":"难度裁判-DR(绳子运用裁判)","min":1,"max":2}]},{"title":"表现裁判","slots":[{"code":"P","name":"表现裁判-P","min":1,"max":2}]}]
""";
///
/// 车轮跳花样裁判席位配置:运动员A/B难度裁判各 1~2 人、表现裁判 1~2 人、主裁 1 人
///
public const string WheelJudgeRoleSchemaJson = """
[{"title":"主裁判","slots":[{"code":"T","name":"主裁判-T","min":1,"max":1}]},{"title":"难度裁判","slots":[{"code":"DA","name":"难度裁判-DA(运动员A难度裁判)","min":1,"max":2},{"code":"DB","name":"难度裁判-DB(运动员B难度裁判)","min":1,"max":2}]},{"title":"表现裁判","slots":[{"code":"P","name":"表现裁判-P","min":1,"max":2}]}]
""";
///
/// 交互绳花样裁判席位配置:跳绳者/摇绳者难度裁判各 1~2 人、表现裁判 1~2 人、主裁 1 人
///
public const string WireJudgeRoleSchemaJson = """
[{"title":"主裁判","slots":[{"code":"T","name":"主裁判-T","min":1,"max":1}]},{"title":"难度裁判","slots":[{"code":"DJ","name":"难度裁判-DJ(跳绳运动员难度裁判)","min":1,"max":2},{"code":"DT","name":"难度裁判-DT(摇绳运动员难度裁判)","min":1,"max":2}]},{"title":"表现裁判","slots":[{"code":"P","name":"表现裁判-P","min":1,"max":2}]}]
""";
///
/// 车轮跳花样计分参数配置。
/// totalMode=factor 表示按 R = D × (1 + P) × Q × M 相乘;difficultyDivisor=2 对应 D=(dA+dB)/2;
/// 主裁同时承担 Q(规定元素缺失数)与 M(扣分合计)两个因子,因此配置了两条 T。
///
public const string WheelRuleConfigJson = """
{"ruleType":"FREESTYLE_WHEEL","totalMode":"factor","baseScore":0,"scoreDecimals":2,"difficultyDivisor":2,"correctionNeedApproval":false,"roleAggregations":[{"roleType":"DA","symbol":"dA","label":"运动员A难度","sourceField":"DifficultyScore","targetField":"DifficultyScore","aggregate":"avg","sign":1,"factor":"D","factorWeight":1},{"roleType":"DB","symbol":"dB","label":"运动员B难度","sourceField":"DifficultyScore","targetField":"DifficultyScore","aggregate":"avg","sign":1,"factor":"D","factorWeight":1},{"roleType":"P","symbol":"P","label":"表现","sourceField":"PerformanceScore","targetField":"PerformanceScore","aggregate":"avg","sign":1,"factor":"P","factorWeight":0.05},{"roleType":"T","symbol":"Q","label":"规定元素缺失","sourceField":"RequiredMissingCount","targetField":"RequiredScore","aggregate":"max","sign":1,"factor":"Q","factorWeight":0.025},{"roleType":"T","symbol":"M","label":"扣分","sourceField":"DeductionScore","targetField":"DeductionScore","aggregate":"sum","sign":-1,"factor":"M","factorWeight":1}],"tieBreakers":["TotalScore","-DeductionScore","RequiredScore","PerformanceScore","DifficultyScore"]}
""";
///
/// 交互绳花样计分参数配置。
/// D = dJ × 1.4 + dT 是加权合并而非取平均,因此 difficultyDivisor 配置为 1;
/// 交互绳总分无 Q 因子,主裁只配置 M。
///
public const string WireRuleConfigJson = """
{"ruleType":"FREESTYLE_WIRE","totalMode":"factor","baseScore":0,"scoreDecimals":2,"difficultyDivisor":1,"correctionNeedApproval":false,"roleAggregations":[{"roleType":"DJ","symbol":"dJ","label":"跳绳运动员难度","sourceField":"DifficultyScore","targetField":"DifficultyScore","aggregate":"avg","sign":1,"factor":"D","factorWeight":1.4},{"roleType":"DT","symbol":"dT","label":"摇绳运动员难度","sourceField":"DifficultyScore","targetField":"DifficultyScore","aggregate":"avg","sign":1,"factor":"D","factorWeight":1},{"roleType":"P","symbol":"P","label":"表现","sourceField":"PerformanceScore","targetField":"PerformanceScore","aggregate":"avg","sign":1,"factor":"P","factorWeight":0.033},{"roleType":"T","symbol":"M","label":"扣分","sourceField":"DeductionScore","targetField":"DeductionScore","aggregate":"sum","sign":-1,"factor":"M","factorWeight":1}],"tieBreakers":["TotalScore","-DeductionScore","PerformanceScore","DifficultyScore"]}
""";
///
/// 车轮跳花样全部评分项
///
public static IReadOnlyList WheelItems { get; } = BuildWheelItems();
///
/// 交互绳花样全部评分项
///
public static IReadOnlyList WireItems { get; } = BuildWireItems();
///
/// 构造车轮跳花样评分项:DA/DB 难度等级、表现五维与失误、主裁扣分与规定元素、取消资格原因
///
private static List BuildWheelItems()
{
var items = new List();
var sort = 0;
// 运动员A、B 的难度裁判各自只看一名运动员,难度明细带 subjectCode 便于后端聚合与定位。
items.AddRange(BuildDifficultyItems(RoleDifficultyA, SubjectA, null, null, null, null, ref sort));
items.AddRange(BuildDifficultyItems(RoleDifficultyB, SubjectB, null, null, null, null, ref sort));
items.AddRange(BuildPerformanceItems(ref sort));
items.AddRange(BuildChiefDeductionItems("T_INTERVAL", "间歇", ref sort));
// 规定元素:4 类元素每类均需完成 4 个,未完成数由服务端算出后参与 Q。
foreach (var element in WheelRequiredElements)
{
items.Add(new PrescribedRuleItemDefinition
{
JudgeRoleType = RoleChief, ItemCode = element.ItemCode, ItemName = element.ItemName,
ItemType = ScoreItemType.RequiredElement, ScoreDimension = ScoreDimensionType.Required,
CalcMode = ScoreCalcMode.CountByUnit,
UnitValue = 1m, MinValue = 0m, MaxValue = WheelRequiredCountPerElement, StepValue = 1m, DefaultValue = 0m,
IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.Count("个")
});
}
items.Add(new PrescribedRuleItemDefinition
{
JudgeRoleType = RoleChief, ItemCode = "REQUIRED_MISSING", ItemName = "规定元素缺失(个)",
ItemType = ScoreItemType.RequiredElement, ScoreDimension = ScoreDimensionType.None,
CalcMode = ScoreCalcMode.DirectValue,
MinValue = 0m, MaxValue = WheelRequiredTarget, StepValue = 1m, DefaultValue = 0m,
IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.RequiredMissing(WheelRequiredTarget)
});
items.AddRange(BuildDisqualifyItems(ref sort));
return items;
}
///
/// 构造交互绳花样评分项:DJ 按全部动作取均值、DT 取最高 20 个动作,表现与主裁扣分同车轮跳但不计规定元素
///
private static List BuildWireItems()
{
var items = new List();
var sort = 0;
items.AddRange(BuildDifficultyItems(RoleDifficultyJumper, null, null,
Scoring.Dtos.DifficultyAggregateMode.Average, null, null, ref sort, WireJumperDifficultyLevels));
items.AddRange(BuildDifficultyItems(RoleDifficultyTurner, null, null,
Scoring.Dtos.DifficultyAggregateMode.Top, TurnerTopCount, null, ref sort, WireTurnerDifficultyLevels));
items.AddRange(BuildPerformanceItems(ref sort));
items.AddRange(BuildChiefDeductionItems("T_SPACE_VIOLATION", "空间违例", ref sort));
items.AddRange(BuildDisqualifyItems(ref sort));
return items;
}
///
/// 构造一个难度裁判类型的等级计数项。
/// aggregate 为空表示按数量 × 等级分值直接累加;avg 按动作总数取均值;top 取最高 topCount 个动作。
/// itemCodePrefix 用于表演赛把同一裁判的多个类别拆成独立评分项(如 SR_DIFF_LEVEL_3),避免编码互相覆盖。
///
internal static List BuildDifficultyItems(string roleType, string? subjectCode,
string? subjectName, string? aggregate, int? topCount, string? itemCodePrefix, ref int sort,
IReadOnlyList? difficultyLevels = null)
{
var items = new List();
foreach (var level in difficultyLevels ?? DifficultyLevels)
{
items.Add(new PrescribedRuleItemDefinition
{
JudgeRoleType = roleType,
ItemCode = string.IsNullOrEmpty(itemCodePrefix) ? level.ItemCode : $"{itemCodePrefix}_{level.ItemCode}",
ItemName = level.LevelName,
ItemType = ScoreItemType.DifficultyCount, ScoreDimension = ScoreDimensionType.Difficulty,
CalcMode = ScoreCalcMode.CountByUnit,
UnitValue = level.LevelValue, MinValue = 0m, MaxValue = 50m, StepValue = 1m, DefaultValue = 0m,
IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.Difficulty(subjectCode, subjectName, aggregate, topCount)
});
}
return items;
}
///
/// 构造表现裁判评分项:五维各一组人工加/减项 + 一个只读维度分自动项,再加一个失误次数项。
/// 失误联动五维自动减分由服务端在提交时重算,客户端只能改失误次数。
///
internal static List BuildPerformanceItems(ref int sort)
{
var items = new List();
foreach (var dimension in PerformanceDimensions)
{
items.Add(new PrescribedRuleItemDefinition
{
JudgeRoleType = RolePerformance, ItemCode = $"{dimension.Code}_PLUS", ItemName = $"{dimension.Name}(加数量)",
ItemType = ScoreItemType.Performance, ScoreDimension = ScoreDimensionType.Performance,
CalcMode = ScoreCalcMode.CountByUnit,
UnitValue = 1m, MinValue = 0m, MaxValue = 50m, StepValue = 1m, DefaultValue = 0m,
IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.PerformanceAdjust(dimension.Code, 1)
});
items.Add(new PrescribedRuleItemDefinition
{
JudgeRoleType = RolePerformance, ItemCode = $"{dimension.Code}_MINUS", ItemName = $"{dimension.Name}(减数量)",
ItemType = ScoreItemType.Performance, ScoreDimension = ScoreDimensionType.Performance,
CalcMode = ScoreCalcMode.CountByUnit,
UnitValue = 1m, MinValue = 0m, MaxValue = 50m, StepValue = 1m, DefaultValue = 0m,
IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.PerformanceAdjust(dimension.Code, -1)
});
items.Add(new PrescribedRuleItemDefinition
{
JudgeRoleType = RolePerformance, ItemCode = $"{dimension.Code}_SCORE", ItemName = dimension.Name,
ItemType = ScoreItemType.Performance, ScoreDimension = ScoreDimensionType.Performance,
CalcMode = ScoreCalcMode.DirectValue,
UnitValue = 1m, MinValue = 0m, MaxValue = PerformanceMaxValue, StepValue = 1m,
DefaultValue = PerformanceBaseValue, IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.PerformanceDimension(dimension.Code, dimension.Weight)
});
}
items.Add(new PrescribedRuleItemDefinition
{
JudgeRoleType = RolePerformance, ItemCode = "FAILURE_COUNT", ItemName = "失误次数",
ItemType = ScoreItemType.Performance, ScoreDimension = ScoreDimensionType.None,
CalcMode = ScoreCalcMode.CountByUnit,
UnitValue = 1m, MinValue = 0m, MaxValue = 50m, StepValue = 1m, DefaultValue = 0m,
IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.FailureCount()
});
return items;
}
///
/// 构造主裁扣分项。失误按递增序列扣减,违例与 extraCode 指定的第三项(车轮跳为间歇、交互绳为空间违例)按每次 0.05 扣减。
/// extraCode 为空时只生成失误与违例两项(表演赛)。
///
internal static List BuildChiefDeductionItems(string? extraCode, string? extraName, ref int sort)
{
var items = new List
{
new()
{
JudgeRoleType = RoleChief, ItemCode = "T_VIOLATION", ItemName = "违例",
ItemType = ScoreItemType.Deduction, ScoreDimension = ScoreDimensionType.Deduction,
CalcMode = ScoreCalcMode.CountByUnit,
UnitValue = ViolationUnitDeduction, MinValue = 0m, MaxValue = 50m, StepValue = 1m, DefaultValue = 0m,
IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.Count("次")
}
};
if (!string.IsNullOrEmpty(extraCode))
{
items.Add(new PrescribedRuleItemDefinition
{
JudgeRoleType = RoleChief, ItemCode = extraCode, ItemName = extraName ?? extraCode,
ItemType = ScoreItemType.Deduction, ScoreDimension = ScoreDimensionType.Deduction,
CalcMode = ScoreCalcMode.CountByUnit,
UnitValue = ViolationUnitDeduction, MinValue = 0m, MaxValue = 50m, StepValue = 1m, DefaultValue = 0m,
IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.Count("次")
});
}
items.Add(new PrescribedRuleItemDefinition
{
JudgeRoleType = RoleChief, ItemCode = "T_FAILURE", ItemName = "失误",
ItemType = ScoreItemType.Deduction, ScoreDimension = ScoreDimensionType.Deduction,
CalcMode = ScoreCalcMode.CountByUnit,
UnitValue = FailureStepDeductions[0], MinValue = 0m, MaxValue = 50m, StepValue = 1m, DefaultValue = 0m,
IsRequired = false, Sort = ++sort,
ExtensionJson = FreestyleItemExtension.StepDeduction(FailureStepDeductions)
});
return items;
}
private static List BuildWireDifficultyLevels(bool includeBreak)
{
var levels = new List();
if (includeBreak)
levels.Add(new DifficultyLevelDefinition("DIFF_LEVEL_0", "0 级(间歇)", 0m));
for (var level = 1; level <= 5; level++)
{
levels.Add(NewWireDifficultyLevel(level, "MINUS", "-", -0.25));
levels.Add(NewWireDifficultyLevel(level, null, string.Empty, 0));
levels.Add(NewWireDifficultyLevel(level, "PLUS", "+", 0.5));
}
return levels;
}
private static DifficultyLevelDefinition NewWireDifficultyLevel(int level, string? codeSuffix,
string nameSuffix, double levelOffset)
{
var itemCode = codeSuffix == null ? $"DIFF_LEVEL_{level}" : $"DIFF_LEVEL_{level}_{codeSuffix}";
var levelValue = decimal.Round((decimal)Math.Pow(1.5, level + levelOffset), 4,
MidpointRounding.AwayFromZero);
return new DifficultyLevelDefinition(itemCode, $"{level}{nameSuffix} 级", levelValue);
}
///
/// 构造主裁的取消比赛资格原因项,勾选任一项即整条成绩按 0 分处理
///
internal static List BuildDisqualifyItems(ref int sort)
{
var items = new List();
foreach (var reason in DisqualifyReasons)
{
items.Add(new PrescribedRuleItemDefinition
{
JudgeRoleType = RoleChief, ItemCode = reason.ItemCode, ItemName = reason.ReasonName,
ItemType = ScoreItemType.Disqualify, ScoreDimension = ScoreDimensionType.None,
CalcMode = ScoreCalcMode.RecordOnly,
IsRequired = false, Sort = ++sort
});
}
return items;
}
}
///
/// 一个难度等级的定义
///
/// 评分项编码
/// 等级名称
/// 等级分值
public record DifficultyLevelDefinition(string ItemCode, string LevelName, decimal LevelValue);
///
/// 一个表现维度的定义
///
/// 维度编码
/// 维度名称
/// 在单裁判加权分里的权重
public record PerformanceDimensionDefinition(string Code, string Name, decimal Weight);
///
/// 一条取消比赛资格原因的定义
///
/// 评分项编码
/// 原因名称
public record DisqualifyReasonDefinition(string ItemCode, string ReasonName);
///
/// 一类规定元素的定义
///
/// 评分项编码
/// 类别名称
public record RequiredElementDefinition(string ItemCode, string ItemName);
///
/// 花样赛评分项扩展配置(ScoreRuleItem.ExtensionJson)的构造。
/// 字段名与 ScoreSheetCalculationService.CreateDefinition 的解析逻辑一一对应。
///
public static class FreestyleItemExtension
{
///
/// 难度等级计数项:subjectCode/subjectName 区分同一裁判要评的多个对象(车轮跳的两名运动员、表演赛的多个器械类别),
/// difficultyAggregate 指定聚合方式
///
public static string Difficulty(string? subjectCode, string? subjectName, string? aggregate, int? topCount)
{
var node = new JObject { ["inputMode"] = "count", ["unitLabel"] = "个" };
if (!string.IsNullOrEmpty(subjectCode)) node["subjectCode"] = subjectCode;
if (!string.IsNullOrEmpty(subjectName)) node["subjectName"] = subjectName;
if (!string.IsNullOrEmpty(aggregate)) node["difficultyAggregate"] = aggregate;
if (topCount is > 0) node["difficultyTopCount"] = topCount.Value;
return node.ToString(Formatting.None);
}
///
/// 表现维度的人工加/减项:adjustSign 为 1 表示每次计数使维度分 +1,-1 表示 -1
///
public static string PerformanceAdjust(string dimensionCode, int adjustSign) =>
new JObject
{
["inputMode"] = "count", ["unitLabel"] = "次",
["dimensionCode"] = dimensionCode, ["adjustSign"] = adjustSign
}.ToString(Formatting.None);
///
/// 表现维度分(只读自动项):基准 12 分,按权重参与单裁判加权分
///
public static string PerformanceDimension(string dimensionCode, decimal weight) =>
new JObject
{
["inputMode"] = "score", ["isAuto"] = true,
["dimensionCode"] = dimensionCode, ["dimensionWeight"] = weight,
["baseValue"] = FreestyleRuleDefinition.PerformanceBaseValue
}.ToString(Formatting.None);
///
/// 失误次数项:每次失误使五个维度的自动减分各 +1
///
public static string FailureCount() =>
new JObject
{
["inputMode"] = "count", ["unitLabel"] = "次", ["isFailureCount"] = true,
["remark"] = "表现裁判记一次失误,其对应的表现五个方面(音乐,完成质量,创意,娱乐和多样性)减数量+1"
}.ToString(Formatting.None);
///
/// 递增扣分项:第 1 次 0.05、第 2 次 0.075、第 3 次起每次 0.1
///
public static string StepDeduction(IEnumerable steps) =>
new JObject
{
["inputMode"] = "count", ["unitLabel"] = "次",
["stepDeductions"] = new JArray(steps.Cast