Day 14 - implemented in bash, because, well, I could
[advent-of-code-2020.git] / day14 / dockingdata_v2.sh
diff --git a/day14/dockingdata_v2.sh b/day14/dockingdata_v2.sh
new file mode 100755 (executable)
index 0000000..08aed81
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/bash
+
+filename="${1:-p2_208.txt}"
+
+declare -A mem
+
+parse_line() {
+    local line="$1"
+    local key=${line% = *}
+    local value=${line#* = }
+    declare -g cur_mask
+    local base_mask
+    local mask
+
+    if [ $key == "mask" ]; then
+        cur_mask=$value
+    else
+        # it's a memory instruction, yay
+        unset masks
+        get_masks $base_mask
+
+        loc=${key%]}
+        loc=${loc#*[}
+        base_mask=$(get_base_mask $cur_mask $loc)
+        unset masks
+        get_masks $base_mask
+        for mask in "${masks[@]}"; do
+            loc=$(get_value $mask $loc)
+            mem[$loc]=$value
+        done
+    fi
+}
+
+get_base_mask() {
+    local mask=$1
+    local value=$2
+    local newmask=""
+
+    # here we literally translate the string to contain X if
+    # it's an X, and then check against the value and if either
+    # value or mask has a 1 in that position set it to 1 other
+    # wise set it to 0
+    for (( a=0; a<36; a++ )); do
+        if [ ${mask:$a:1} == "X" ]; then
+            newmask+="X"
+        elif [ ${mask:$a:1} -eq 1 ] || [ $((value & 2**(35-$a))) -gt 0 ]; then
+            newmask+="1"
+        else
+            newmask+="0"
+        fi
+    done
+
+    echo $newmask
+}
+
+get_masks() {
+    local string="$1"
+    local test="${string/X/b}"
+    local mask1
+    local mask2
+    declare -g -a masks
+
+    if [ "$string" == "$test" ]; then
+        masks+=( $string )
+        return 0
+    fi
+
+    # do the 2 potential replacements and run them through
+    mask1=${string/X/1}
+    get_masks $mask1
+    mask2=${string/X/0}
+    get_masks $mask2
+}
+
+get_value() {
+    local mask="$1"
+    local value="$2"
+    local mask_part1=${mask//X/0}
+    local mask_part2=${mask//1/X}
+    mask_part2=${mask_part2//0/1}
+    mask_part2=${mask_part2//X/0}
+    value=$((value | 2#$mask_part1))
+    value=$(( ~ $value & (2**36)-1 ))
+    value=$((value | 2#$mask_part2))
+    value=$(( ~ $value & (2**36)-1 ))
+    echo $value
+}
+
+exec 3<"$filename"
+while read -u 3 line; do
+    parse_line "$line"
+done
+
+total=0
+for key in ${!mem[@]}; do
+    total=$((total+${mem[$key]}))
+done
+
+echo "Total: $total"