Day 16 pt 1 - doesn't actually stack packets hierarchically - just parses the headers
[advent-of-code-2021.git] / day16 / decoder.sh
1 #!/bin/bash
2
3 set -u
4
5 filename=${1:-p1_16.txt}
6 debug=${2:-0}
7
8 exec 3<"${filename}"
9
10 declare -A hex_to_binary=( [0]="0000" [1]="0001" [2]="0010" [3]="0011" [4]="0100" [5]="0101" [6]="0110" [7]="0111" [8]="1000" [9]="1001" [A]="1010" [B]="1011" [C]="1100" [D]="1101" [E]="1110" [F]="1111" )
11
12 read -u 3 hex_string
13
14 declare -g __packets=""
15 for (( a=0; a<${#hex_string}; a++ )); do
16     __packets+=${hex_to_binary[${hex_string:$a:1}]}
17 done
18
19 declare -g __versions_total=0
20
21 declare __packet_offset=0
22
23 if [ $debug == "0"  ]; then
24     echo_verbose() { true; }
25 else
26     echo_verbose() { echo "$@" >&2; }
27 fi
28
29 parse_version() {
30     declare -g __packet_version=$((2#${__packets:$__packet_offset:3}))
31     ((__packet_offset+=3))
32     echo_verbose "Packet version: $__packet_version"
33 }
34
35 parse_type() {
36     declare -g __packet_type=$((2#${__packets:$__packet_offset:3}))
37     ((__packet_offset+=3))
38     echo_verbose "Packet type: $__packet_type"
39 }
40
41 parse_literal() {
42     local keep_going=${__packets:$__packet_offset:1}
43     local binary_value=""
44     ((__packet_offset+=1))
45     while [ $keep_going -eq 1 ]; do
46         binary_value+=${__packets:$__packet_offset:4}
47         ((__packet_offset+=4))
48         keep_going=${__packets:$__packet_offset:1}
49         ((__packet_offset+=1))
50     done
51     # if we're here, we're on to the last group
52     binary_value+=${__packets:$__packet_offset:4}
53     ((__packet_offset+=4))
54     declare -g __packet_literal=$((2#$binary_value))
55     echo_verbose "Packet literal: $__packet_literal"
56 }
57
58 parse_operator() {
59     local len_type=$((2#${__packets:$__packet_offset:1}))
60     ((__packet_offset+=1))
61
62     case $len_type in
63         0)
64             __packets_length=$((2#${__packets:$__packet_offset:15}))
65             ((__packet_offset+=15))
66             ;;
67         1)
68             __packets_count=$((2#${__packets:$__packet_offset:11}))
69             ((__packet_offset+=11))
70             ;;
71     esac
72 }
73
74 parse_packets() {
75     # we'll first need the version and the type, so grab those
76     local pversion
77     local ptype
78
79     while [ $__packet_offset -lt ${#__packets} ]; do
80         parse_version
81         parse_type
82         version=$__packet_version
83         ptype=$__packet_type
84
85         ((__versions_total+=$version))
86
87         echo_verbose "Remaining: ${__packets:$__packet_offset}"
88
89         case $ptype in
90             4)
91                 parse_literal
92                 ;;
93             *)
94                 parse_operator
95                 ;;
96         esac
97
98         if [ $(($__packet_offset+7)) -ge ${#__packets} ]; then
99             break
100         fi
101     done
102 }
103
104 parse_packets
105
106 echo "Total: $__versions_total"