95 lines
4.5 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|