Added solution for "Day 19: Aplenty", part 1
This commit is contained in:
parent
b32a7345cb
commit
c3019613bd
|
@ -22,27 +22,289 @@ unit UAplenty;
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, USolver;
|
Classes, SysUtils, Generics.Collections, USolver;
|
||||||
|
|
||||||
type
|
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 }
|
||||||
|
|
||||||
TAplenty = class(TSolver)
|
TAplenty = class(TSolver)
|
||||||
|
private
|
||||||
|
FIsReadingWorkflows: Boolean;
|
||||||
|
FWorkflows: TWorkflows;
|
||||||
|
FStart: TWorkflow;
|
||||||
|
procedure ProcessWorkflowLine(const ALine: string);
|
||||||
|
procedure ProcessMachinePartLine(const ALine: string);
|
||||||
public
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure Init; override;
|
||||||
procedure ProcessDataLine(const ALine: string); override;
|
procedure ProcessDataLine(const ALine: string); override;
|
||||||
procedure Finish; override;
|
procedure Finish; override;
|
||||||
function GetDataFileName: string; override;
|
function GetDataFileName: string; override;
|
||||||
function GetPuzzleName: string; override;
|
function GetPuzzleName: string; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
CAccepted = 'A';
|
||||||
|
CRejected = 'R';
|
||||||
|
CLessThanChar = '<';
|
||||||
|
CStartWorkflowName = 'in';
|
||||||
|
|
||||||
implementation
|
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 }
|
{ 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);
|
procedure TAplenty.ProcessDataLine(const ALine: string);
|
||||||
begin
|
begin
|
||||||
|
if ALine = '' then
|
||||||
|
FIsReadingWorkflows := False
|
||||||
|
else if FIsReadingWorkflows then
|
||||||
|
ProcessWorkflowLine(ALine)
|
||||||
|
else
|
||||||
|
ProcessMachinePartLine(ALine);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAplenty.Finish;
|
procedure TAplenty.Finish;
|
||||||
|
|
|
@ -57,7 +57,7 @@ end;
|
||||||
|
|
||||||
procedure TAplentyFullDataTestCase.TestPart1;
|
procedure TAplentyFullDataTestCase.TestPart1;
|
||||||
begin
|
begin
|
||||||
AssertEquals(-1, FSolver.GetResultPart1);
|
AssertEquals(331208, FSolver.GetResultPart1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAplentyFullDataTestCase.TestPart2;
|
procedure TAplentyFullDataTestCase.TestPart2;
|
||||||
|
|
Loading…
Reference in New Issue