Day 16 pt 1 - doesn't actually stack packets hierarchically - just parses the headers
[advent-of-code-2021.git] / day16 / decoder.sh
diff --git a/day16/decoder.sh b/day16/decoder.sh
new file mode 100755 (executable)
index 0000000..fe67cbd
--- /dev/null
@@ -0,0 +1,106 @@
+#!/bin/bash
+
+set -u
+
+filename=${1:-p1_16.txt}
+debug=${2:-0}
+
+exec 3<"${filename}"
+
+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" )
+
+read -u 3 hex_string
+
+declare -g __packets=""
+for (( a=0; a<${#hex_string}; a++ )); do
+    __packets+=${hex_to_binary[${hex_string:$a:1}]}
+done
+
+declare -g __versions_total=0
+
+declare __packet_offset=0
+
+if [ $debug == "0"  ]; then
+    echo_verbose() { true; }
+else
+    echo_verbose() { echo "$@" >&2; }
+fi
+
+parse_version() {
+    declare -g __packet_version=$((2#${__packets:$__packet_offset:3}))
+    ((__packet_offset+=3))
+    echo_verbose "Packet version: $__packet_version"
+}
+
+parse_type() {
+    declare -g __packet_type=$((2#${__packets:$__packet_offset:3}))
+    ((__packet_offset+=3))
+    echo_verbose "Packet type: $__packet_type"
+}
+
+parse_literal() {
+    local keep_going=${__packets:$__packet_offset:1}
+    local binary_value=""
+    ((__packet_offset+=1))
+    while [ $keep_going -eq 1 ]; do
+        binary_value+=${__packets:$__packet_offset:4}
+        ((__packet_offset+=4))
+        keep_going=${__packets:$__packet_offset:1}
+        ((__packet_offset+=1))
+    done
+    # if we're here, we're on to the last group
+    binary_value+=${__packets:$__packet_offset:4}
+    ((__packet_offset+=4))
+    declare -g __packet_literal=$((2#$binary_value))
+    echo_verbose "Packet literal: $__packet_literal"
+}
+
+parse_operator() {
+    local len_type=$((2#${__packets:$__packet_offset:1}))
+    ((__packet_offset+=1))
+
+    case $len_type in
+        0)
+            __packets_length=$((2#${__packets:$__packet_offset:15}))
+            ((__packet_offset+=15))
+            ;;
+        1)
+            __packets_count=$((2#${__packets:$__packet_offset:11}))
+            ((__packet_offset+=11))
+            ;;
+    esac
+}
+
+parse_packets() {
+    # we'll first need the version and the type, so grab those
+    local pversion
+    local ptype
+
+    while [ $__packet_offset -lt ${#__packets} ]; do
+        parse_version
+        parse_type
+        version=$__packet_version
+        ptype=$__packet_type
+
+        ((__versions_total+=$version))
+
+        echo_verbose "Remaining: ${__packets:$__packet_offset}"
+
+        case $ptype in
+            4)
+                parse_literal
+                ;;
+            *)
+                parse_operator
+                ;;
+        esac
+
+        if [ $(($__packet_offset+7)) -ge ${#__packets} ]; then
+            break
+        fi
+    done
+}
+
+parse_packets
+
+echo "Total: $__versions_total"