Learning/AoC/2015/day_3/day_3.adb
2025-03-19 20:08:32 +01:00

121 lines
3.3 KiB
Ada

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers; use Ada.Containers;
with Ada.Containers.Hashed_Sets;
procedure Day_3 is
type Uint32 is mod 2**32;
type Coordinate is
record
X : Uint32;
Y : Uint32;
end record;
function "=" (A,B : Coordinate) return Boolean is
begin
return A.X = B.X and A.Y = B.Y;
end "=";
type Coordinates is array (Natural range <>) of Coordinate;
function Hash(A : Uint32) return Uint32 is
Key : Uint32 := A;
begin
Key := (not @) + (@ * 2**15);
Key := @ or (@ / 2**12);
Key := @ + (@ * 2**2);
Key := @ or (@ / 2**4);
Key := @ * 2057;
Key := @ or (Key / 2**16);
return Key;
end Hash;
function Hash(A : Coordinate) return Hash_Type is
Result : UInt32 := Hash((53 + Hash(A.X)) * 53 + Hash(A.Y));
begin
return Hash_Type(Integer(Result/2));
end Hash;
package Set is new Ada.Containers.Hashed_Sets(
Element_Type => Coordinate,
Hash => Hash,
Equivalent_Elements => "=");
function Read_File(File_Name : String) return Set.Set is
S : Set.Set;
Base : Coordinate := ( X => 0, Y => 0);
File : File_Type;
begin
S.Insert(Base);
Open(File, In_File, File_Name);
main_loop:
while not End_Of_File(File) loop
declare
Line : String := Get_Line(File);
begin
for I in Line'Range loop
case Line(I) is
when '^' => Base.Y := @ + 1;
when 'v' => Base.Y := @ - 1;
when '>' => Base.X := @ + 1;
when '<' => Base.X := @ - 1;
when others => exit main_loop;
end case;
if not S.Contains(Base) then
S.Insert(Base);
end if;
end loop;
end;
end loop main_loop;
Close(File);
return S;
end Read_File;
function Read_File_Part_Two(File_Name : String) return Set.Set is
S : Set.Set;
Base : Coordinates(0 .. 1) :=
(others => (X => 0, Y => 0));
File : File_Type;
Santa : Natural := 0;
begin
S.Insert(Base(0));
Open(File, In_File, File_Name);
main_loop:
while not End_Of_File(File) loop
declare
Line : String := Get_Line(File);
begin
for I in Line'Range loop
case Line(I) is
when '^' => Base(Santa).Y := @ + 1;
when 'v' => Base(Santa).Y := @ - 1;
when '>' => Base(Santa).X := @ + 1;
when '<' => Base(Santa).X := @ - 1;
when others => exit main_loop;
end case;
if not S.Contains(Base(Santa)) then
S.Insert(Base(Santa));
end if;
Santa := (@ + 1) mod 2;
end loop;
end;
end loop main_loop;
Close(File);
return S;
end Read_File_Part_Two;
File_Name : String := "input_day_3.txt";
S : Set.Set;
begin
Put_Line(Read_File_Part_Two(File_Name).Length'Image);
end Day_3;