X-Git-Url: https://git.sommitrealweird.co.uk/advent-of-code-2019.git/blobdiff_plain/771333fb448632f450163d13b304ef93f36e648c..79304811c66e5ce6d4898a33dd8f4799a5d1c5d3:/day13/computer.sh diff --git a/day13/computer.sh b/day13/computer.sh new file mode 100644 index 0000000..1e9c60e --- /dev/null +++ b/day13/computer.sh @@ -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 +} +