with Ada.Text_IO; use Ada.Text_IO; procedure Day_6 is Parse_Error : Exception; type Instruction is ( None, Turn_On, Turn_Off, Toggle); type Instr is record Inst : Instruction := None; X0, Y0, X1, Y1 : Natural; end record; function Read_Coordinates( Text : String ) return Instr is Output : Instr; Start_Num : Natural := Text'First; Thr : String := "through"; Thr_Idx : Natural := Thr'First; type State is (Start, X0, Y0, Through, X1, Y1); St : State := Start; begin for I in Text'Range loop case St is when Start => case Text(I) is when '0' .. '9' => Start_Num := I; St := X0; when others => raise Parse_Error with "Invalid character"; end case; when X0 => case Text(I) is when '0' .. '9' => null; when ',' => Output.X0 := Natural'Value(Text(Start_Num .. I-1)); Start_Num := I+1; St := Y0; when others => raise Parse_Error with "Invalid character"; end case; when Y0 => case Text(I) is when '0' .. '9' => null; when ' ' => Output.Y0 := Natural'Value(Text(Start_Num .. I-1)); St := Through; when others => raise Parse_Error with "Invalid character"; end case; when Through => if Thr_Idx > Thr'Last then if Text(I) = ' ' then St := X1; Start_Num := I+1; else raise Parse_Error with "Invalid character"; end if; else if Text(I) = Thr(Thr_Idx) then Thr_Idx := @ + 1; else raise Parse_Error with "Invalid character"; end if; end if; when X1 => case Text(I) is when '0' .. '9' => null; when ',' => Output.X1 := Natural'Value(Text(Start_Num .. I-1)); Start_Num := I+1; St := Y1; when others => raise Parse_Error with "Invalid character"; end case; when Y1 => case Text(I) is when '0' .. '9' => null; when others => raise Parse_Error with "Invalid character"; end case; if I = Text'Last then Output.Y1 := Natural'Value(Text(Start_Num .. I)); end if; end case; end loop; return Output; end Read_Coordinates; function Read_Instruction( Text : String ) return Instr is Idx : Natural := Text'First; Inst : Instr; begin if Text(Idx .. Idx + 3) = "turn" then if Text(Idx + 5 .. Idx + 6) = "on" then Inst := Read_Coordinates( Text( Idx + 8 .. Text'Last)); Inst.Inst := Turn_On; elsif Text(Idx + 5 .. Idx + 7) = "off" then Inst := Read_Coordinates( Text( Idx + 9 .. Text'Last)); Inst.Inst := Turn_Off; else raise Parse_Error with "no on/off found"; end if; elsif Text(Idx .. Idx + 5) = "toggle" then Inst := Read_Coordinates( Text( Idx + 7 .. Text'Last)); Inst.Inst := Toggle; else raise Parse_Error with "Illegal Instruction"; end if; return Inst; end Read_Instruction; type BMatrix is array (Natural range <>, Natural range <>) of Boolean; type IMatrix is array (Natural range <>, Natural range <>) of Natural; function Day_1_1( File_Name : String ) return Natural is Sum : Natural := 0; Lights : Bmatrix(0 .. 999, 0 .. 999 ) := (others => (others => False)); File : File_Type; begin Open(File, In_File, File_Name); while not End_Of_File(File) loop declare Inst : Instr := Read_Instruction(Get_Line(File)); begin for I in Inst.X0 .. Inst.X1 loop for J in Inst.Y0 .. Inst.Y1 loop case Inst.Inst is when None => raise Parse_Error with "Cannot have none instruction"; when Toggle => Lights(I,J) := @ xor True; when Turn_On => Lights(I,J) := True; when Turn_Off => Lights(I,J) := False; end case; end loop; end loop; end; end loop; for I in 0 .. 999 loop for J in 0 .. 999 loop if Lights(I,J) = True then Sum := @ + 1; end if; end loop; end loop; Close(File); return Sum; end Day_1_1; function Day_1_2( File_Name : String ) return Natural is Sum : Natural := 0; Lights : Imatrix(0 .. 999, 0 .. 999 ) := (others => (others => 0)); File : File_Type; begin Open(File, In_File, File_Name); while not End_Of_File(File) loop declare Inst : Instr := Read_Instruction(Get_Line(File)); begin for I in Inst.X0 .. Inst.X1 loop for J in Inst.Y0 .. Inst.Y1 loop case Inst.Inst is when None => raise Parse_Error with "Cannot have none instruction"; when Toggle => Lights(I,J) := @ + 2; when Turn_On => Lights(I,J) := @ + 1; when Turn_Off => Lights(I,J) := Natural'Max(0, @ - 1); end case; end loop; end loop; end; end loop; for I in 0 .. 999 loop for J in 0 .. 999 loop Sum := @ + Lights(I,J); end loop; end loop; Close(File); return Sum; end Day_1_2; File_Name : String := "input_day_6.txt"; begin Put_Line("Christmas lights on" & Day_1_1(File_Name)'Image); Put_Line("Christmas lights on" & Day_1_2(File_Name)'Image); end Day_6;