Move to have day be 2 digit always
[advent-of-code-2020.git] / day04 / count_valid_passports_2.sh
diff --git a/day04/count_valid_passports_2.sh b/day04/count_valid_passports_2.sh
new file mode 100644 (file)
index 0000000..88fc560
--- /dev/null
@@ -0,0 +1,163 @@
+#!/bin/bash
+
+declare -a data
+cur_data=""
+seperator=""
+valid_count=0
+
+required_fields=(byr iyr eyr hgt hcl ecl pid)
+
+check_year() {
+    value=$1
+    min=$2
+    max=$3
+
+    if [ $value -ge $min ] && [ $value -le $max ]; then
+        exit 0
+    fi
+    exit 1
+}
+
+check_height() {
+    value=$1
+    units=${value:$((${#value}-2)):2}
+    value=${value:0:$((${#value}-2))}
+    case $units in
+        in)
+            if [ $value -ge 59 ] && [ $value -le 76 ]; then
+                exit 0
+            fi
+            ;;
+        cm)
+            if [ $value -ge 150 ] && [ $value -le 193 ]; then
+                exit 0
+            fi
+            ;;
+        *)
+            ;;
+    esac
+    exit 1
+}
+
+check_hair() {
+    value=$1
+
+    if [ ${value:0:1} != "#" ]; then
+        exit 1
+    fi
+
+    if [[ $value =~ /^[a-f0-9]{6}$/ ]]; then
+        exit 1
+    fi
+
+    exit 0
+}
+
+check_eyes() {
+    colour="$1"
+    case $colour in
+        amb|blu|brn|gry|grn|hzl|oth)
+            exit 0
+            ;;
+        *)
+            exit 1
+            ;;
+    esac
+    exit 1
+}
+
+check_data() {
+    local -n record=$1
+    for x in ${!record[@]}; do
+        value=${record[$x]}
+        case $x in
+            byr)
+                if ! ( check_year $value 1920 2002 ); then
+                    exit 1
+                fi
+                ;;
+            iyr)
+                if ! ( check_year $value 2010 2020 ); then
+                    exit 1
+                fi
+                ;;
+            eyr)
+                if ! ( check_year $value 2020 2030 ); then
+                    exit 1
+                fi
+                ;;
+            hgt)
+                if ! ( check_height $value ); then
+                    exit 1
+                fi
+                ;;
+            hcl)
+                if ! ( check_hair $value ); then
+                    exit 1
+                fi
+                ;;
+            ecl)
+                if ! ( check_eyes $value ); then
+                    exit 1
+                fi
+                ;;
+            pid)
+                value=${record[$x]}
+                if [ ${#value} -ne 9 ]; then
+                    exit 1
+                fi
+                ;;
+            *)
+                ;;
+        esac
+    done
+
+    exit 0
+}
+
+exec 3<input.txt
+
+while read -u 3 line; do
+    if [ "$line" = "" ]; then
+        data+=("$cur_data")
+        seperator=""
+        cur_data=""
+        continue
+    fi
+    cur_data="${cur_data}${seperator}$line"
+    seperator=" "
+done
+
+check_fields() {
+    local -n record=$1
+    for field in ${required_fields[@]}; do
+        if ! [ ${record[$field]+a} ]; then
+            exit 1
+        fi
+    done
+
+    exit 0
+}
+
+# on the last line, if cur_data isn't empty, add that to the array
+if [ "$cur_data" != "" ]; then
+    data+=("$cur_data")
+fi
+
+for (( i=0; i<${#data[@]}; i++ )); do
+    record="${data[$i]}"
+    declare -A kvp
+    for field in $record; do
+        key=${field%:*}
+        value=${field#*:}
+        kvp[$key]=$value
+    done
+    if ( check_fields kvp ); then
+        if ( check_data kvp ); then
+            valid_count=$((valid_count+1))
+        fi
+    fi
+    unset kvp
+done
+
+echo "$valid_count valid entries"