Added solution for "Day 14: Parabolic Reflector Dish", part 2
This commit is contained in:
parent
637e7aedad
commit
22b9a24893
|
@ -27,6 +27,7 @@ uses
|
||||||
const
|
const
|
||||||
CRoundRockChar = 'O';
|
CRoundRockChar = 'O';
|
||||||
CCubeRockChar = '#';
|
CCubeRockChar = '#';
|
||||||
|
CMaxSpinCount = 1000000000;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
|
@ -45,12 +46,31 @@ type
|
||||||
|
|
||||||
TRockPiles = specialize TObjectList<TRockPile>;
|
TRockPiles = specialize TObjectList<TRockPile>;
|
||||||
|
|
||||||
|
{ TPlatform }
|
||||||
|
|
||||||
|
TPlatform = class
|
||||||
|
private
|
||||||
|
FLines: TStringList;
|
||||||
|
procedure TiltNorth;
|
||||||
|
procedure TiltSouth;
|
||||||
|
procedure TiltWest;
|
||||||
|
procedure TiltEast;
|
||||||
|
function IsEqualTo(const FOther: TStringList): Boolean;
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure Add(const ALine: string);
|
||||||
|
procedure Spin;
|
||||||
|
function CalcWeight: Integer;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TParabolicReflectorDish }
|
{ TParabolicReflectorDish }
|
||||||
|
|
||||||
TParabolicReflectorDish = class(TSolver)
|
TParabolicReflectorDish = class(TSolver)
|
||||||
private
|
private
|
||||||
FLineIndex: Integer;
|
FLineIndex: Integer;
|
||||||
FActivePiles, FFinishedPiles: TRockPiles;
|
FActivePiles, FFinishedPiles: TRockPiles;
|
||||||
|
FPlatform: TPlatform;
|
||||||
public
|
public
|
||||||
constructor Create;
|
constructor Create;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
@ -87,7 +107,218 @@ end;
|
||||||
|
|
||||||
function TRockPile.CalcWeight(const ALineCount: Integer): Integer;
|
function TRockPile.CalcWeight(const ALineCount: Integer): Integer;
|
||||||
begin
|
begin
|
||||||
Result := (2 * (ALineCount - FStart) - FLength + 1) * FLength div 2;
|
Result := FLength * (2 * (ALineCount - FStart) - FLength + 1) div 2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TPlatform }
|
||||||
|
|
||||||
|
procedure TPlatform.TiltNorth;
|
||||||
|
var
|
||||||
|
i, j, k: Integer;
|
||||||
|
s: string;
|
||||||
|
begin
|
||||||
|
for i := 0 to FLines.Count - 1 do
|
||||||
|
for j := 1 to Length(FLines[i]) do
|
||||||
|
if FLines[i][j] = CRoundRockChar then
|
||||||
|
begin
|
||||||
|
k := i - 1;
|
||||||
|
while (k >= 0) and (FLines[k][j] = '.') do
|
||||||
|
Dec(k);
|
||||||
|
Inc(k);
|
||||||
|
if k < i then
|
||||||
|
begin
|
||||||
|
s := FLines[i];
|
||||||
|
s[j] := '.';
|
||||||
|
FLines[i] := s;
|
||||||
|
s := FLines[k];
|
||||||
|
s[j] := CRoundRockChar;
|
||||||
|
FLines[k] := s;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPlatform.TiltSouth;
|
||||||
|
var
|
||||||
|
i, j, k: Integer;
|
||||||
|
s: string;
|
||||||
|
begin
|
||||||
|
for i := FLines.Count - 1 downto 0 do
|
||||||
|
for j := 1 to Length(FLines[i]) do
|
||||||
|
if FLines[i][j] = CRoundRockChar then
|
||||||
|
begin
|
||||||
|
k := i + 1;
|
||||||
|
while (k < FLines.Count) and (FLines[k][j] = '.') do
|
||||||
|
Inc(k);
|
||||||
|
Dec(k);
|
||||||
|
if k > i then
|
||||||
|
begin
|
||||||
|
s := FLines[i];
|
||||||
|
s[j] := '.';
|
||||||
|
FLines[i] := s;
|
||||||
|
s := FLines[k];
|
||||||
|
s[j] := CRoundRockChar;
|
||||||
|
FLines[k] := s;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPlatform.TiltWest;
|
||||||
|
var
|
||||||
|
i, j, k: Integer;
|
||||||
|
s: string;
|
||||||
|
begin
|
||||||
|
for i := 0 to FLines.Count - 1 do
|
||||||
|
begin
|
||||||
|
s := FLines[i];
|
||||||
|
k := 1;
|
||||||
|
for j := 1 to Length(s) do
|
||||||
|
begin
|
||||||
|
case s[j] of
|
||||||
|
'.':
|
||||||
|
if k <= 0 then
|
||||||
|
k := j;
|
||||||
|
CRoundRockChar: begin
|
||||||
|
if (k > 0) and (k < j) then
|
||||||
|
begin
|
||||||
|
s[k] := CRoundRockChar;
|
||||||
|
s[j] := '.';
|
||||||
|
Inc(k);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
k := 0;
|
||||||
|
end;
|
||||||
|
CCubeRockChar: k := 0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
FLines[i] := s;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPlatform.TiltEast;
|
||||||
|
var
|
||||||
|
i, j, k: Integer;
|
||||||
|
s: string;
|
||||||
|
begin
|
||||||
|
for i := 0 to FLines.Count - 1 do
|
||||||
|
begin
|
||||||
|
s := FLines[i];
|
||||||
|
k := Length(s) + 1;
|
||||||
|
for j := Length(s) downto 1 do
|
||||||
|
begin
|
||||||
|
case s[j] of
|
||||||
|
'.':
|
||||||
|
if k > Length(s) then
|
||||||
|
k := j;
|
||||||
|
CRoundRockChar: begin
|
||||||
|
if (k <= Length(s)) and (j < k) then
|
||||||
|
begin
|
||||||
|
s[k] := CRoundRockChar;
|
||||||
|
s[j] := '.';
|
||||||
|
Dec(k);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
k := Length(s) + 1;
|
||||||
|
end;
|
||||||
|
CCubeRockChar: k := Length(s) + 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
FLines[i] := s;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TPlatform.IsEqualTo(const FOther: TStringList): Boolean;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if FLines.Count = FOther.Count then
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
for i := 0 to FLines.Count - 1 do
|
||||||
|
if FLines[i] <> FOther[i] then
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := False;end;
|
||||||
|
|
||||||
|
constructor TPlatform.Create;
|
||||||
|
begin
|
||||||
|
FLines := TStringList.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TPlatform.Destroy;
|
||||||
|
begin
|
||||||
|
FLines.Free;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPlatform.Add(const ALine: string);
|
||||||
|
begin
|
||||||
|
FLines.Add(ALine);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPlatform.Spin;
|
||||||
|
var
|
||||||
|
i, j, x: Integer;
|
||||||
|
match: Boolean;
|
||||||
|
history: specialize TObjectList<TStringList>;
|
||||||
|
begin
|
||||||
|
// Intializes history of platform rock configurations.
|
||||||
|
history := specialize TObjectList<TStringList>.Create;
|
||||||
|
history.Add(TStringList.Create);
|
||||||
|
history[0].AddStrings(FLines);
|
||||||
|
|
||||||
|
// Performs spins until a configuration from the history is encountered again.
|
||||||
|
for i := 1 to CMaxSpinCount do
|
||||||
|
begin
|
||||||
|
TiltNorth;
|
||||||
|
TiltWest;
|
||||||
|
TiltSouth;
|
||||||
|
TiltEast;
|
||||||
|
|
||||||
|
// Searches history for the current configuration.
|
||||||
|
j := 0;
|
||||||
|
match := False;
|
||||||
|
while (j < history.Count) and not match do
|
||||||
|
begin
|
||||||
|
match := IsEqualTo(history[j]);
|
||||||
|
if not match then
|
||||||
|
Inc(j);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if match then
|
||||||
|
begin
|
||||||
|
x := CMaxSpinCount mod (i - j);
|
||||||
|
while x < j do
|
||||||
|
Inc(x, i - j);
|
||||||
|
FLines.Free;
|
||||||
|
FLines := history.ExtractIndex(x);
|
||||||
|
Break;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
history.Add(TStringList.Create);
|
||||||
|
history[i].AddStrings(FLines);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
history.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TPlatform.CalcWeight: Integer;
|
||||||
|
var
|
||||||
|
i, j, len, count: Integer;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
len := Length(FLines[0]);
|
||||||
|
for i := 0 to FLines.Count - 1 do
|
||||||
|
begin
|
||||||
|
count := 0;
|
||||||
|
for j := 1 to len do
|
||||||
|
if FLines[i][j] = CRoundRockChar then
|
||||||
|
Inc(count);
|
||||||
|
Inc(Result, count * (FLines.Count - i));
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TParabolicReflectorDish }
|
{ TParabolicReflectorDish }
|
||||||
|
@ -97,12 +328,14 @@ begin
|
||||||
FLineIndex := 0;
|
FLineIndex := 0;
|
||||||
FActivePiles := TRockPiles.Create;
|
FActivePiles := TRockPiles.Create;
|
||||||
FFinishedPiles := TRockPiles.Create;
|
FFinishedPiles := TRockPiles.Create;
|
||||||
|
FPlatform := TPlatform.Create;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TParabolicReflectorDish.Destroy;
|
destructor TParabolicReflectorDish.Destroy;
|
||||||
begin
|
begin
|
||||||
FActivePiles.Free;
|
FActivePiles.Free;
|
||||||
FFinishedPiles.Free;
|
FFinishedPiles.Free;
|
||||||
|
FPlatform.Free;
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -135,16 +368,22 @@ begin
|
||||||
FActivePiles[i - 1].SetStart(FLineIndex);
|
FActivePiles[i - 1].SetStart(FLineIndex);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
FPlatform.Add(ALine);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TParabolicReflectorDish.Finish;
|
procedure TParabolicReflectorDish.Finish;
|
||||||
var
|
var
|
||||||
i: Integer;
|
pile: TRockPile;
|
||||||
begin
|
begin
|
||||||
for i := 0 to FFinishedPiles.Count - 1 do
|
for pile in FFinishedPiles do
|
||||||
Inc(FPart1, FFinishedPiles[i].CalcWeight(FLineIndex));
|
Inc(FPart1, pile.CalcWeight(FLineIndex));
|
||||||
for i := 0 to FActivePiles.Count - 1 do
|
for pile in FActivePiles do
|
||||||
Inc(FPart1, FActivePiles[i].CalcWeight(FLineIndex));
|
Inc(FPart1, pile.CalcWeight(FLineIndex));
|
||||||
|
|
||||||
|
// Spins the platform and weighs the rocks.
|
||||||
|
FPlatform.Spin;
|
||||||
|
FPart2 := FPlatform.CalcWeight;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TParabolicReflectorDish.GetDataFileName: string;
|
function TParabolicReflectorDish.GetDataFileName: string;
|
||||||
|
|
|
@ -33,6 +33,7 @@ type
|
||||||
function CreateSolver: ISolver; override;
|
function CreateSolver: ISolver; override;
|
||||||
published
|
published
|
||||||
procedure TestPart1;
|
procedure TestPart1;
|
||||||
|
procedure TestPart2;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TParabolicReflectorDishExampleTestCase }
|
{ TParabolicReflectorDishExampleTestCase }
|
||||||
|
@ -42,6 +43,7 @@ type
|
||||||
function CreateSolver: ISolver; override;
|
function CreateSolver: ISolver; override;
|
||||||
published
|
published
|
||||||
procedure TestPart1;
|
procedure TestPart1;
|
||||||
|
procedure TestPart2;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
@ -58,6 +60,11 @@ begin
|
||||||
AssertEquals(103614, FSolver.GetResultPart1);
|
AssertEquals(103614, FSolver.GetResultPart1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TParabolicReflectorDishFullDataTestCase.TestPart2;
|
||||||
|
begin
|
||||||
|
AssertEquals(83790, FSolver.GetResultPart2);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TParabolicReflectorDishExampleTestCase }
|
{ TParabolicReflectorDishExampleTestCase }
|
||||||
|
|
||||||
function TParabolicReflectorDishExampleTestCase.CreateSolver: ISolver;
|
function TParabolicReflectorDishExampleTestCase.CreateSolver: ISolver;
|
||||||
|
@ -70,6 +77,11 @@ begin
|
||||||
AssertEquals(136, FSolver.GetResultPart1);
|
AssertEquals(136, FSolver.GetResultPart1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TParabolicReflectorDishExampleTestCase.TestPart2;
|
||||||
|
begin
|
||||||
|
AssertEquals(64, FSolver.GetResultPart2);
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
|
||||||
RegisterTest(TParabolicReflectorDishFullDataTestCase);
|
RegisterTest(TParabolicReflectorDishFullDataTestCase);
|
||||||
|
|
Loading…
Reference in New Issue