Day 8
[advent-of-code-2021.git] / day08 / get_count.sh
diff --git a/day08/get_count.sh b/day08/get_count.sh
new file mode 100755 (executable)
index 0000000..4a89d5e
--- /dev/null
@@ -0,0 +1,156 @@
+#!/bin/bash
+
+set -u
+
+filename="${1:-input.txt}"
+
+exec 3<"$filename"
+
+declare -a all_inputs
+declare -a all_outputs
+
+while read -u 3 -d "|" inputs; do
+    all_inputs+=("$inputs")
+    read -u 3 outputs
+    all_outputs+=("$outputs")
+done
+
+one_count=0 # 2 on signals
+seven_count=0 # 3 on signals
+four_count=0 # 4 on signals
+eight_count=0 # 7 on signals
+
+for output in "${all_outputs[@]}"; do
+    read -a seperates <<<$output
+    for s in "${seperates[@]}"; do
+        case ${#s} in
+            2)
+                ((one_count+=1))
+                ;;
+            3)
+                ((seven_count+=1))
+                ;;
+            4)
+                ((four_count+=1))
+                ;;
+            7)
+                ((eight_count+=1))
+                ;;
+        esac
+    done
+done
+
+echo "1 count: $one_count"
+echo "4 count: $four_count"
+echo "7 count: $seven_count"
+echo "8 count: $eight_count"
+echo
+echo "Total: $((one_count+$four_count+$seven_count+$eight_count))"
+
+declare -A seg_vals=( [a]=1 [b]=2 [c]=4 [d]=8 [e]=16 [f]=32 [g]=64 )
+declare -A char_map=( [119]=0 [36]=1 [93]=2 [109]=3 [46]=4 [107]=5 [123]=6 [37]=7 [127]=8 [111]=9 )
+
+get_digits() {
+    local input="$1"
+    local output="$2"
+    local -A segcounts=( [a]=0 [b]=0 [c]=0 [d]=0 [e]=0 [f]=0 [g]=0 )
+    local -A segmap=( [a]= [b]= [c]= [d]= [e]= [f]= [g]= )
+
+    read -a segs <<<"${input}"
+    for seg in "${segs[@]}"; do
+        for (( a=0; a<${#seg}; a++ )); do
+            ((segcounts[${seg:$a:1}]+=1))
+        done
+    done
+
+    # we've now got some counts, so we can do *some* of the mappings
+    for seg_name in "${!segcounts[@]}"; do
+        case ${segcounts[$seg_name]} in
+            4)
+                segmap[$seg_name]=e
+                ;;
+            6)
+                segmap[$seg_name]=b
+                ;;
+            9)
+                segmap[$seg_name]=f
+                ;;
+            7)
+                segmap[$seg_name]=dg
+                ;;
+            8)
+                segmap[$seg_name]=ac
+                ;;
+        esac
+    done
+
+    # now go through segs again, this time checking how long the string is, because from that
+    # we can find 7, which will give us a.
+
+    for seg in "${segs[@]}"; do
+        case ${#seg} in
+            2)
+                # this is number 1 - it has a c but no a
+                for (( a=0; a<${#seg}; a++ )); do
+                    if [ ${segmap[${seg:$a:1}]} == "ac" ]; then
+                        segmap[${seg:$a:1}]=c
+                        break
+                    fi
+                done
+                # because we've worked out where a is, we now go find the one that thinks it's a or c
+                for seg_name in "${!segmap[@]}"; do
+                    if [ "${segmap[$seg_name]}" == "ac" ]; then
+                        segmap[$seg_name]=a
+                        break
+                    fi
+                done
+                ;;
+            4)
+                # this is number 4
+                for (( a=0; a<${#seg}; a++ )); do
+                    if [ ${segmap[${seg:$a:1}]} == "dg" ]; then
+                        segmap[${seg:$a:1}]=d
+                        break
+                    fi
+                done
+                for seg_name in "${!segmap[@]}"; do
+                    if [ "${segmap[$seg_name]}" == "dg" ]; then
+                        segmap[$seg_name]=g
+                        break
+                    fi
+                done
+                ;;
+        esac
+    done
+
+    output_digits=""
+
+    # finally, we can get each of the digits in the output, so go through the output
+    read -a charsets <<<"${output}"
+    for chars in "${charsets[@]}"; do
+        char_value=0
+        for (( a=0; a<${#chars}; a++ )); do
+            ((char_value+=${seg_vals[${segmap[${chars:$a:1}]}]}))
+        done
+        if [ "${char_map[$char_value]+abc}" ]; then
+            output_digits+=${char_map[$char_value]}
+        else
+            declare -p segmap >&2
+            echo "Chars: $chars" >&2
+            exit 1
+        fi
+    done
+
+    # remove any leading 0s the cheating way
+    echo $((10#$output_digits))
+}
+
+# Now lets start playing with the first input and try working out the outputs
+
+total_output_count=0
+
+for (( a=0; a<${#all_inputs[@]}; a++ )); do
+    ((total_output_count+=$(get_digits "${all_inputs[$a]}" "${all_outputs[$a]}")))
+done
+
+echo "Sum of all output digits: $total_output_count"