1e9c60e85985af7b2190ba43dda88943d5f1d3a8
[advent-of-code-2019.git] / day13 / computer.sh
1 #!/bin/bash
2
3 declare -a data
4
5 get_value() {
6     local -n da=$1
7     local index=$2
8
9     if [ $index -lt 0 ]; then
10         echo "Index negative, give up!"
11         exit 2
12     fi
13
14     if ! [ ${da[$index]+a} ]; then
15         da[$index]=0
16     fi
17
18     echo "${da[$index]}"
19 }
20
21 get_param() {
22     local -n dap=$1
23     local pos=$2
24     local mode=$3
25     local relative_base=$4
26
27     loc=$(get_param_loc dap $pos $mode $relative_base)
28
29     get_value dap $loc
30 }
31
32 get_param_loc() {
33     local -n dapl=$1
34     local pos=$2
35     local mode=$3
36     local relative_base=$4
37
38     case $mode in
39         0)
40             get_value dapl $pos
41             ;;
42         1)
43             echo $pos
44             ;;
45         2)
46             move_by=$(get_value dapl $pos)
47             echo $((relative_base+$move_by))
48             ;;
49         *)
50             echo "Unknown parameter mode: $mode"
51             exit 2
52             ;;
53     esac
54 }
55
56 run_program() {
57     local -n od=$1
58     local relative_base=0
59     data=("${od[@]}")
60     pos=0
61     declare -a immediate
62     while [ $pos -le ${#data[@]} ]; do
63         # first, printf the value to 5 digits
64         instruction=$(printf "%05d" ${data[$pos]})
65         for (( a=0; a<3; a++ )); do
66             immediate[$((3-a))]=${instruction:$a:1}
67         done
68         instruction=${instruction:3}
69         param_count=3
70         echo -n $'\r'"    "$'\r'$instruction >&2
71         case $instruction in
72             01|02)
73                 # 01 - add, 02 multiply
74                 symbol="+"
75                 if [ $instruction == "02" ]; then
76                     symbol="*"
77                 fi
78                 val1=$(get_param data $((pos+1)) ${immediate[1]} $relative_base)
79                 val2=$(get_param data $((pos+2)) ${immediate[2]} $relative_base)
80                 res_loc=$(get_param_loc data $((pos+3)) ${immediate[3]} $relative_base)
81                 data[$res_loc]=$(($val1 $symbol $val2))
82                 ;;
83             03)
84                 # 03 - read input
85                 echo -n $'\r'"    "$'\r' >&2
86                 echo "input: "
87                 read input
88                 input=${input//\n/}
89                 input=${input//\r/}
90                 echo >&2
91                 echo "$instruction: '$input'" >&2
92                 echo >&2
93                 res_loc=$(get_param_loc data $((pos+1)) ${immediate[1]} $relative_base)
94                 data[$res_loc]=$input
95                 param_count=1
96                 ;;
97             04)
98                 # 04 - output
99                 val=$(get_param data $((pos+1)) ${immediate[1]} $relative_base)
100                 echo -n $'\r'"    "$'\r' >&2
101                 echo $val
102                 param_count=1
103                 ;;
104             05|06)
105                 # 05 - jump-if-true, 06 - jump-if-false
106                 val=$(get_param data $((pos+1)) ${immediate[1]} $relative_base)
107                 jumpto=$(get_param data $((pos+2)) ${immediate[2]} $relative_base)
108                 param_count=2
109                 if ( [ $val -ne 0 ] && [ "$instruction" == "05" ] ) ||
110                     ( [ $val -eq 0 ] && [ "$instruction" == "06" ] ); then
111                     pos=$jumpto
112                     continue
113                 fi
114                 ;;
115             07|08)
116                 # 07 - is less than, 08 - is equal
117                 val1=$(get_param data $((pos+1)) ${immediate[1]} $relative_base)
118                 val2=$(get_param data $((pos+2)) ${immediate[2]} $relative_base)
119                 echo >&2
120                 echo "$instruction: '$val1' '$val2'" >&2
121                 echo >&2
122                 res_pos=$(get_param_loc data $((pos+3)) ${immediate[3]} $relative_base)
123                 data[$res_pos]=0
124                 if [ "$instruction" == "07" ]; then
125                     if [ $val1 -lt $val2 ]; then
126                         data[$res_pos]=1
127                     fi
128                 else
129                     if [ $val1 -eq $val2 ]; then
130                         data[$res_pos]=1
131                     fi
132                 fi
133                 ;;
134             09)
135                 # adjust relative base
136                 param_count=1
137                 val=$(get_param data $((pos+1)) ${immediate[1]} $relative_base)
138                 relative_base=$((relative_base+$val))
139                 ;;
140             99)
141                 break
142                 ;;
143             *)
144                 echo "Invalid opcode: $instruction at position $pos"
145                 exit 1
146                 ;;
147         esac
148         pos=$(($pos+$param_count+1))
149     done
150     echo -n $'\r'"    "$'\r' >&2
151 }
152