5 filename=${1:-input.txt}
9 IFS="," read -u 3 -a instructions
12 basedir=$(dirname $(readlink -f ${BASH_SOURCE}))
14 . $basedir/computer.sh
16 coproc computer (run_program instructions 2>/dev/null)
17 comp_pid=${computer_PID}
18 comp_stdin=${computer[1]}
19 comp_stdout=${computer[0]}
23 declare -A map=( [$cur_x,$cur_y]=".")
30 declare -a oxygen_location=()
31 declare -A directions=( [n]=1 [s]=2 [w]=3 [e]=4 )
32 declare -A direction_names=( [1]="North" [2]="South" [3]="West" [4]="East" )
34 if [ "$verbose" == "0" ]; then
35 echo_verbose() { echo "$@"; }
37 echo_verbose() { true ; }
40 # use left hand rule, if we can go left, go left, if we can't, go straight, if
41 # that fails, go right, and if that fails, go back on ourselves
42 cur_direction=${directions[w]}
45 case $cur_direction in
47 cur_direction=${directions["w"]}
50 cur_direction=${directions["n"]}
53 cur_direction=${directions["e"]}
56 cur_direction=${directions["s"]}
62 case $cur_direction in
64 cur_direction=${directions["e"]}
67 cur_direction=${directions["s"]}
70 cur_direction=${directions["w"]}
73 cur_direction=${directions["n"]}
79 declare -A tentative=( [0,0]=0 )
80 declare -A lowest_cost=()
82 total_x=$((max_x - $min_x))
83 total_y=$((max_y - $min_y))
84 total_points=$((total_x*total_y))
88 while [ ! "${lowest_cost[${oxygen_location[0]},${oxygen_location[1]}]+abc}" ]; do
89 echo -ne "\rProgress: "
90 printf "%2d" $((((${#lowest_cost[@]}*100) / $total_points)))
92 lowest_cost[$cur_x,$cur_y]="${tentative["$cur_x,$cur_y"]}"
93 unset tentative[$cur_x,$cur_y]
95 # go left / right / up / down from our point to get new tentatives
96 for test_x in $((cur_x-1)) $((cur_x+1)); do
97 if [ "${map[$test_x,$cur_y]+abc}" ] && [[ "${map[$test_x,$cur_y]}" =~ [\.O] ]]; then
98 if [ ! "${lowest_cost[$test_x,$cur_y]+abc}" ]; then
99 new_cost=${lowest_cost[$cur_x,$cur_y]}
100 ((new_cost+=1)) # always 1 step from where we were previously
101 if [ "${tentative[$test_x,$cur_y]+abc}" ]; then
102 if [ $new_cost -lt ${tentative[$test_x,$cur_y]} ]; then
103 tentative[$test_x,$cur_y]=$new_cost
106 tentative[$test_x,$cur_y]=$new_cost
111 for test_y in $((cur_y-1)) $((cur_y+1)); do
112 if [ "${map[$cur_x,$test_y]+abc}" ] && [[ "${map[$cur_x,$test_y]}" =~ [\.O] ]]; then
113 if [ ! "${lowest_cost[$cur_x,$test_y]+abc}" ]; then
114 new_cost=${lowest_cost[$cur_x,$cur_y]}
115 ((new_cost+=1)) # always 1 step from where we were previously
116 if [ "${tentative[$cur_x,$test_y]+abc}" ]; then
117 if [ $new_cost -lt ${tentative[$cur_x,$test_y]} ]; then
118 tentative[$cur_x,$test_y]=$new_cost
121 tentative[$cur_x,$test_y]=$new_cost
127 # find the new lowest tentative
131 for location in "${!tentative[@]}"; do
132 if [ -z "$new_location" ]; then
133 new_location=$location
134 new_value=${tentative[$location]}
135 elif [ ${tentative[$location]} -lt $new_value ]; then
136 new_location=$location
137 new_value=${tentative[$location]}
141 if [ -z "$new_location" ]; then
144 cur_x=${new_location%,*}
145 cur_y=${new_location#*,}
147 echo -e "\rProgress: 100%"
149 echo "Lowest route cost: ${lowest_cost[${oxygen_location[0]},${oxygen_location[1]}]}"
152 # fill the room with oxygen, this could take a few iterations
155 declare -A oxygen_locations=( [${oxygen_location[0]},${oxygen_location[1]}]=0 )
156 declare -a spread_points=( "${oxygen_location[0]},${oxygen_location[1]}" )
157 declare -a new_spread_points=()
159 while [ "${#spread_points[@]}" -gt 0 ]; do
161 for spread_point in "${spread_points[@]}"; do
162 # check round the point, left, right, up and down, and if they haven't already got O
163 # add them to the oxygen_locations, and the new_spread_points, if they're on the map
164 spread_x=${spread_point%,*}
165 spread_y=${spread_point#*,}
166 for test_x in $((spread_x-1)) $((spread_x+1)); do
167 if [ "${map[$test_x,$spread_y]+abc}" ]; then
168 if [ "${map[$test_x,$spread_y]}" == "." ]; then
169 if [ ! ${oxygen_locations[$test_x,$spread_y]+abc} ]; then
170 oxygen_locations[$test_x,$spread_y]=$rounds
171 new_spread_points+=( "$test_x,$spread_y" )
176 for test_y in $((spread_y-1)) $((spread_y+1)); do
177 if [ "${map[$spread_x,$test_y]+abc}" ]; then
178 if [ "${map[$spread_x,$test_y]}" == "." ]; then
179 if [ ! "${oxygen_locations[$spread_x,$test_y]+abc}" ]; then
180 oxygen_locations[$spread_x,$test_y]=$rounds
181 new_spread_points+=( "$spread_x,$test_y" )
187 if [ ${#new_spread_points[@]} -eq 0 ]; then
191 declare -a spread_points=()
192 for spread_point in "${new_spread_points[@]}"; do
193 spread_points+=( "$spread_point" )
195 unset new_spread_points
196 declare -a new_spread_points=()
199 echo "It'd take $rounds minutes to fill the maze with oxygen"
202 declare -a spinner=( '-' '\' '|' '/' )
206 echo -ne "\r${spinner[$spinner_offset]}"
207 ((spinner_offset+=1))
208 if [ $spinner_offset -gt $((${#spinner[@]} - 1)) ]; then
214 echo "min_x $min_x max_x $max_x min_y $min_y max_y $max_y"
215 for (( a=$max_y; a >= $min_y; a-- )); do
216 for (( b=$min_x; b <= $max_x; b++ )); do
217 marker=${map[$b,$a]:-" "}
218 if [ $a -eq 0 ] && [ $b -eq 0 ]; then
221 if [ $a -eq $cur_y ] && [ $b -eq $cur_x ]; then
231 while ps -p $comp_pid > /dev/null 2>/dev/null; do
232 read -u $comp_stdout prompt
233 if [ "$prompt" != "input:" ]; then
234 echo_verbose "We has no input!"
237 echo $cur_direction >&$comp_stdin
240 case $cur_direction in
243 if [ $new_y -gt $max_y ]; then
249 if [ $new_y -lt $min_y ]; then
255 if [ $new_x -gt $max_x ]; then
261 if [ $new_x -lt $min_x ]; then
266 echo_verbose "x: $cur_x, new_x: $new_x, y: $cur_y, new_y: $new_y, direction: ${direction_names[$cur_direction]}"
267 read -u $comp_stdout status
270 echo_verbose "Hit a wall"
271 map[$new_x,$new_y]="#"
275 echo_verbose "Moved ${direction_names[$cur_direction]}"
276 if [ ! ${map[$cur_x,$cur_y]+abc} ]; then
277 map[$cur_x,$cur_y]="."
281 if [ $refind_home -eq 1 ] && [ $new_x -eq 0 ] && [ $new_y -eq 0 ]; then
287 echo_verbose "Found oxygen system"
288 map[$cur_x,$cur_y]="."
289 map[$new_x,$new_y]="O"
295 oxygen_location=( $cur_x $cur_y )
298 echo_verbose "Weird response '$status'"
307 echo "Calculating best route."