Files
Workspace/Assets/Demos/Demo2/Domain/Demo2RuleEngine.cs
T
2026-08-18 02:03:34 +08:00

95 lines
4.5 KiB
C#

#nullable enable
using System;
using System.Collections.Generic;
namespace Demo2.Domain
{
public struct Demo2RuleContext
{
public long Payload;
public long MultiplierMilli;
public long Energy;
public long Money;
public long ExcessFirepower;
public int Faults;
public bool ThreeSameRecipes;
public bool IronFuelAdjacent;
public bool BeltBelowEightyPercent;
public bool FirstBatch;
public bool CoreAtRisk;
public int DuplicatedOutputs;
public long FinalFirepower => SaturatingMath.MultiplyScaled(Payload, MultiplierMilli);
}
public static class Demo2RuleEngine
{
public static Demo2RuleContext Evaluate(Demo2RuleContext context, IReadOnlyList<Demo2RuleDefinition> orderedRules)
{
context.MultiplierMilli = context.MultiplierMilli <= 0 ? SaturatingMath.Scale : context.MultiplierMilli;
for (var ruleIndex = 0; ruleIndex < orderedRules.Count; ruleIndex++)
{
var instructions = orderedRules[ruleIndex].Instructions;
for (var instructionIndex = 0; instructionIndex < instructions.Count; instructionIndex++)
{
var instruction = instructions[instructionIndex];
if (!Matches(instruction.Condition, context)) continue;
Apply(ref context, instruction);
}
}
return context;
}
public static bool Matches(Demo2RuleCondition condition, in Demo2RuleContext context)
{
if ((condition & Demo2RuleCondition.ThreeSameRecipes) != 0 && !context.ThreeSameRecipes) return false;
if ((condition & Demo2RuleCondition.IronFuelAdjacent) != 0 && !context.IronFuelAdjacent) return false;
if ((condition & Demo2RuleCondition.BeltBelowEightyPercent) != 0 && !context.BeltBelowEightyPercent) return false;
if ((condition & Demo2RuleCondition.NoFaults) != 0 && context.Faults != 0) return false;
if ((condition & Demo2RuleCondition.HasExcessEnergy) != 0 && context.Energy <= 0) return false;
if ((condition & Demo2RuleCondition.FirstBatch) != 0 && !context.FirstBatch) return false;
if ((condition & Demo2RuleCondition.CoreAtRisk) != 0 && !context.CoreAtRisk) return false;
if ((condition & Demo2RuleCondition.HasFaults) != 0 && context.Faults <= 0) return false;
return true;
}
public static void Apply(ref Demo2RuleContext context, Demo2RuleInstructionData instruction)
{
switch (instruction.Opcode)
{
case Demo2RuleOpcode.AddPayload:
context.Payload = SaturatingMath.Add(context.Payload, instruction.Operand);
break;
case Demo2RuleOpcode.MultiplyPayload:
context.Payload = SaturatingMath.MultiplyScaled(context.Payload, instruction.Operand);
break;
case Demo2RuleOpcode.AddMultiplier:
context.MultiplierMilli = SaturatingMath.Add(context.MultiplierMilli, instruction.Operand);
break;
case Demo2RuleOpcode.MultiplyMultiplier:
context.MultiplierMilli = SaturatingMath.MultiplyScaled(context.MultiplierMilli, instruction.Operand);
break;
case Demo2RuleOpcode.ConvertEnergyToPayload:
context.Payload = SaturatingMath.Add(context.Payload, SaturatingMath.Multiply(context.Energy, instruction.Operand));
context.Energy = 0;
break;
case Demo2RuleOpcode.AddMoneyFromExcess:
context.Money = SaturatingMath.Add(context.Money, context.ExcessFirepower / Math.Max(1, instruction.Operand));
break;
case Demo2RuleOpcode.DuplicateNextOutput:
context.DuplicatedOutputs = SaturatingMath.Add(context.DuplicatedOutputs, (int)instruction.Operand) > int.MaxValue
? int.MaxValue
: context.DuplicatedOutputs + (int)instruction.Operand;
break;
case Demo2RuleOpcode.AddFaults:
context.Faults = Math.Max(0, context.Faults + (int)instruction.Operand);
break;
case Demo2RuleOpcode.RepairFaults:
context.Faults = Math.Max(0, context.Faults - (int)instruction.Operand);
break;
}
}
}
}