[rocher][6][Ada] Delete only one character to get Part 1.
Part 2 here:
pragma Ada_2022;
with Ada.Text_IO; use Ada.Text_IO;
procedure Day06_P2 is
subtype Marker_Type is String (1 .. 14);
function Is_Marker (M : Marker_Type) return Boolean is
begin
for X in M'First .. M'Last - 1 loop
for Y in X + 1 .. M'Last loop
if M (X) = M (Y) then
return False;
end if;
end loop;
end loop;
return True;
end Is_Marker;
procedure Insert (M : in out Marker_Type; C : Character) is
begin
M (M'First .. M'Last - 1) := M (M'First + 1 .. M'Last);
M (M'Last) := C;
end Insert;
Marker : Marker_Type;
Next_Char : Character;
Position : Natural := Marker'Last;
Input : File_Type;
begin
Open (Input, In_File, "input.txt");
Get (Input, Marker);
while not Is_Marker (Marker) loop
Get (Input, Next_Char);
Insert (Marker, Next_Char);
Position := @ + 1;
end loop;
Close (Input);
Put_Line ("Answer:" & Position'Image);
end Day06_P2;
[rocher][7][Ada] Here parts 1 & 2, using a mix between trees and lists
pragma Ada_2022;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Containers.Doubly_Linked_Lists; use Ada.Containers;
procedure Day07_P1 is
type Node_Type;
type Node_Access is access all Node_Type;
package Node_Package is new Doubly_Linked_Lists (Node_Access);
use Node_Package;
subtype Node_Name is Unbounded_String;
function To_Node_Name (Str : String) return Node_Name renames
To_Unbounded_String;
type Subdirectory is access all Node_Package.List;
type Node_Type is record
parent : Node_Access := null;
name : Node_Name := Null_Unbounded_String;
size : Natural := 0;
dir : Subdirectory := null;
end record;
procedure Set_File_Size (Node : Node_Access; Size : Natural) is
Parent : Node_Access := Node.parent;
begin
Node.size := Size;
while Parent /= null loop
Parent.size := @ + Size;
Parent := Parent.parent;
end loop;
end Set_File_Size;
-- Set file size and propagate the size (add) to parent directories
procedure Add_Node
(Node : Node_Access; Name : Node_Name; Size : Natural := 0)
is
New_Node : Node_Access := new Node_Type;
begin
New_Node.parent := Node;
New_Node.name := Name;
if Node.dir = null then
Node.dir := new Node_Package.List;
end if;
Node.dir.Append (New_Node);
if Size > 0 then
Set_File_Size (New_Node, Size);
end if;
end Add_Node;
-- Append a new node to the subdirectory
function Change_Directory
(CWD : Node_Access; Name : Node_Name) return Node_Access
is
Dir : Node_Package.Cursor := CWD.dir.First;
begin
while Element (Dir).name /= Name loop
Dir := Next (Dir);
end loop;
return Element (Dir);
end Change_Directory;
-- Change from CWD to directory 'Name'
function Select_and_Sum (Node : Node_Access) return Natural is
Child : Node_Package.Cursor;
ฮฃ_size : Natural := 0;
begin
if Node.dir /= null then
if Node.size <= 100_000 then
ฮฃ_size := @ + Node.size;
end if;
Child := Node.dir.First;
while Child /= Node_Package.No_Element loop
ฮฃ_size := @ + Select_and_Sum (Element (Child));
Child := Next (Child);
end loop;
end if;
return ฮฃ_size;
end Select_and_Sum;
-- Returns the sum of the directories with size <= 100_000
function Select_Smallest
(Node : Node_Access := null; Used : Natural := 0; Min : Natural := 0)
return Natural
is
Child : Node_Package.Cursor;
Used_Size : Natural := Used;
Min_Size : Natural := Min;
begin
if Node.name = To_Node_Name ("/") then
Used_Size := Node.size;
Min_Size := Node.size;
end if;
if Node.dir /= null then
if 70_000_000 + Node.size - Used_Size >= 30_000_000 and
Node.size < Min_Size
then
Min_Size := Node.size;
end if;
Child := Node.dir.First;
while Child /= Node_Package.No_Element loop
Min_Size :=
Select_Smallest (Element (Child), Used_Size, Min_Size);
Child := Next (Child);
end loop;
end if;
return Min_Size;
end Select_Smallest;
-- Returns the size of the smallest directory that provides enough space
Root : Node_Access := new Node_Type;
CWD : Node_Access := Root; -- current working directory
Input : File_Type;
begin
Root.name := To_Node_Name ("/");
Open (Input, In_File, "input.txt");
loop
declare
Line : String := Get_Line (Input);
begin
if Line (1) = '$' then -- new command
if Line (3 .. 4) = "cd" then
declare
Name : Node_Name :=
To_Node_Name (Line (6 .. Line'Last));
begin
if Name = "/" then
CWD := Root;
elsif Name = ".." then
CWD := CWD.parent;
else
CWD := Change_Directory (CWD, Name);
end if;
end;
else
null; -- start new 'ls' command
end if;
else -- continue with current 'ls' command
declare
Space : Natural := Index (To_Unbounded_String (Line), " ");
Size : Natural := 0;
Name : Node_Name :=
To_Node_Name (Line (Space + 1 .. Line'Last));
begin
if Line (1) in '0' .. '9' then
Size := Natural'Value (Line (1 .. Space - 1));
end if;
Add_Node (CWD, Name, Size);
end;
end if;
end;
exit when End_Of_File (Input);
end loop;
Close (Input);
Put_Line ("Answer part 1:" & Natural'Image (Select_and_Sum (Root)));
Put_Line ("Answer part 2:" & Natural'Image (Select_Smallest (Root)));
end Day07_P1;
The permalink above points to my original solution, but then reading about reznikmmโs solution with a recursive parser, I redid it just using an array, and it still uses SPARK mode: