hac_0.11.0_c596ed7c/exm/aoc/2020/aoc_2020_04_b_full_ada.adb

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
--  Solution to Advent of Code 2020, Day 04, Part Two
-----------------------------------------------------
--  Passport Processing
--
--  Full Ada version.
--
--  https://adventofcode.com/2020/day/04
--
with Ada.Characters.Handling, Ada.Strings.Fixed, Ada.Text_IO;
with Interfaces;

procedure AoC_2020_04_b_Full_Ada is
  use Ada.Characters.Handling, Ada.Strings.Fixed, Ada.Text_IO, Interfaces;
  --
  function Val (s : String) return Integer_64 is
  begin
    return Integer_64'Value (s);
  exception
    when others => return -1;
  end Val;
  --
  type Cat is (byr, iyr, eyr, hgt, hcl, ecl, pid);
  ok : Boolean;
  f : File_Type;
  cats, cat_idx, total : Integer := 0;
  tok_begin, tok_end : Integer;
begin
  Open (f, In_File, "aoc_2020_04.txt");
  while not End_Of_File (f) loop
    declare
      s : constant String := Get_Line (f);
    begin
      if s = "" then
        cats := 0;
      end if;
      for c in Cat loop
        cat_idx := Index (s, To_Lower (Cat'Image (c)) & ':');
        if cat_idx > 0 then
          tok_begin := cat_idx + 4;
          tok_end := Index (s, " ", tok_begin);
          if tok_end > 0 then
            tok_end := tok_end - 1;
          else
            tok_end := s'Last;
          end if;
          declare
            tok : String renames s (tok_begin .. tok_end);
          begin
            case c is
              when byr => ok := Val (tok) in 1920 .. 2002;
              when iyr => ok := Val (tok) in 2010 .. 2020;
              when eyr => ok := Val (tok) in 2020 .. 2030;
              when hcl => ok := Val ("16" & tok & '#') > 0;
              when pid => ok := tok'Length = 9 and then Val (tok) > 0;
              when ecl => ok := Index ("amb blu brn gry grn hzl oth", tok) > 0;
                                --  ^ Idea: Maxim Reznik, replaces checking each value
              when hgt =>
                ok :=
                    ((Val (s (tok_begin .. tok_end - 2)) in 150 .. 193
                                 and then s (tok_end - 1 .. tok_end) = "cm")
                      or else
                     (Val (s (tok_begin .. tok_end - 2)) in 59 .. 76
                                 and then s (tok_end - 1 .. tok_end) = "in")
                    );
            end case;
          end;
          if ok then cats := cats + 1; end if;
        end if;
      end loop;
      if cats = 7 then
        total := total + 1;
        --  Prevent incrementing total if there is garbage
        --  or a "cid:" until next blank line:
        cats := 0;
      end if;
    end;
  end loop;
  Close (f);
  Put_Line ("Valid passports (criteria #2):" & Integer'Image (total));
end AoC_2020_04_b_Full_Ada;