diff --git a/solvers/ULensLibrary.pas b/solvers/ULensLibrary.pas index d6831d7..134dd7b 100644 --- a/solvers/ULensLibrary.pas +++ b/solvers/ULensLibrary.pas @@ -22,16 +22,45 @@ unit ULensLibrary; interface uses - Classes, SysUtils, USolver; + Classes, SysUtils, Generics.Collections, USolver; type + { TLens } + + TLens = record + Key: string; + FocalLength: Byte; + end; + + TBoxContent = specialize TList; + + TBoxes = specialize TObjectList; + + { THashMap } + + THashMap = class + private + FBoxes: TBoxes; + function IndexOf(const AHash: Byte; const AKey: string): Integer; + public + constructor Create; + destructor Destroy; override; + function CalcHash(const AInput: string): Byte; + procedure AddLens(const AKey: string; const AFocalLength: Byte); + procedure RemoveLens(const AKey: string); + function CalcFocusingPower: Int64; + end; + { TLensLibrary } TLensLibrary = class(TSolver) private - function CalcHash(const AInput: string): Byte; + FHashMap: THashMap; + procedure ProcessInstruction(const AInstruction: string); public + constructor Create; + destructor Destroy; override; procedure ProcessDataLine(const ALine: string); override; procedure Finish; override; function GetDataFileName: string; override; @@ -40,9 +69,41 @@ type implementation -{ TLensLibrary } +{ THashMap } -function TLensLibrary.CalcHash(const AInput: string): Byte; +function THashMap.IndexOf(const AHash: Byte; const AKey: string): Integer; +var + i: Integer; +begin + Result := -1; + i := 0; + while (i < FBoxes[AHash].Count) and (Result < 0) do + begin + if FBoxes[AHash][i].Key = AKey then + Result := i; + Inc(i); + end; +end; + +constructor THashMap.Create; +var + i: Integer; +begin + FBoxes := TBoxes.Create; + FBoxes.Count := 256; + for i := 0 to FBoxes.Count - 1 do + begin + FBoxes[i] := TBoxContent.Create; + end; +end; + +destructor THashMap.Destroy; +begin + FBoxes.Free; + inherited Destroy; +end; + +function THashMap.CalcHash(const AInput: string): Byte; var c: Char; begin @@ -51,6 +112,72 @@ begin Result := ((Result + Ord(c)) * 17) and 255; end; +procedure THashMap.AddLens(const AKey: string; const AFocalLength: Byte); +var + hash: Byte; + i: Integer; + lens: TLens; +begin + hash := CalcHash(AKey); + i := IndexOf(hash, AKey); + if i >= 0 then + begin + lens := FBoxes[hash][i]; + lens.FocalLength := AFocalLength; + FBoxes[hash][i] := lens; + end + else begin + lens.Key := AKey; + lens.FocalLength := AFocalLength; + FBoxes[hash].Add(lens); + end; +end; + +procedure THashMap.RemoveLens(const AKey: string); +var + hash: Byte; + i: Integer; +begin + hash := CalcHash(AKey); + i := IndexOf(hash, AKey); + if i >= 0 then + FBoxes[hash].Delete(i); +end; + +function THashMap.CalcFocusingPower: Int64; +var + i, j: Integer; +begin + Result := 0; + for i := 0 to FBoxes.Count - 1 do + for j := 0 to FBoxes[i].Count - 1 do + Inc(Result, (i + 1) * (j + 1) * FBoxes[i][j].FocalLength); +end; + +{ TLensLibrary } + +procedure TLensLibrary.ProcessInstruction(const AInstruction: string); +var + len: Integer; +begin + len := Length(AInstruction); + if AInstruction[len] = '-' then + FHashMap.RemoveLens(Copy(AInstruction, 1, len - 1)) + else + FHashMap.AddLens(Copy(AInstruction, 1, len - 2), StrToInt(AInstruction[len])); +end; + +constructor TLensLibrary.Create; +begin + FHashMap := THashMap.Create; +end; + +destructor TLensLibrary.Destroy; +begin + FHashMap.Free; + inherited Destroy; +end; + procedure TLensLibrary.ProcessDataLine(const ALine: string); var split: TStringArray; @@ -58,12 +185,15 @@ var begin split := ALine.Split(','); for s in split do - Inc(FPart1, CalcHash(s)); + begin + Inc(FPart1, FHashMap.CalcHash(s)); + ProcessInstruction(s); + end; end; procedure TLensLibrary.Finish; begin - + FPart2 := FHashMap.CalcFocusingPower; end; function TLensLibrary.GetDataFileName: string; diff --git a/tests/ULensLibraryTestCases.pas b/tests/ULensLibraryTestCases.pas index f22a345..98abdfa 100644 --- a/tests/ULensLibraryTestCases.pas +++ b/tests/ULensLibraryTestCases.pas @@ -33,6 +33,7 @@ type function CreateSolver: ISolver; override; published procedure TestPart1; + procedure TestPart2; end; { TLensLibraryExampleTestCase } @@ -42,6 +43,7 @@ type function CreateSolver: ISolver; override; published procedure TestPart1; + procedure TestPart2; end; implementation @@ -58,6 +60,11 @@ begin AssertEquals(519041, FSolver.GetResultPart1); end; +procedure TLensLibraryFullDataTestCase.TestPart2; +begin + AssertEquals(260530, FSolver.GetResultPart2); +end; + { TLensLibraryExampleTestCase } function TLensLibraryExampleTestCase.CreateSolver: ISolver; @@ -70,6 +77,11 @@ begin AssertEquals(1320, FSolver.GetResultPart1); end; +procedure TLensLibraryExampleTestCase.TestPart2; +begin + AssertEquals(145, FSolver.GetResultPart2); +end; + initialization RegisterTest(TLensLibraryFullDataTestCase);