Day 13 2019
authorBrett Parker <iDunno@sommitrealweird.co.uk>
Thu, 10 Dec 2020 02:11:48 +0000 (02:11 +0000)
committerBrett Parker <iDunno@sommitrealweird.co.uk>
Thu, 10 Dec 2020 02:11:48 +0000 (02:11 +0000)
  - Don't rely on the prompt from "read -p", it doesn't display on non-interactive
    sessions, so we can't easily work out what's going on
  - Add exit with high score incase we didn't clear the blocks

day13/computer.sh [new file with mode: 0644]
day13/input.txt [new file with mode: 0644]
day13/run.sh [new file with mode: 0755]
day13/run2.sh [new file with mode: 0755]
day13/screen.sh [new file with mode: 0644]

diff --git a/day13/computer.sh b/day13/computer.sh
new file mode 100644 (file)
index 0000000..1e9c60e
--- /dev/null
@@ -0,0 +1,152 @@
+#!/bin/bash
+
+declare -a data
+
+get_value() {
+    local -n da=$1
+    local index=$2
+
+    if [ $index -lt 0 ]; then
+        echo "Index negative, give up!"
+        exit 2
+    fi
+
+    if ! [ ${da[$index]+a} ]; then
+        da[$index]=0
+    fi
+
+    echo "${da[$index]}"
+}
+
+get_param() {
+    local -n dap=$1
+    local pos=$2
+    local mode=$3
+    local relative_base=$4
+
+    loc=$(get_param_loc dap $pos $mode $relative_base)
+
+    get_value dap $loc
+}
+
+get_param_loc() {
+    local -n dapl=$1
+    local pos=$2
+    local mode=$3
+    local relative_base=$4
+
+    case $mode in
+        0)
+            get_value dapl $pos
+            ;;
+        1)
+            echo $pos
+            ;;
+        2)
+            move_by=$(get_value dapl $pos)
+            echo $((relative_base+$move_by))
+            ;;
+        *)
+            echo "Unknown parameter mode: $mode"
+            exit 2
+            ;;
+    esac
+}
+
+run_program() {
+    local -n od=$1
+    local relative_base=0
+    data=("${od[@]}")
+    pos=0
+    declare -a immediate
+    while [ $pos -le ${#data[@]} ]; do
+        # first, printf the value to 5 digits
+        instruction=$(printf "%05d" ${data[$pos]})
+        for (( a=0; a<3; a++ )); do
+            immediate[$((3-a))]=${instruction:$a:1}
+        done
+        instruction=${instruction:3}
+        param_count=3
+        echo -n $'\r'"    "$'\r'$instruction >&2
+        case $instruction in
+            01|02)
+                # 01 - add, 02 multiply
+                symbol="+"
+                if [ $instruction == "02" ]; then
+                    symbol="*"
+                fi
+                val1=$(get_param data $((pos+1)) ${immediate[1]} $relative_base)
+                val2=$(get_param data $((pos+2)) ${immediate[2]} $relative_base)
+                res_loc=$(get_param_loc data $((pos+3)) ${immediate[3]} $relative_base)
+                data[$res_loc]=$(($val1 $symbol $val2))
+                ;;
+            03)
+                # 03 - read input
+                echo -n $'\r'"    "$'\r' >&2
+                echo "input: "
+                read input
+                input=${input//\n/}
+                input=${input//\r/}
+                echo >&2
+                echo "$instruction: '$input'" >&2
+                echo >&2
+                res_loc=$(get_param_loc data $((pos+1)) ${immediate[1]} $relative_base)
+                data[$res_loc]=$input
+                param_count=1
+                ;;
+            04)
+                # 04 - output
+                val=$(get_param data $((pos+1)) ${immediate[1]} $relative_base)
+                echo -n $'\r'"    "$'\r' >&2
+                echo $val
+                param_count=1
+                ;;
+            05|06)
+                # 05 - jump-if-true, 06 - jump-if-false
+                val=$(get_param data $((pos+1)) ${immediate[1]} $relative_base)
+                jumpto=$(get_param data $((pos+2)) ${immediate[2]} $relative_base)
+                param_count=2
+                if ( [ $val -ne 0 ] && [ "$instruction" == "05" ] ) ||
+                    ( [ $val -eq 0 ] && [ "$instruction" == "06" ] ); then
+                    pos=$jumpto
+                    continue
+                fi
+                ;;
+            07|08)
+                # 07 - is less than, 08 - is equal
+                val1=$(get_param data $((pos+1)) ${immediate[1]} $relative_base)
+                val2=$(get_param data $((pos+2)) ${immediate[2]} $relative_base)
+                echo >&2
+                echo "$instruction: '$val1' '$val2'" >&2
+                echo >&2
+                res_pos=$(get_param_loc data $((pos+3)) ${immediate[3]} $relative_base)
+                data[$res_pos]=0
+                if [ "$instruction" == "07" ]; then
+                    if [ $val1 -lt $val2 ]; then
+                        data[$res_pos]=1
+                    fi
+                else
+                    if [ $val1 -eq $val2 ]; then
+                        data[$res_pos]=1
+                    fi
+                fi
+                ;;
+            09)
+                # adjust relative base
+                param_count=1
+                val=$(get_param data $((pos+1)) ${immediate[1]} $relative_base)
+                relative_base=$((relative_base+$val))
+                ;;
+            99)
+                break
+                ;;
+            *)
+                echo "Invalid opcode: $instruction at position $pos"
+                exit 1
+                ;;
+        esac
+        pos=$(($pos+$param_count+1))
+    done
+    echo -n $'\r'"    "$'\r' >&2
+}
+
diff --git a/day13/input.txt b/day13/input.txt
new file mode 100644 (file)
index 0000000..a9a41da
--- /dev/null
@@ -0,0 +1 @@
+1,380,379,385,1008,2399,462045,381,1005,381,12,99,109,2400,1102,0,1,383,1101,0,0,382,20101,0,382,1,21001,383,0,2,21102,37,1,0,1105,1,578,4,382,4,383,204,1,1001,382,1,382,1007,382,44,381,1005,381,22,1001,383,1,383,1007,383,20,381,1005,381,18,1006,385,69,99,104,-1,104,0,4,386,3,384,1007,384,0,381,1005,381,94,107,0,384,381,1005,381,108,1105,1,161,107,1,392,381,1006,381,161,1102,-1,1,384,1106,0,119,1007,392,42,381,1006,381,161,1101,0,1,384,21002,392,1,1,21101,0,18,2,21102,1,0,3,21101,138,0,0,1105,1,549,1,392,384,392,21002,392,1,1,21102,1,18,2,21102,3,1,3,21101,0,161,0,1106,0,549,1101,0,0,384,20001,388,390,1,20101,0,389,2,21102,1,180,0,1106,0,578,1206,1,213,1208,1,2,381,1006,381,205,20001,388,390,1,21002,389,1,2,21102,1,205,0,1105,1,393,1002,390,-1,390,1102,1,1,384,20101,0,388,1,20001,389,391,2,21102,228,1,0,1105,1,578,1206,1,261,1208,1,2,381,1006,381,253,21002,388,1,1,20001,389,391,2,21102,253,1,0,1105,1,393,1002,391,-1,391,1101,1,0,384,1005,384,161,20001,388,390,1,20001,389,391,2,21101,279,0,0,1106,0,578,1206,1,316,1208,1,2,381,1006,381,304,20001,388,390,1,20001,389,391,2,21102,304,1,0,1106,0,393,1002,390,-1,390,1002,391,-1,391,1102,1,1,384,1005,384,161,21002,388,1,1,21002,389,1,2,21101,0,0,3,21101,0,338,0,1105,1,549,1,388,390,388,1,389,391,389,20101,0,388,1,20101,0,389,2,21102,1,4,3,21102,1,365,0,1106,0,549,1007,389,19,381,1005,381,75,104,-1,104,0,104,0,99,0,1,0,0,0,0,0,0,318,20,15,1,1,22,109,3,22101,0,-2,1,21202,-1,1,2,21102,1,0,3,21102,1,414,0,1106,0,549,21201,-2,0,1,22102,1,-1,2,21101,429,0,0,1106,0,601,2101,0,1,435,1,386,0,386,104,-1,104,0,4,386,1001,387,-1,387,1005,387,451,99,109,-3,2105,1,0,109,8,22202,-7,-6,-3,22201,-3,-5,-3,21202,-4,64,-2,2207,-3,-2,381,1005,381,492,21202,-2,-1,-1,22201,-3,-1,-3,2207,-3,-2,381,1006,381,481,21202,-4,8,-2,2207,-3,-2,381,1005,381,518,21202,-2,-1,-1,22201,-3,-1,-3,2207,-3,-2,381,1006,381,507,2207,-3,-4,381,1005,381,540,21202,-4,-1,-1,22201,-3,-1,-3,2207,-3,-4,381,1006,381,529,22101,0,-3,-7,109,-8,2106,0,0,109,4,1202,-2,44,566,201,-3,566,566,101,639,566,566,1201,-1,0,0,204,-3,204,-2,204,-1,109,-4,2106,0,0,109,3,1202,-1,44,593,201,-2,593,593,101,639,593,593,21002,0,1,-2,109,-3,2105,1,0,109,3,22102,20,-2,1,22201,1,-1,1,21102,443,1,2,21101,114,0,3,21102,1,880,4,21102,1,630,0,1106,0,456,21201,1,1519,-2,109,-3,2105,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,2,2,0,2,2,2,2,2,0,2,2,2,0,0,0,2,2,2,2,2,2,0,2,2,0,0,2,2,2,0,2,2,2,2,0,0,2,0,2,2,0,1,1,0,2,2,0,2,2,2,2,2,0,2,2,0,2,2,2,0,0,0,2,0,2,2,0,0,2,2,2,0,2,2,2,2,2,0,2,0,0,2,2,0,0,1,1,0,2,2,0,2,2,2,2,2,2,0,2,2,2,2,0,2,2,0,0,2,0,0,0,2,0,0,2,2,2,2,2,0,2,2,0,2,2,2,0,2,0,1,1,0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,0,0,2,2,2,0,2,2,2,0,2,2,0,0,0,2,2,2,2,2,2,0,2,2,2,2,0,1,1,0,0,2,2,2,2,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,2,0,2,0,0,0,2,0,2,2,0,0,2,2,2,2,2,0,2,0,1,1,0,0,2,2,2,2,2,2,2,2,0,2,2,0,0,2,0,2,0,2,0,0,2,2,0,0,2,2,0,0,0,2,0,2,0,2,2,2,0,2,2,0,1,1,0,0,0,0,0,0,2,0,2,0,0,2,2,0,2,2,0,0,2,0,0,2,2,2,2,2,2,2,2,0,2,2,0,0,0,2,2,2,2,2,2,0,1,1,0,0,2,2,2,2,0,0,0,0,2,0,0,2,2,0,2,2,2,2,2,2,0,2,2,2,0,2,2,2,0,2,2,2,2,2,2,0,2,0,2,0,1,1,0,2,0,2,2,2,2,2,0,0,2,2,2,2,2,0,2,2,2,2,2,2,0,2,0,0,0,2,2,0,2,0,0,2,0,2,2,2,2,2,2,0,1,1,0,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,0,2,2,2,2,2,2,0,2,2,2,2,2,2,0,0,0,2,2,0,2,0,1,1,0,0,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,0,2,0,2,2,0,2,2,0,2,2,2,0,2,2,0,0,2,0,2,0,2,2,0,0,1,1,0,0,2,2,2,2,0,2,0,2,2,0,2,2,2,2,2,2,0,2,0,0,0,0,2,0,2,2,2,2,2,0,0,2,0,2,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,56,72,33,24,73,85,29,45,48,12,58,96,32,17,48,17,9,49,78,6,48,98,91,23,28,37,16,54,30,88,69,69,23,59,33,61,89,94,79,64,42,13,82,45,98,57,57,80,6,2,67,86,26,84,80,47,72,38,22,73,75,4,3,47,96,34,52,22,26,90,74,84,37,68,37,73,86,59,27,67,52,22,63,92,41,46,68,93,55,3,6,78,32,82,8,34,41,77,29,92,77,81,17,90,40,50,27,80,82,96,66,21,67,96,69,12,39,65,93,7,91,97,55,95,64,9,91,48,23,44,96,67,38,43,26,70,64,17,47,98,35,54,89,31,67,18,36,42,52,19,71,4,47,21,43,77,6,64,45,94,49,52,54,85,9,78,73,44,56,3,37,15,45,16,78,98,82,27,59,13,26,75,73,18,74,20,63,65,56,55,98,34,10,97,55,70,51,25,9,16,10,79,49,58,13,92,19,25,79,33,48,5,78,86,94,48,39,3,43,90,35,45,56,60,51,92,4,52,64,63,18,70,44,82,70,29,72,53,91,36,75,95,57,61,42,79,98,26,8,73,10,3,69,95,69,39,13,70,90,66,96,97,21,35,38,43,21,79,91,5,92,93,48,25,31,15,39,58,51,68,46,93,10,56,16,5,54,34,54,68,22,97,18,14,96,52,92,62,62,62,43,62,73,41,85,36,81,81,1,41,92,94,78,32,72,15,30,54,86,1,60,28,20,94,15,52,60,68,63,15,45,39,66,65,42,35,28,31,83,59,87,69,83,22,58,45,22,70,86,98,44,13,37,24,67,80,7,67,16,10,88,54,60,76,97,37,63,31,61,91,10,61,97,76,59,40,28,15,45,50,86,61,30,11,85,87,53,10,88,40,69,82,60,57,38,74,35,44,33,98,80,47,3,51,56,12,28,86,26,91,45,10,92,18,63,4,66,47,73,18,57,51,32,79,25,41,61,68,78,34,71,3,33,29,40,25,15,72,88,51,20,76,70,10,20,38,13,27,92,97,60,22,54,73,20,51,27,87,51,41,73,61,1,31,94,11,74,56,34,9,74,31,20,91,63,75,1,54,62,31,30,60,74,67,13,83,65,10,63,38,65,75,94,85,98,53,59,63,42,21,93,13,55,36,76,53,14,30,71,2,84,16,82,87,57,74,57,29,48,14,73,4,22,91,81,94,41,67,27,82,20,4,89,43,92,36,70,29,45,82,65,49,2,63,78,18,13,75,76,50,85,64,37,4,57,41,18,15,65,70,44,85,72,11,36,35,84,4,70,49,47,20,10,80,79,59,89,1,87,5,22,87,31,23,38,35,49,71,33,46,81,64,43,59,46,51,62,33,89,61,66,64,92,23,30,56,17,71,85,18,2,72,2,42,31,13,53,35,17,91,73,73,48,95,20,26,23,10,65,4,40,6,79,49,84,7,15,49,90,45,24,42,76,21,97,3,63,42,30,92,55,38,44,53,67,44,42,36,28,9,17,66,92,44,51,55,57,59,6,50,52,97,21,45,19,17,21,76,86,32,23,56,78,93,97,13,93,87,32,83,89,23,21,63,40,87,83,95,95,74,57,60,82,48,45,18,93,63,74,31,30,43,50,28,69,60,43,81,86,67,64,17,67,27,79,49,92,21,71,59,32,83,29,72,3,62,47,95,76,63,32,53,32,28,75,50,22,37,43,20,10,13,80,80,19,43,55,23,14,70,32,80,4,44,4,40,35,44,55,41,68,80,68,25,27,97,39,30,24,42,52,88,87,36,23,83,58,50,85,60,97,72,97,51,37,83,40,59,52,25,83,8,76,14,20,94,43,45,75,47,12,67,46,56,30,74,1,28,41,42,74,21,36,22,80,69,23,12,62,25,39,77,8,46,56,64,43,34,8,54,85,43,20,84,24,13,64,92,68,7,61,49,46,16,87,54,24,94,70,63,63,33,43,30,29,34,22,23,98,20,90,14,77,27,89,39,13,3,77,47,462045
diff --git a/day13/run.sh b/day13/run.sh
new file mode 100755 (executable)
index 0000000..8c8a139
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+exec 3<input.txt
+OLDIFS=$IFS
+IFS="," read -u 3 -a instructions
+IFS=$OLDIFS
+
+basedir=$(dirname $(readlink -f ${BASH_SOURCE}))
+
+. $basedir/computer.sh
+. $basedir/screen.sh
+
+run_program instructions 2>/dev/null | arcade_screen
diff --git a/day13/run2.sh b/day13/run2.sh
new file mode 100755 (executable)
index 0000000..daccab3
--- /dev/null
@@ -0,0 +1,118 @@
+#!/bin/bash
+
+exec 3<input.txt
+OLDIFS=$IFS
+IFS="," read -u 3 -a instructions
+IFS=$OLDIFS
+exec 4>output.txt
+
+basedir=$(dirname $(readlink -f ${BASH_SOURCE}))
+
+. $basedir/computer.sh
+. $basedir/screen.sh
+
+instructions[0]=2
+
+coproc computer (run_program instructions 2>computer_output.txt)
+
+comp_pid=${computer_PID}
+comp_stdin=${computer[1]}
+comp_stdout=${computer[0]}
+
+paddle_x=0
+paddle_y=0
+ball_x=0
+ball_y=0
+ball_dir_left=-2
+ball_dir_up=0
+ball_started=-1
+where_paddle_should_be_x=0
+
+get_joystick_direction() {
+    if [ $ball_dir_left -eq -2 ]; then
+        echo "0"
+        return
+    fi
+
+    if   [ $paddle_x -lt $ball_x ]; then
+        paddle_dir=1
+    elif [ $paddle_x -gt $ball_x ]; then
+        paddle_dir=-1
+    elif [ $paddle_x -eq $ball_x ]; then
+        paddle_dir=0
+    fi
+
+    echo "Where we think the paddle should be: $where_ball_will_be_on_paddle_line" >&4
+    echo "Where we are: $paddle_x,$paddle_y" >&4
+    echo "Where the ball is: $ball_x, $ball_y" >&4
+    echo "Direction of ball: $ball_dir_left,$ball_dir_up" >&4
+    echo "Direction of paddle: $paddle_dir" >&4
+
+    echo "$paddle_dir"
+}
+
+update_paddle_pos() {
+    paddle_x=$1
+    paddle_y=$2
+}
+
+update_ball_pos() {
+    local x=$1
+    local y=$2
+
+    # work out if we're going up or down
+    # left or right
+    if [ $x -gt $ball_x ]; then
+        ball_dir_left=1
+    elif [ $x -lt $ball_x ]; then
+        ball_dir_left=-1
+    else
+        ball_dir_left=0
+    fi
+
+    if [ $y -gt $ball_y ]; then
+        ball_dir_up=1
+    elif [ $y -lt $ball_y ]; then
+        ball_dir_up=-1
+    else
+        ball_dir_up=0
+    fi
+
+    ball_x=$x
+    ball_y=$y
+}
+
+arcade_screen_init
+
+while ps -p $comp_pid >/dev/null 2>/dev/null; do
+    read -u $comp_stdout x || break
+    if [ $x == "input:" ]; then
+        echo "$(get_joystick_direction)" >&$comp_stdin
+        continue # go back to main loop
+    fi
+    echo "x: '$x'" >&4
+    if [ "x$x" == "xinput: " ]; then
+        continue
+    fi
+    read -u $comp_stdout y || break
+    echo "y: '$y'" >&4
+    read -u $comp_stdout z || break
+    echo "z: '$z'" >&4
+
+    case $z in
+        3)
+            update_paddle_pos $x $y
+            ;;
+        4)
+            update_ball_pos $x $y
+            ;;
+    esac
+
+    if [ $x -eq -1 ]; then
+        update_score_board $z
+        continue
+    fi
+    arcade_screen_update $x $y $z
+done
+
+arcade_screen_finish
diff --git a/day13/screen.sh b/day13/screen.sh
new file mode 100644 (file)
index 0000000..3bc3956
--- /dev/null
@@ -0,0 +1,140 @@
+__arcade_score=0
+
+clear_screen() {
+    echo -en '\033[2J'
+}
+
+move_cursor() {
+    local x=$1
+    local y=$2
+
+    # program assumes 0 based, we're 1 based, apparently
+    x=$((x+1))
+    y=$((y+1))
+
+    echo -en '\033['$y';'$x'f'
+}
+
+draw_tile() {
+    local tile_type=$1
+
+    case $tile_type in
+        0)
+            # blank
+            echo -n ' '
+            ;;
+        1)
+            # wall
+            echo -n '|'
+            ;;
+        2)
+            # block
+            echo -n '#'
+            ;;
+        3)
+            # horizontal paddle
+            echo -n '='
+            ;;
+        4)
+            # ball
+            echo -n 'o'
+            ;;
+    esac
+}
+
+hide_cursor() {
+    tput civis
+}
+
+show_cursor() {
+    tput cvvis
+}
+
+draw_score_board() {
+    local value=${1:-0}
+    local scoreboard_y=20
+    local scoreboard_width=43
+    move_cursor 0 $scoreboard_y
+    printf "+"
+    printf "%.0s-" {1..42}
+    printf "+\n"
+    printf "|"
+    printf "%.0s " {1..42}
+    printf "|\n"
+    printf "+"
+    printf "%.0s-" {1..42}
+    printf "+\n"
+    update_score_board
+}
+
+update_score_board() {
+    local value=${1:-$__arcade_score}
+    move_cursor 2 21
+    if [ $value -gt 0 ]; then
+        __arcade_score=$value
+    fi
+    printf '% 40d' $value
+}
+
+arcade_screen_init() {
+    clear_screen
+    hide_cursor
+    draw_score_board
+}
+
+arcade_screen_update() {
+    local x=$1
+    local y=$2
+    local tile=$3
+
+    move_cursor $x $y
+    draw_tile $tile
+}
+
+arcade_screen_finish() {
+    move_cursor 0 23
+    show_cursor
+    echo high score: $__arcade_score
+}
+
+arcade_screen() {
+    local max_y=0
+    local max_x=0
+    local -A blocks
+
+    # first, clear the screen and hide the cursor
+    clear_screen
+    hide_cursor
+
+    draw_score_board
+
+    while read x; do
+        read y
+        read tile
+        if [ $x -gt $max_x ]; then
+            max_x=$x
+        fi
+        if [ $y -gt $max_y ]; then
+            max_y=$y
+        fi
+        move_cursor $x $y
+        draw_tile $tile
+
+        case $tile in
+            0)
+                if [ ${blocks[$x,$y]+a} ]; then
+                    unset blocks[$x,$y]
+                fi
+                ;;
+            2)
+                blocks[$x,$y]=1
+                ;;
+        esac
+    done
+
+    move_cursor 0 $((max_y+4))
+    echo "We have ${#blocks[@]} blocks on the screen"
+    echo "The maximum x was $max_x"
+    echo "The maximum y was $max_y"
+    show_cursor
+}