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().ToArray()), ["remark"] = "第1次扣0.05,第2次扣0.075,第3次起每次扣0.1" }.ToString(Formatting.None); /// /// 普通计数项 /// public static string Count(string unitLabel) => new JObject { ["inputMode"] = "count", ["unitLabel"] = unitLabel }.ToString(Formatting.None); /// /// 规定元素类别项:录入数量大于 0 即计一类完成(表演赛使用)。 /// public static string RequiredElement() => new JObject { ["inputMode"] = "count", ["unitLabel"] = "个", ["requiredAsCategory"] = true }.ToString(Formatting.None); /// /// 规定元素缺失数(只读自动项):缺失数 = max(0, 目标类别数 - 完成类别数) /// public static string RequiredMissing(decimal target) => new JObject { ["inputMode"] = "score", ["isAuto"] = true, ["unitLabel"] = "个", ["requiredTarget"] = target }.ToString(Formatting.None); }