First attempt
authorBrett Parker <iDunno@sommitrealweird.co.uk>
Sun, 6 Dec 2020 17:23:35 +0000 (17:23 +0000)
committerBrett Parker <iDunno@sommitrealweird.co.uk>
Sun, 6 Dec 2020 17:23:35 +0000 (17:23 +0000)
day3/wires.sh [new file with mode: 0644]

diff --git a/day3/wires.sh b/day3/wires.sh
new file mode 100644 (file)
index 0000000..a28765a
--- /dev/null
@@ -0,0 +1,235 @@
+#!/bin/bash
+
+set -u
+set -e
+
+# these wires should give 6
+#wire_1=(R8 U5 L5 D3)
+#wire_2=(U7 R6 D4 L4)
+
+# these wires should get 159
+#wire_1=(R75 D30 R83 U83 L12 D49 R71 U7 L72)
+#wire_2=(U62 R66 U55 R34 D71 R55 D58 R83)
+
+# these wires should get 135
+wire_1=(R98 U47 R26 D63 R33 U87 L62 D20 R33 U53 R51)
+wire_2=(U98 R91 D20 R16 D67 R40 U7 R15 U6 R7)
+
+# read in data from file instead
+#exec 3<input.txt
+#IFS="," read -u 3 -a wire_1
+#IFS="," read -u 3 -a wire_2
+
+get_min_max() {
+    local -n wire=$1
+    horz_min=0
+    horz_max=0
+    vert_min=0
+    vert_max=0
+    cur_horz=0
+    cur_vert=0
+    for instruction in "${wire[@]}"; do
+        direction=${instruction:0:1}
+        amount=${instruction:1}
+        case $direction in
+            U)
+                cur_vert=$((cur_vert+$amount))
+                if [ $cur_vert -gt $vert_max ]; then
+                    vert_max=$cur_vert
+                fi
+                ;;
+            D)
+                cur_vert=$((cur_vert-$amount))
+                if [ $cur_vert -lt $vert_min ]; then
+                    vert_min=$cur_vert
+                fi
+                ;;
+            R)
+                cur_horz=$((cur_horz+$amount))
+                if [ $cur_horz -gt $horz_max ]; then
+                    horz_max=$cur_horz
+                fi
+                ;;
+            L)
+                cur_horz=$((cur_horz-$amount))
+                if [ $cur_horz -lt $horz_min ]; then
+                    horz_min=$cur_horz
+                fi
+                ;;
+        esac
+    done
+
+    echo "$horz_min,$horz_max,$vert_min,$vert_max"
+}
+
+trace_wire() {
+    local -n w=$1
+    local -n b=$2
+    local -n c=$3
+    min_left=$4
+    cur_vert=0
+    cur_horz=0
+    moved=0
+    last_replace_char="-"
+
+    for operation in "${w[@]}"; do
+        direction=${operation:0:1}
+        amount=${operation:1}
+        case $direction in
+            U)
+                operator=+
+                ;;
+            D)
+                operator=-
+                ;;
+            L)
+                operator=-
+                ;;
+            R)
+                operator=+
+                ;;
+        esac
+
+        case $direction in
+            U|D)
+                last_replace_char="|"
+                offset=$((0-$min_left))
+                offset=$((offset+$cur_horz))
+                for (( moved=1; moved <= $amount; moved++ )); do
+                    cur_vert=$((cur_vert${operator}1))
+                    cur_line=${b[$cur_vert]}
+                    cur_char=${cur_line:$offset:1}
+                    replace_char="|"
+                    if [ $cur_char = "-" ] || [ $cur_char = "|" ]; then
+                        replace_char="X"
+                        c+=($cur_horz,$cur_vert)
+                    fi
+                    if [ $moved -eq $amount ]; then
+                        replace_char="+"
+                    fi
+                    if [ $cur_vert -eq 0 ] && [ $cur_horz -eq 0 ]; then
+                        replace_char='o'
+                    fi
+                    new_line="${cur_line:0:$((offset))}${replace_char}${cur_line:$((offset+1))}"
+                    b[$cur_vert]=$new_line
+                done
+                ;;
+            L|R)
+                last_replace_char="-"
+                # this could change multiple characters in the line
+                for (( moved=1; moved <= $amount; moved++ )); do
+                    cur_horz=$((cur_horz${operator}1))
+                    offset=$((0-$min_left))
+                    offset=$((offset+$cur_horz))
+                    cur_line=${b[$cur_vert]}
+                    cur_char=${cur_line:$offset:1}
+                    replace_char="-"
+                    if [ $cur_char = "-" ] || [ $cur_char = "|" ]; then
+                        replace_char="X"
+                        c+=($cur_horz,$cur_vert)
+                    fi
+                    if [ $moved -eq $amount ]; then
+                        replace_char="+"
+                    fi
+                    if [ $cur_vert -eq 0 ] && [ $cur_horz -eq 0 ]; then
+                        replace_char='o'
+                    fi
+                    new_line="${cur_line:0:$((offset))}${replace_char}${cur_line:$((offset+1))}"
+                    b[$cur_vert]=$new_line
+                done
+                ;;
+        esac
+    done
+
+    cur_line=${b[$cur_vert]}
+    offset=$((0-$min_left))
+    offset=$((offset+$cur_horz))
+    if [ ${cur_line:$offset:1} != 'X' ]; then
+        new_line="${cur_line:0:$((offset))}${last_replace_char}${cur_line:$((offset+1))}"
+        b[$cur_vert]=$new_line
+    fi
+    echo
+}
+
+make_board() {
+    local -n mm=$1
+    local -n b=$2
+
+    min_horz=${mm[0]}
+    if [ $min_horz -gt 0 ]; then
+        min_horz=0
+    fi
+
+    min_vert=${mm[2]}
+    if [ $min_vert -gt 0 ]; then
+        min_vert=0
+    fi
+
+    max_horz=${mm[1]}
+    total_horz=$(($max_horz - $min_horz))
+
+    max_vert=${mm[3]}
+
+    cur_vert=${min_vert}
+    blank_string=$(printf ".%.0s" $(eval echo '{0..'$total_horz'}'))
+    while [[ $cur_vert -le ${max_vert} ]]; do
+        if [[ $cur_vert -eq 0 ]]; then
+            offset=$((0-${mm[0]}))
+            line="${blank_string:0:$offset}o${blank_string:$((offset+1))}"
+            b[$cur_vert]=$line
+        else
+            b[$cur_vert]=$blank_string
+        fi
+        cur_vert=$((cur_vert+1))
+    done
+}
+
+echo "Getting board boundaries"
+IFS="," read -a min_max < <(get_min_max wire_1)
+IFS="," read -a min_max_2 < <(get_min_max wire_2)
+
+# do the minimums first
+for pos in 0 2; do
+    if [ ${min_max[$pos]} -gt ${min_max_2[$pos]} ]; then
+        min_max[$pos]=${min_max_2[$pos]}
+    fi
+done
+
+# now the maximums
+for pos in 1 3; do
+    if [ ${min_max[$pos]} -lt ${min_max_2[$pos]} ]; then
+        min_max[$pos]=${min_max_2[$pos]}
+    fi
+done
+
+echo "  ${min_max[@]}"
+
+# we now know exactly how big the grid is, which is handy, as we'll use it to do offsets
+declare -A board
+declare -a cross_wires
+echo "Building board"
+make_board min_max board
+echo "Tracing first wire"
+trace_wire wire_1 board cross_wires ${min_max[0]}
+echo "Tracing second wire"
+trace_wire wire_2 board cross_wires ${min_max[0]}
+
+for (( a=${min_max[3]}; a>=${min_max[2]}; a-- )); do
+    echo ${board[$a]}
+done
+
+echo "Wires cross at:"
+min_distance=-1
+for cross in "${cross_wires[@]}"; do
+    echo "  $cross"
+    horz=${cross%,*}
+    horz=${horz//-/}
+    vert=${cross#*,}
+    vert=${vert//-/}
+    distance=$((horz+$vert))
+    if [ $min_distance -lt 0 ] || [ $min_distance -gt $distance ]; then
+        min_distance=$distance
+    fi
+done
+
+echo Min distance: $min_distance