Day 14 - implemented in bash, because, well, I could
[advent-of-code-2020.git] / day14 / dockingdata_v2.sh
1 #!/bin/bash
2
3 filename="${1:-p2_208.txt}"
4
5 declare -A mem
6
7 parse_line() {
8     local line="$1"
9     local key=${line% = *}
10     local value=${line#* = }
11     declare -g cur_mask
12     local base_mask
13     local mask
14
15     if [ $key == "mask" ]; then
16         cur_mask=$value
17     else
18         # it's a memory instruction, yay
19         unset masks
20         get_masks $base_mask
21
22         loc=${key%]}
23         loc=${loc#*[}
24         base_mask=$(get_base_mask $cur_mask $loc)
25         unset masks
26         get_masks $base_mask
27         for mask in "${masks[@]}"; do
28             loc=$(get_value $mask $loc)
29             mem[$loc]=$value
30         done
31     fi
32 }
33
34 get_base_mask() {
35     local mask=$1
36     local value=$2
37     local newmask=""
38
39     # here we literally translate the string to contain X if
40     # it's an X, and then check against the value and if either
41     # value or mask has a 1 in that position set it to 1 other
42     # wise set it to 0
43     for (( a=0; a<36; a++ )); do
44         if [ ${mask:$a:1} == "X" ]; then
45             newmask+="X"
46         elif [ ${mask:$a:1} -eq 1 ] || [ $((value & 2**(35-$a))) -gt 0 ]; then
47             newmask+="1"
48         else
49             newmask+="0"
50         fi
51     done
52
53     echo $newmask
54 }
55
56 get_masks() {
57     local string="$1"
58     local test="${string/X/b}"
59     local mask1
60     local mask2
61     declare -g -a masks
62
63     if [ "$string" == "$test" ]; then
64         masks+=( $string )
65         return 0
66     fi
67
68     # do the 2 potential replacements and run them through
69     mask1=${string/X/1}
70     get_masks $mask1
71     mask2=${string/X/0}
72     get_masks $mask2
73 }
74
75 get_value() {
76     local mask="$1"
77     local value="$2"
78     local mask_part1=${mask//X/0}
79     local mask_part2=${mask//1/X}
80     mask_part2=${mask_part2//0/1}
81     mask_part2=${mask_part2//X/0}
82     value=$((value | 2#$mask_part1))
83     value=$(( ~ $value & (2**36)-1 ))
84     value=$((value | 2#$mask_part2))
85     value=$(( ~ $value & (2**36)-1 ))
86     echo $value
87 }
88
89 exec 3<"$filename"
90 while read -u 3 line; do
91     parse_line "$line"
92 done
93
94 total=0
95 for key in ${!mem[@]}; do
96     total=$((total+${mem[$key]}))
97 done
98
99 echo "Total: $total"