--- /dev/null
+#!/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
+}
+