Fixup day18 and add second part
[advent-of-code-2020.git] / day04 / count_valid_passports_2.sh
1 #!/bin/bash
2
3 declare -a data
4 cur_data=""
5 seperator=""
6 valid_count=0
7
8 required_fields=(byr iyr eyr hgt hcl ecl pid)
9
10 check_year() {
11     value=$1
12     min=$2
13     max=$3
14
15     if [ $value -ge $min ] && [ $value -le $max ]; then
16         exit 0
17     fi
18     exit 1
19 }
20
21 check_height() {
22     value=$1
23     units=${value:$((${#value}-2)):2}
24     value=${value:0:$((${#value}-2))}
25     case $units in
26         in)
27             if [ $value -ge 59 ] && [ $value -le 76 ]; then
28                 exit 0
29             fi
30             ;;
31         cm)
32             if [ $value -ge 150 ] && [ $value -le 193 ]; then
33                 exit 0
34             fi
35             ;;
36         *)
37             ;;
38     esac
39     exit 1
40 }
41
42 check_hair() {
43     value=$1
44
45     if [ ${value:0:1} != "#" ]; then
46         exit 1
47     fi
48
49     if [[ $value =~ /^[a-f0-9]{6}$/ ]]; then
50         exit 1
51     fi
52
53     exit 0
54 }
55
56 check_eyes() {
57     colour="$1"
58     case $colour in
59         amb|blu|brn|gry|grn|hzl|oth)
60             exit 0
61             ;;
62         *)
63             exit 1
64             ;;
65     esac
66     exit 1
67 }
68
69 check_data() {
70     local -n record=$1
71     for x in ${!record[@]}; do
72         value=${record[$x]}
73         case $x in
74             byr)
75                 if ! ( check_year $value 1920 2002 ); then
76                     exit 1
77                 fi
78                 ;;
79             iyr)
80                 if ! ( check_year $value 2010 2020 ); then
81                     exit 1
82                 fi
83                 ;;
84             eyr)
85                 if ! ( check_year $value 2020 2030 ); then
86                     exit 1
87                 fi
88                 ;;
89             hgt)
90                 if ! ( check_height $value ); then
91                     exit 1
92                 fi
93                 ;;
94             hcl)
95                 if ! ( check_hair $value ); then
96                     exit 1
97                 fi
98                 ;;
99             ecl)
100                 if ! ( check_eyes $value ); then
101                     exit 1
102                 fi
103                 ;;
104             pid)
105                 value=${record[$x]}
106                 if [ ${#value} -ne 9 ]; then
107                     exit 1
108                 fi
109                 ;;
110             *)
111                 ;;
112         esac
113     done
114
115     exit 0
116 }
117
118 exec 3<input.txt
119
120 while read -u 3 line; do
121     if [ "$line" = "" ]; then
122         data+=("$cur_data")
123         seperator=""
124         cur_data=""
125         continue
126     fi
127     cur_data="${cur_data}${seperator}$line"
128     seperator=" "
129 done
130
131 check_fields() {
132     local -n record=$1
133     for field in ${required_fields[@]}; do
134         if ! [ ${record[$field]+a} ]; then
135             exit 1
136         fi
137     done
138
139     exit 0
140 }
141
142 # on the last line, if cur_data isn't empty, add that to the array
143 if [ "$cur_data" != "" ]; then
144     data+=("$cur_data")
145 fi
146
147 for (( i=0; i<${#data[@]}; i++ )); do
148     record="${data[$i]}"
149     declare -A kvp
150     for field in $record; do
151         key=${field%:*}
152         value=${field#*:}
153         kvp[$key]=$value
154     done
155     if ( check_fields kvp ); then
156         if ( check_data kvp ); then
157             valid_count=$((valid_count+1))
158         fi
159     fi
160     unset kvp
161 done
162
163 echo "$valid_count valid entries"