Day 8
[advent-of-code-2021.git] / day08 / get_count.sh
1 #!/bin/bash
2
3 set -u
4
5 filename="${1:-input.txt}"
6
7 exec 3<"$filename"
8
9 declare -a all_inputs
10 declare -a all_outputs
11
12 while read -u 3 -d "|" inputs; do
13     all_inputs+=("$inputs")
14     read -u 3 outputs
15     all_outputs+=("$outputs")
16 done
17
18 one_count=0 # 2 on signals
19 seven_count=0 # 3 on signals
20 four_count=0 # 4 on signals
21 eight_count=0 # 7 on signals
22
23 for output in "${all_outputs[@]}"; do
24     read -a seperates <<<$output
25     for s in "${seperates[@]}"; do
26         case ${#s} in
27             2)
28                 ((one_count+=1))
29                 ;;
30             3)
31                 ((seven_count+=1))
32                 ;;
33             4)
34                 ((four_count+=1))
35                 ;;
36             7)
37                 ((eight_count+=1))
38                 ;;
39         esac
40     done
41 done
42
43 echo "1 count: $one_count"
44 echo "4 count: $four_count"
45 echo "7 count: $seven_count"
46 echo "8 count: $eight_count"
47 echo
48 echo "Total: $((one_count+$four_count+$seven_count+$eight_count))"
49
50 declare -A seg_vals=( [a]=1 [b]=2 [c]=4 [d]=8 [e]=16 [f]=32 [g]=64 )
51 declare -A char_map=( [119]=0 [36]=1 [93]=2 [109]=3 [46]=4 [107]=5 [123]=6 [37]=7 [127]=8 [111]=9 )
52
53 get_digits() {
54     local input="$1"
55     local output="$2"
56     local -A segcounts=( [a]=0 [b]=0 [c]=0 [d]=0 [e]=0 [f]=0 [g]=0 )
57     local -A segmap=( [a]= [b]= [c]= [d]= [e]= [f]= [g]= )
58
59     read -a segs <<<"${input}"
60     for seg in "${segs[@]}"; do
61         for (( a=0; a<${#seg}; a++ )); do
62             ((segcounts[${seg:$a:1}]+=1))
63         done
64     done
65
66     # we've now got some counts, so we can do *some* of the mappings
67     for seg_name in "${!segcounts[@]}"; do
68         case ${segcounts[$seg_name]} in
69             4)
70                 segmap[$seg_name]=e
71                 ;;
72             6)
73                 segmap[$seg_name]=b
74                 ;;
75             9)
76                 segmap[$seg_name]=f
77                 ;;
78             7)
79                 segmap[$seg_name]=dg
80                 ;;
81             8)
82                 segmap[$seg_name]=ac
83                 ;;
84         esac
85     done
86
87     # now go through segs again, this time checking how long the string is, because from that
88     # we can find 7, which will give us a.
89
90     for seg in "${segs[@]}"; do
91         case ${#seg} in
92             2)
93                 # this is number 1 - it has a c but no a
94                 for (( a=0; a<${#seg}; a++ )); do
95                     if [ ${segmap[${seg:$a:1}]} == "ac" ]; then
96                         segmap[${seg:$a:1}]=c
97                         break
98                     fi
99                 done
100                 # because we've worked out where a is, we now go find the one that thinks it's a or c
101                 for seg_name in "${!segmap[@]}"; do
102                     if [ "${segmap[$seg_name]}" == "ac" ]; then
103                         segmap[$seg_name]=a
104                         break
105                     fi
106                 done
107                 ;;
108             4)
109                 # this is number 4
110                 for (( a=0; a<${#seg}; a++ )); do
111                     if [ ${segmap[${seg:$a:1}]} == "dg" ]; then
112                         segmap[${seg:$a:1}]=d
113                         break
114                     fi
115                 done
116                 for seg_name in "${!segmap[@]}"; do
117                     if [ "${segmap[$seg_name]}" == "dg" ]; then
118                         segmap[$seg_name]=g
119                         break
120                     fi
121                 done
122                 ;;
123         esac
124     done
125
126     output_digits=""
127
128     # finally, we can get each of the digits in the output, so go through the output
129     read -a charsets <<<"${output}"
130     for chars in "${charsets[@]}"; do
131         char_value=0
132         for (( a=0; a<${#chars}; a++ )); do
133             ((char_value+=${seg_vals[${segmap[${chars:$a:1}]}]}))
134         done
135         if [ "${char_map[$char_value]+abc}" ]; then
136             output_digits+=${char_map[$char_value]}
137         else
138             declare -p segmap >&2
139             echo "Chars: $chars" >&2
140             exit 1
141         fi
142     done
143
144     # remove any leading 0s the cheating way
145     echo $((10#$output_digits))
146 }
147
148 # Now lets start playing with the first input and try working out the outputs
149
150 total_output_count=0
151
152 for (( a=0; a<${#all_inputs[@]}; a++ )); do
153     ((total_output_count+=$(get_digits "${all_inputs[$a]}" "${all_outputs[$a]}")))
154 done
155
156 echo "Sum of all output digits: $total_output_count"