Added solution for "Day 19: Aplenty", part 1
This commit is contained in:
parent
b32a7345cb
commit
c3019613bd
|
@ -22,27 +22,289 @@ unit UAplenty;
|
|||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, USolver;
|
||||
Classes, SysUtils, Generics.Collections, USolver;
|
||||
|
||||
type
|
||||
TMachinePartCategory = (mpcExtremelyCoolLookingCategoryIndex, mpcMusicalCategoryIndex, mpcAerodynamicCategoryIndex,
|
||||
mpcShinyCategoryIndex);
|
||||
|
||||
{ TMachinePart }
|
||||
|
||||
TMachinePart = class
|
||||
private
|
||||
FCategories: array[TMachinePartCategory] of Integer;
|
||||
function GetCategory(const AIndex: TMachinePartCategory): Integer;
|
||||
public
|
||||
property Category[AIndex: TMachinePartCategory]: Integer read GetCategory;
|
||||
constructor Create(const ALine: string);
|
||||
function CalcRating: Integer;
|
||||
end;
|
||||
|
||||
TWorkflow = class;
|
||||
|
||||
TWorkflowRuleEffectType = (wetAccept, wetReject, wetMove);
|
||||
|
||||
{ TWorkflowRuleEffect }
|
||||
|
||||
TWorkflowRuleEffect = class
|
||||
private
|
||||
FEffectType: TWorkflowRuleEffectType;
|
||||
FMoveDestinationName: string;
|
||||
FMoveDestination: TWorkflow;
|
||||
public
|
||||
property EffectType: TWorkflowRuleEffectType read FEffectType;
|
||||
property MoveDestinationName: string read FMoveDestinationName;
|
||||
property MoveDestination: TWorkflow read FMoveDestination write FMoveDestination;
|
||||
constructor Create(const ALine: string);
|
||||
function IsEqualTo(const AOther: TWorkflowRuleEffect): Boolean;
|
||||
end;
|
||||
|
||||
{ TWorkflowRule }
|
||||
|
||||
TWorkflowRule = class
|
||||
private
|
||||
FCategory: TMachinePartCategory;
|
||||
FLessThan: Boolean;
|
||||
FThreshold: Integer;
|
||||
FEffect: TWorkflowRuleEffect;
|
||||
public
|
||||
property Effect: TWorkflowRuleEffect read FEffect;
|
||||
constructor Create(const ALine: string);
|
||||
destructor Destroy; override;
|
||||
function IsMatch(const AMachinePart: TMachinePart): Boolean;
|
||||
end;
|
||||
|
||||
TWorkflowRules = specialize TObjectList<TWorkflowRule>;
|
||||
|
||||
{ TWorkflow }
|
||||
|
||||
TWorkflow = class
|
||||
private
|
||||
FName: string;
|
||||
FRules: TWorkflowRules;
|
||||
FLastEffect: TWorkflowRuleEffect;
|
||||
public
|
||||
property Name: string read FName;
|
||||
constructor Create(const ALine: string);
|
||||
destructor Destroy; override;
|
||||
function Process(const AMachinePart: TMachinePart): TWorkflowRuleEffect;
|
||||
end;
|
||||
|
||||
TWorkflows = specialize TObjectList<TWorkflow>;
|
||||
|
||||
{ TAplenty }
|
||||
|
||||
TAplenty = class(TSolver)
|
||||
private
|
||||
FIsReadingWorkflows: Boolean;
|
||||
FWorkflows: TWorkflows;
|
||||
FStart: TWorkflow;
|
||||
procedure ProcessWorkflowLine(const ALine: string);
|
||||
procedure ProcessMachinePartLine(const ALine: string);
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure Init; override;
|
||||
procedure ProcessDataLine(const ALine: string); override;
|
||||
procedure Finish; override;
|
||||
function GetDataFileName: string; override;
|
||||
function GetPuzzleName: string; override;
|
||||
end;
|
||||
|
||||
const
|
||||
CAccepted = 'A';
|
||||
CRejected = 'R';
|
||||
CLessThanChar = '<';
|
||||
CStartWorkflowName = 'in';
|
||||
|
||||
implementation
|
||||
|
||||
{ TMachinePart }
|
||||
|
||||
function TMachinePart.GetCategory(const AIndex: TMachinePartCategory): Integer;
|
||||
begin
|
||||
Result := FCategories[AIndex];
|
||||
end;
|
||||
|
||||
constructor TMachinePart.Create(const ALine: string);
|
||||
var
|
||||
split: TStringArray;
|
||||
begin
|
||||
split := ALine.Split(',');
|
||||
FCategories[mpcExtremelyCoolLookingCategoryIndex] := StrToInt(Copy(split[0], 4, Length(split[0]) - 3));
|
||||
FCategories[mpcMusicalCategoryIndex] := StrToInt(Copy(split[1], 3, Length(split[1]) - 2));
|
||||
FCategories[mpcAerodynamicCategoryIndex] := StrToInt(Copy(split[2], 3, Length(split[2]) - 2));
|
||||
FCategories[mpcShinyCategoryIndex] := StrToInt(Copy(split[3], 3, Length(split[3]) - 3));
|
||||
end;
|
||||
|
||||
function TMachinePart.CalcRating: Integer;
|
||||
var
|
||||
cat: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
for cat in FCategories do
|
||||
Inc(Result, cat);
|
||||
end;
|
||||
|
||||
{ TWorkflowRuleEffect }
|
||||
|
||||
constructor TWorkflowRuleEffect.Create(const ALine: string);
|
||||
begin
|
||||
if ALine = CAccepted then
|
||||
FEffectType := wetAccept
|
||||
else if ALine = CRejected then
|
||||
FEffectType := wetReject
|
||||
else begin
|
||||
FEffectType := wetMove;
|
||||
FMoveDestinationName := ALine;
|
||||
FMoveDestination := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TWorkflowRuleEffect.IsEqualTo(const AOther: TWorkflowRuleEffect): Boolean;
|
||||
begin
|
||||
Result := (FEffectType = AOther.FEffectType) and (FMoveDestinationName = AOther.FMoveDestinationName);
|
||||
end;
|
||||
|
||||
{ TWorkflowRule }
|
||||
|
||||
constructor TWorkflowRule.Create(const ALine: string);
|
||||
var
|
||||
split: TStringArray;
|
||||
begin
|
||||
case ALine[1] of
|
||||
'x': FCategory := mpcExtremelyCoolLookingCategoryIndex;
|
||||
'm': FCategory := mpcMusicalCategoryIndex;
|
||||
'a': FCategory := mpcAerodynamicCategoryIndex;
|
||||
's': FCategory := mpcShinyCategoryIndex;
|
||||
end;
|
||||
FLessThan := Aline[2] = CLessThanChar;
|
||||
|
||||
split := ALine.Split(':');
|
||||
FThreshold := StrToInt(Copy(split[0], 3, Length(split[0]) - 2));
|
||||
FEffect := TWorkflowRuleEffect.Create(split[1]);
|
||||
end;
|
||||
|
||||
destructor TWorkflowRule.Destroy;
|
||||
begin
|
||||
FEffect.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TWorkflowRule.IsMatch(const AMachinePart: TMachinePart): Boolean;
|
||||
begin
|
||||
if FLessThan then
|
||||
Result := AMachinePart.Category[FCategory] < FThreshold
|
||||
else
|
||||
Result := AMachinePart.Category[FCategory] > FThreshold;
|
||||
end;
|
||||
|
||||
{ TWorkflow }
|
||||
|
||||
constructor TWorkflow.Create(const ALine: string);
|
||||
var
|
||||
split: TStringArray;
|
||||
i: Integer;
|
||||
begin
|
||||
split := ALine.Split([',', '{', '}']);
|
||||
FName := split[0];
|
||||
FRules := TWorkflowRules.Create;
|
||||
for i := 1 to Length(split) - 3 do
|
||||
FRules.Add(TWorkflowRule.Create(split[i]));
|
||||
FLastEffect := TWorkflowRuleEffect.Create(split[Length(split) - 2]);
|
||||
|
||||
i := FRules.Count;
|
||||
while (i > 0) and (FRules[i - 1].Effect.IsEqualTo(FLastEffect)) do
|
||||
Dec(i);
|
||||
if i < FRules.Count then
|
||||
FRules.DeleteRange(i, FRules.Count - i);
|
||||
end;
|
||||
|
||||
destructor TWorkflow.Destroy;
|
||||
begin
|
||||
FRules.Free;
|
||||
FLastEffect.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TWorkflow.Process(const AMachinePart: TMachinePart): TWorkflowRuleEffect;
|
||||
var
|
||||
rule: TWorkflowRule;
|
||||
begin
|
||||
for rule in FRules do
|
||||
if rule.IsMatch(AMachinePart) then
|
||||
begin
|
||||
Result := rule.Effect;
|
||||
Exit;
|
||||
end;
|
||||
Result := FLastEffect;
|
||||
end;
|
||||
|
||||
{ TAplenty }
|
||||
|
||||
procedure TAplenty.ProcessWorkflowLine(const ALine: string);
|
||||
var
|
||||
workflow: TWorkflow;
|
||||
begin
|
||||
workflow := TWorkflow.Create(ALine);
|
||||
FWorkflows.Add(workflow);
|
||||
if workflow.Name = CStartWorkflowName then
|
||||
FStart := workflow;
|
||||
end;
|
||||
|
||||
procedure TAplenty.ProcessMachinePartLine(const ALine: string);
|
||||
var
|
||||
part: TMachinePart;
|
||||
workflow, search: TWorkflow;
|
||||
effect: TWorkflowRuleEffect;
|
||||
begin
|
||||
part := TMachinePart.Create(ALine);
|
||||
workflow := FStart;
|
||||
repeat
|
||||
effect := workflow.Process(part);
|
||||
if effect.EffectType = wetMove then
|
||||
begin
|
||||
if effect.MoveDestination = nil then
|
||||
for search in FWorkflows do
|
||||
if search.Name = effect.MoveDestinationName then
|
||||
begin
|
||||
effect.MoveDestination := search;
|
||||
Break;
|
||||
end;
|
||||
workflow := effect.MoveDestination;
|
||||
end;
|
||||
until effect.EffectType <> wetMove;
|
||||
|
||||
if effect.EffectType = wetAccept then
|
||||
Inc(FPart1, part.CalcRating);
|
||||
part.Free;
|
||||
end;
|
||||
|
||||
constructor TAplenty.Create;
|
||||
begin
|
||||
FWorkflows := TWorkflows.Create;
|
||||
end;
|
||||
|
||||
destructor TAplenty.Destroy;
|
||||
begin
|
||||
FWorkflows.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TAplenty.Init;
|
||||
begin
|
||||
inherited Init;
|
||||
FIsReadingWorkflows := True;
|
||||
end;
|
||||
|
||||
procedure TAplenty.ProcessDataLine(const ALine: string);
|
||||
begin
|
||||
|
||||
if ALine = '' then
|
||||
FIsReadingWorkflows := False
|
||||
else if FIsReadingWorkflows then
|
||||
ProcessWorkflowLine(ALine)
|
||||
else
|
||||
ProcessMachinePartLine(ALine);
|
||||
end;
|
||||
|
||||
procedure TAplenty.Finish;
|
||||
|
|
|
@ -57,7 +57,7 @@ end;
|
|||
|
||||
procedure TAplentyFullDataTestCase.TestPart1;
|
||||
begin
|
||||
AssertEquals(-1, FSolver.GetResultPart1);
|
||||
AssertEquals(331208, FSolver.GetResultPart1);
|
||||
end;
|
||||
|
||||
procedure TAplentyFullDataTestCase.TestPart2;
|
||||
|
|
Loading…
Reference in New Issue