Added solution for "Day 3: Gear Ratios", part 2
This commit is contained in:
parent
015b823376
commit
9c4fb8b63a
|
@ -22,21 +22,59 @@ unit UGearRatios;
|
|||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, USolver;
|
||||
Classes, SysUtils, fgl, USolver;
|
||||
|
||||
const
|
||||
CDigitChars = ['0'..'9'];
|
||||
CNonSymbolChars = ['0'..'9', '.'];
|
||||
CGearChar = '*';
|
||||
|
||||
type
|
||||
|
||||
{ TGearCandidate }
|
||||
|
||||
TGearCandidate = class
|
||||
private
|
||||
FColumn, FPartNumber1, FPartNumber2, FPartNumber3: Integer;
|
||||
public
|
||||
constructor Create(AColumn: Integer);
|
||||
procedure AddPartNumber(APartNumber: Integer);
|
||||
function GetGearRatio: Integer;
|
||||
property Column: Integer read FColumn;
|
||||
end;
|
||||
|
||||
{ TGearCandidates }
|
||||
|
||||
TGearCandidates = specialize TFPGObjectList<TGearCandidate>;
|
||||
|
||||
{ TGearCandidateTracker }
|
||||
|
||||
TGearCandidateTracker = class
|
||||
private
|
||||
FPreviousLine, FLine, FNextLine, FCurrentNumber: TGearCandidates;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function GetLine(AIndex: Integer): TGearCandidates;
|
||||
function FinishLine: Integer;
|
||||
property PreviousLine: TGearCandidates read FPreviousLine;
|
||||
property Line: TGearCandidates read FLine;
|
||||
property NextLine: TGearCandidates read FNextLine;
|
||||
property CurrentNumber: TGearCandidates read FCurrentNumber;
|
||||
end;
|
||||
|
||||
{ TGearRatios }
|
||||
|
||||
TGearRatios = class(TSolver)
|
||||
private
|
||||
FPreviousLine, FLine: string;
|
||||
FGearTracker: TGearCandidateTracker;
|
||||
procedure ProcessDataLineTriplet(const APreviousLine, ALine, ANextLine: string);
|
||||
function HasSymbolCharInColumn(const AIndex: Integer; const ALines: array of string): Boolean;
|
||||
procedure LogForCurrentGearCandidates(const APartNumber: Integer);
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure ProcessDataLine(const ALine: string); override;
|
||||
procedure Finish; override;
|
||||
function GetDataFileName: string; override;
|
||||
|
@ -45,6 +83,80 @@ type
|
|||
|
||||
implementation
|
||||
|
||||
{ TGearCandidate }
|
||||
|
||||
constructor TGearCandidate.Create(AColumn: Integer);
|
||||
begin
|
||||
FColumn := AColumn;
|
||||
FPartNumber1 := 0;
|
||||
FPartNumber2 := 0;
|
||||
FPartNumber3 := 0;
|
||||
end;
|
||||
|
||||
procedure TGearCandidate.AddPartNumber(APartNumber: Integer);
|
||||
begin
|
||||
if FPartNumber1 = 0 then
|
||||
FPartNumber1 := APartNumber
|
||||
else if FPartNumber2 = 0 then
|
||||
FPartNumber2 := APartNumber
|
||||
else
|
||||
FPartNumber3 := APartNumber;
|
||||
end;
|
||||
|
||||
function TGearCandidate.GetGearRatio: Integer;
|
||||
begin
|
||||
if FPartNumber3 = 0 then
|
||||
Result := FPartNumber1 * FPartNumber2
|
||||
else
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
{ TGearCandidateTracker }
|
||||
|
||||
constructor TGearCandidateTracker.Create;
|
||||
begin
|
||||
FPreviousLine := TGearCandidates.Create;
|
||||
FLine := TGearCandidates.Create;
|
||||
FNextLine := TGearCandidates.Create;
|
||||
FCurrentNumber := TGearCandidates.Create(False);
|
||||
end;
|
||||
|
||||
destructor TGearCandidateTracker.Destroy;
|
||||
begin
|
||||
FPreviousLine.Free;
|
||||
FLine.Free;
|
||||
FNextLine.Free;
|
||||
FCurrentNumber.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TGearCandidateTracker.GetLine(AIndex: Integer): TGearCandidates;
|
||||
begin
|
||||
case AIndex of
|
||||
0: Result := FPreviousLine;
|
||||
1: Result := FLine;
|
||||
2: Result := FNextLine;
|
||||
else Result := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TGearCandidateTracker.FinishLine: Integer;
|
||||
var
|
||||
candidate: TGearCandidate;
|
||||
temp: TGearCandidates;
|
||||
begin
|
||||
Result := 0;
|
||||
for candidate in FPreviousLine do
|
||||
begin
|
||||
Inc(Result, candidate.GetGearRatio);
|
||||
end;
|
||||
FPreviousLine.Clear;
|
||||
temp := FPreviousLine;
|
||||
FPreviousLine := FLine;
|
||||
FLine := FNextLine;
|
||||
FNextLine := temp;
|
||||
end;
|
||||
|
||||
{ TGearRatios }
|
||||
|
||||
procedure TGearRatios.ProcessDataLineTriplet(const APreviousLine, ALine, ANextLine: string);
|
||||
|
@ -61,35 +173,21 @@ begin
|
|||
begin
|
||||
inNumber := True;
|
||||
numberStart := i;
|
||||
FGearTracker.CurrentNumber.Clear;
|
||||
|
||||
// Checks for a symbol in the column before the first digit.
|
||||
isPartNumber := (i > 1) and
|
||||
(not (APreviousLine[i - 1] in CNonSymbolChars)
|
||||
or not (ALine[i - 1] in CNonSymbolChars)
|
||||
or not (ANextLine[i - 1] in CNonSymbolChars));
|
||||
isPartNumber := (i > 1) and HasSymbolCharInColumn(i - 1, [APreviousLine, ALine, ANextLine]);
|
||||
end;
|
||||
|
||||
// Checks for a symbol in the column of the current digit.
|
||||
if inNumber and not isPartNumber and
|
||||
(not (APreviousLine[i] in CNonSymbolChars)
|
||||
or not (ANextLine[i] in CNonSymbolChars)) then
|
||||
begin
|
||||
if inNumber and HasSymbolCharInColumn(i, [APreviousLine, ALine, ANextLine]) then
|
||||
isPartNumber := True;
|
||||
end;
|
||||
|
||||
// Checks if number ends.
|
||||
if inNumber and (not (ALine[i] in CDigitChars) or (i = ALine.Length)) then
|
||||
begin
|
||||
inNumber := False;
|
||||
|
||||
// Checks for a symbol in the column after the last digit.
|
||||
if not (APreviousLine[i] in CNonSymbolChars)
|
||||
or not (ALine[i] in CNonSymbolChars)
|
||||
or not (ANextLine[i] in CNonSymbolChars) then
|
||||
begin
|
||||
isPartNumber := True;
|
||||
end;
|
||||
|
||||
// Counts if it is a part number.
|
||||
if isPartNumber then
|
||||
begin
|
||||
|
@ -98,9 +196,71 @@ begin
|
|||
Inc(numberLength);
|
||||
partNumber := StrToInt(Copy(ALine, numberStart, numberLength));
|
||||
Inc(FPart1, partNumber);
|
||||
LogForCurrentGearCandidates(partNumber);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
Inc(FPart2, FGearTracker.FinishLine);
|
||||
end;
|
||||
|
||||
function TGearRatios.HasSymbolCharInColumn(const AIndex: Integer; const ALines: array of string): Boolean;
|
||||
var
|
||||
i: Integer;
|
||||
candidates: TGearCandidates;
|
||||
candidate: TGearCandidate;
|
||||
exists: Boolean;
|
||||
begin
|
||||
Result := False;
|
||||
for i := 0 to High(ALines) do
|
||||
if not (ALines[i][AIndex] in CNonSymbolChars) then
|
||||
begin
|
||||
Result := True;
|
||||
// Could exit here for part 1, the following is only for part 2.
|
||||
if ALines[i][AIndex] = CGearChar then
|
||||
begin
|
||||
candidates := FGearTracker.GetLine(i);
|
||||
exists := False;
|
||||
for candidate in candidates do
|
||||
begin
|
||||
if candidate.Column = AIndex then
|
||||
begin
|
||||
// The current gear candidate has already been found.
|
||||
FGearTracker.CurrentNumber.Add(candidate);
|
||||
exists := True;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
if not exists then
|
||||
begin
|
||||
// A new gear candidate was found.
|
||||
candidate := TGearCandidate.Create(AIndex);
|
||||
candidates.Add(candidate);
|
||||
FGearTracker.CurrentNumber.Add(candidate);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TGearRatios.LogForCurrentGearCandidates(const APartNumber: Integer);
|
||||
var
|
||||
candidate: TGearCandidate;
|
||||
begin
|
||||
for candidate in FGearTracker.CurrentNumber do
|
||||
begin
|
||||
candidate.AddPartNumber(APartNumber);
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TGearRatios.Create;
|
||||
begin
|
||||
FGearTracker := TGearCandidateTracker.Create;
|
||||
end;
|
||||
|
||||
destructor TGearRatios.Destroy;
|
||||
begin
|
||||
FGearTracker.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TGearRatios.ProcessDataLine(const ALine: string);
|
||||
|
|
|
@ -44,6 +44,7 @@ type
|
|||
procedure TearDown; override;
|
||||
published
|
||||
procedure TestPart1;
|
||||
procedure TestPart2;
|
||||
end;
|
||||
|
||||
{ TGearRatiosTestCase }
|
||||
|
@ -97,6 +98,12 @@ begin
|
|||
AssertEquals(530495, FSolver.GetResultPart1);
|
||||
end;
|
||||
|
||||
procedure TGearRatiosFullDataTestCase.TestPart2;
|
||||
begin
|
||||
AssertEquals(80253814, FSolver.GetResultPart2);
|
||||
end;
|
||||
|
||||
|
||||
{ TGearRatiosTestCase }
|
||||
|
||||
procedure TGearRatiosTestCase.TestEndOfLineNumber;
|
||||
|
|
|
@ -11,6 +11,8 @@ TGearRatiosFullDataTestCase.Checked=1
|
|||
TGearRatiosFullDataTestCase.Expanded=1
|
||||
TGearRatiosFullDataTestCase.TestPart1.Checked=1
|
||||
TGearRatiosFullDataTestCase.TestPart1.Expanded=0
|
||||
TGearRatiosFullDataTestCase.TestPart2.Checked=1
|
||||
TGearRatiosFullDataTestCase.TestPart2.Expanded=0
|
||||
TGearRatiosTestCase.Checked=1
|
||||
TGearRatiosTestCase.Expanded=1
|
||||
TGearRatiosTestCase.TestEndOfLineNumber.Checked=1
|
||||
|
|
Loading…
Reference in New Issue