Day 12
[advent-of-code-2020.git] / day12 / ship.sh
diff --git a/day12/ship.sh b/day12/ship.sh
new file mode 100755 (executable)
index 0000000..413ce66
--- /dev/null
@@ -0,0 +1,190 @@
+#!/bin/bash
+
+filename=${1:-17E_8S_25.txt}
+
+declare -a possible_directions=("E" "S" "W" "N")
+
+read_file() {
+    local filename="${1}"
+    unset instructions
+    declare -g -a instructions
+    exec 3<"$filename"
+    while read -u 3 line; do
+        instructions+=( $line )
+    done
+}
+
+read_file "$filename"
+
+ship_direction="E"
+
+ship_east=0
+ship_north=0
+
+go_north() {
+    amount=$1
+    ship_north=$((ship_north+$amount))
+}
+
+go_south() {
+    amount=$1
+    go_north $((amount*-1))
+}
+
+go_east() {
+    amount=$1
+    ship_east=$((ship_east+$amount))
+}
+go_west() {
+    amount=$1
+    go_east $((amount*-1))
+}
+
+do_move() {
+    direction=$1
+    amount=$2
+
+    case $direction in
+        N)
+            go_north $count
+            ;;
+        S)
+            go_south $count
+            ;;
+        E)
+            go_east $count
+            ;;
+        W)
+            go_west $count
+            ;;
+    esac
+}
+
+do_turn() {
+    local amount=$1
+    local mult=$2
+    local dir_pos
+    local a
+
+    # well, we want amount to be done
+    # in 90° blocks, so
+    amount=$((amount / 90))
+    amount=$((amount*mult))
+
+    dir_pos=0
+
+    # find where current direction is in the array
+    for a in ${!possible_directions[@]}; do
+        if [ ${possible_directions[$a]} == $ship_direction ]; then
+            dir_pos=$a
+            break
+        fi
+    done
+
+    dir_pos=$((dir_pos+$amount))
+    dir_pos=$((dir_pos % ${#possible_directions[@]}))
+    ship_direction=${possible_directions[$dir_pos]}
+}
+
+do_waypoint_move() {
+    direction=$1
+    amount=$2
+
+    case $direction in
+        N)
+            waypoint_north=$((waypoint_north+$amount))
+            ;;
+        S)
+            waypoint_north=$((waypoint_north-$amount))
+            ;;
+        E)
+            waypoint_east=$((waypoint_east+$amount))
+            ;;
+        W)
+            waypoint_east=$((waypoint_east-$amount))
+            ;;
+    esac
+}
+
+do_waypoint_turn() {
+    local degrees=$1
+    local steps=$((degrees/90))
+    local temp
+
+    if [ $steps -lt 0 ]; then
+        steps=4+$steps
+    fi
+
+    for (( a=0; a<steps; a++ )); do
+        temp=$waypoint_north
+        waypoint_north=$((waypoint_east*-1))
+        waypoint_east=$temp
+    done
+}
+
+do_move_ship_to_waypoint() {
+    local times=$1
+    ship_east=$((ship_east+($times*$waypoint_east)))
+    ship_north=$((ship_north+($times*$waypoint_north)))
+}
+
+echo "Part 1:"
+
+for instruction in "${instructions[@]}"; do
+    direction=${instruction:0:1}
+    count=${instruction:1}
+
+    case $direction in
+        E|S|N|W)
+            do_move $direction $count
+            ;;
+        F)
+            do_move $ship_direction $count
+            ;;
+        L)
+            do_turn $count -1
+            ;;
+        R)
+            do_turn $count 1
+            ;;
+    esac
+done
+
+echo "  Ship ended at $ship_east E, $ship_north N"
+e=${ship_east#-}
+n=${ship_north#-}
+md=$((e+$n))
+echo "  Manhatten distance: $md"
+
+echo "Part 2:"
+
+waypoint_east=10
+waypoint_north=1
+ship_east=0
+ship_north=0
+
+for instruction in "${instructions[@]}"; do
+    direction=${instruction:0:1}
+    count=${instruction:1}
+
+    case $direction in
+        E|S|N|W)
+            do_waypoint_move $direction $count
+            ;;
+        F)
+            do_move_ship_to_waypoint $count
+            ;;
+        L)
+            do_waypoint_turn $((count*-1))
+            ;;
+        R)
+            do_waypoint_turn $((count))
+            ;;
+    esac
+done
+
+echo "  Ship ended at $ship_east E, $ship_north N"
+e=${ship_east#-}
+n=${ship_north#-}
+md=$((e+$n))
+echo "  Manhatten distance: $md"