X-Git-Url: https://git.sommitrealweird.co.uk/advent-of-code-2019.git/blobdiff_plain/09b6a3fd0fae26e58acfcfb024ab535829651a9d..f14e299af2b72a96621361be9d5ef6fdf1b7d4bc:/day15/computer.sh diff --git a/day15/computer.sh b/day15/computer.sh new file mode 100644 index 0000000..8d7a56e --- /dev/null +++ b/day15/computer.sh @@ -0,0 +1,166 @@ +#!/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 + + declare -g __comp_value="${da[$index]}" +} + +get_param() { + local -n dap=$1 + local pos=$2 + local mode=$3 + local relative_base=$4 + + get_param_loc dap $pos $mode $relative_base + loc=$__comp_param_loc + + 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 + declare -g __comp_param_loc=$__comp_value + ;; + 1) + declare -g __comp_param_loc=$pos + ;; + 2) + get_value dapl $pos + move_by=$__comp_value + declare -g __comp_param_loc=$((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 + get_param data $((pos+1)) ${immediate[1]} $relative_base + val1=$__comp_value + get_param data $((pos+2)) ${immediate[2]} $relative_base + val2=$__comp_value + get_param_loc data $((pos+3)) ${immediate[3]} $relative_base + res_loc=$__comp_param_loc + 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 + get_param_loc data $((pos+1)) ${immediate[1]} $relative_base + res_loc=$__comp_param_loc + data[$res_loc]=$input + param_count=1 + ;; + 04) + # 04 - output + get_param data $((pos+1)) ${immediate[1]} $relative_base + val=$__comp_value + echo -n $'\r'" "$'\r' >&2 + echo $val + param_count=1 + ;; + 05|06) + # 05 - jump-if-true, 06 - jump-if-false + get_param data $((pos+1)) ${immediate[1]} $relative_base + val=$__comp_value + get_param data $((pos+2)) ${immediate[2]} $relative_base + jumpto=$__comp_value + 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 + get_param data $((pos+1)) ${immediate[1]} $relative_base + val1=$__comp_value + get_param data $((pos+2)) ${immediate[2]} $relative_base + val2=$__comp_value + echo >&2 + echo "$instruction: '$val1' '$val2'" >&2 + echo >&2 + get_param_loc data $((pos+3)) ${immediate[3]} $relative_base + res_pos=$__comp_param_loc + 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 + get_param data $((pos+1)) ${immediate[1]} $relative_base + val=$__comp_value + 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 +} +