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