251 lines
6.0 KiB
Bash
251 lines
6.0 KiB
Bash
|
#!/usr/bin/env bash
|
||
|
|
||
|
FUNCNEST=99999
|
||
|
MAP_FILE=input-map
|
||
|
DIRECTIONS_FILE=input-movements
|
||
|
MAP_WIDTH=$(( ( $( head -1 "$MAP_FILE" | wc -c ) -1 ) * 2 ))
|
||
|
|
||
|
# Move the robot
|
||
|
move_robot() {
|
||
|
MAP_ARRAY[ROBOT_POSITION]=.
|
||
|
ROBOT_POSITION=$NEXT_POSITION
|
||
|
MAP_ARRAY[ROBOT_POSITION]=@
|
||
|
}
|
||
|
|
||
|
# Function to move box in n direction
|
||
|
vertical_move_box () {
|
||
|
local BOX_COORDINATE=$1
|
||
|
local BOX_MOVE_DIRECTION=$2
|
||
|
|
||
|
# Normalise coordinates
|
||
|
if [[ ${MAP_ARRAY[$BOX_COORDINATE]} == "[" ]]
|
||
|
then
|
||
|
local L_SIDE=$BOX_COORDINATE
|
||
|
local R_SIDE=$(( BOX_COORDINATE +1 ))
|
||
|
elif [[ ${MAP_ARRAY[$BOX_COORDINATE]} == "]" ]]
|
||
|
then
|
||
|
local L_SIDE=$(( BOX_COORDINATE -1 ))
|
||
|
local R_SIDE=$BOX_COORDINATE
|
||
|
fi
|
||
|
local L_SIDE_MOVE_COORDINATE=$(( L_SIDE + BOX_MOVE_DIRECTION ))
|
||
|
local R_SIDE_MOVE_COORDINATE=$(( R_SIDE + BOX_MOVE_DIRECTION ))
|
||
|
|
||
|
# Recurse if there are more boxes
|
||
|
if [[ ${MAP_ARRAY[L_SIDE_MOVE_COORDINATE]} == "[" ]] || \
|
||
|
[[ ${MAP_ARRAY[L_SIDE_MOVE_COORDINATE]} == "]" ]]
|
||
|
then
|
||
|
vertical_move_box "$L_SIDE_MOVE_COORDINATE" "$BOX_MOVE_DIRECTION"
|
||
|
fi
|
||
|
if [[ ${MAP_ARRAY[R_SIDE_MOVE_COORDINATE]} == "[" ]] || \
|
||
|
[[ ${MAP_ARRAY[R_SIDE_MOVE_COORDINATE]} == "]" ]]
|
||
|
then
|
||
|
vertical_move_box "$R_SIDE_MOVE_COORDINATE" "$BOX_MOVE_DIRECTION"
|
||
|
fi
|
||
|
|
||
|
MAP_ARRAY[L_SIDE_MOVE_COORDINATE]="["
|
||
|
MAP_ARRAY[R_SIDE_MOVE_COORDINATE]="]"
|
||
|
MAP_ARRAY[L_SIDE]="."
|
||
|
MAP_ARRAY[R_SIDE]="."
|
||
|
}
|
||
|
|
||
|
|
||
|
# Function to check if box can be moved in n direction
|
||
|
vertical_check_move_box () {
|
||
|
local BOX_COORDINATE=$1
|
||
|
local BOX_MOVE_DIRECTION=$2
|
||
|
|
||
|
# Normalise coordinates
|
||
|
if [[ ${MAP_ARRAY[$BOX_COORDINATE]} == "[" ]]
|
||
|
then
|
||
|
local L_SIDE=$BOX_COORDINATE
|
||
|
local R_SIDE=$(( BOX_COORDINATE +1 ))
|
||
|
elif [[ ${MAP_ARRAY[$BOX_COORDINATE]} == "]" ]]
|
||
|
then
|
||
|
L_SIDE=$(( BOX_COORDINATE -1 ))
|
||
|
R_SIDE=$BOX_COORDINATE
|
||
|
fi
|
||
|
|
||
|
# Check if boxes are movable
|
||
|
local L_SIDE_MOVE_COORDINATE=$(( L_SIDE + BOX_MOVE_DIRECTION ))
|
||
|
local R_SIDE_MOVE_COORDINATE=$(( R_SIDE + BOX_MOVE_DIRECTION ))
|
||
|
if [[ ${MAP_ARRAY[$L_SIDE_MOVE_COORDINATE]} == '.' ]] && \
|
||
|
[[ ${MAP_ARRAY[$R_SIDE_MOVE_COORDINATE]} == '.' ]] # Can move
|
||
|
then
|
||
|
return 0
|
||
|
elif [[ ${MAP_ARRAY[$L_SIDE_MOVE_COORDINATE]} == '#' ]] || \
|
||
|
[[ ${MAP_ARRAY[$R_SIDE_MOVE_COORDINATE]} == '#' ]] # Blocked by wall
|
||
|
then
|
||
|
return 1
|
||
|
fi
|
||
|
|
||
|
# Recurse if there are more boxes
|
||
|
if [[ ${MAP_ARRAY[L_SIDE_MOVE_COORDINATE]} == "[" ]] || \
|
||
|
[[ ${MAP_ARRAY[L_SIDE_MOVE_COORDINATE]} == "]" ]]
|
||
|
then
|
||
|
vertical_check_move_box "$L_SIDE_MOVE_COORDINATE" "$BOX_MOVE_DIRECTION"
|
||
|
if [[ $? -eq 1 ]]
|
||
|
then
|
||
|
return 1
|
||
|
fi
|
||
|
fi
|
||
|
if [[ ${MAP_ARRAY[R_SIDE_MOVE_COORDINATE]} == "[" ]] || \
|
||
|
[[ ${MAP_ARRAY[R_SIDE_MOVE_COORDINATE]} == "]" ]]
|
||
|
then
|
||
|
vertical_check_move_box "$R_SIDE_MOVE_COORDINATE" "$BOX_MOVE_DIRECTION"
|
||
|
if [[ $? -eq 1 ]]
|
||
|
then
|
||
|
return 1
|
||
|
fi
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
horizontal_move_box () {
|
||
|
|
||
|
local BOX_COOR=$1
|
||
|
local BOX_MOVE_DIRECTION=$2
|
||
|
|
||
|
local NEXT_SPOT=$(( BOX_COOR + BOX_MOVE_DIRECTION * 2 ))
|
||
|
if [[ ${MAP_ARRAY[$NEXT_SPOT]} == "#" ]]
|
||
|
then
|
||
|
return 1 # Failed to move box
|
||
|
elif [[ ${MAP_ARRAY[$NEXT_SPOT]} == "[" ]] || \
|
||
|
[[ ${MAP_ARRAY[$NEXT_SPOT]} == "]" ]]
|
||
|
then
|
||
|
horizontal_move_box "$NEXT_SPOT" "$BOX_MOVE_DIRECTION"
|
||
|
if [[ $? -eq 1 ]] ; then return 1 ; fi
|
||
|
elif [[ ${MAP_ARRAY[$NEXT_SPOT]} != "." ]]
|
||
|
then
|
||
|
return 1
|
||
|
fi
|
||
|
|
||
|
# Move the box
|
||
|
if [[ $NEXT_SPOT -lt $(( BOX_COOR + BOX_MOVE_DIRECTION )) ]]
|
||
|
then
|
||
|
MAP_ARRAY[NEXT_SPOT]="["
|
||
|
MAP_ARRAY[BOX_COOR + BOX_MOVE_DIRECTION]="]"
|
||
|
else
|
||
|
MAP_ARRAY[BOX_COOR + BOX_MOVE_DIRECTION]="["
|
||
|
MAP_ARRAY[NEXT_SPOT]="]"
|
||
|
fi
|
||
|
MAP_ARRAY[BOX_COOR]="."
|
||
|
}
|
||
|
|
||
|
# Load map
|
||
|
read -r -a MAP_ARRAY <<< "$(
|
||
|
< "$MAP_FILE" paste -s -d "" |
|
||
|
sed -E '
|
||
|
s/#/##/g;
|
||
|
s/\./../g;
|
||
|
s/@/@./g;
|
||
|
s/O/[]/g;
|
||
|
s/(.)(.)/\1 \2 /g'
|
||
|
)"
|
||
|
MAP_LEN=${#MAP_ARRAY[@]}
|
||
|
|
||
|
print_map () {
|
||
|
printf "%s " "${MAP_ARRAY[@]}" |
|
||
|
fold -w $(( MAP_WIDTH * 2 ))
|
||
|
printf "\n"
|
||
|
}
|
||
|
|
||
|
# Get robot position
|
||
|
for (( i=0; i<MAP_LEN; i++ ))
|
||
|
do
|
||
|
if [[ ${MAP_ARRAY[$i]} == "@" ]]
|
||
|
then
|
||
|
ROBOT_POSITION=$i
|
||
|
break
|
||
|
fi
|
||
|
done
|
||
|
printf "Robot position : %s\n" "$ROBOT_POSITION"
|
||
|
|
||
|
# Hardcode direction values
|
||
|
UP=$(( - MAP_WIDTH ))
|
||
|
DOWN=$MAP_WIDTH
|
||
|
LEFT=-1
|
||
|
RIGHT=1
|
||
|
|
||
|
# Iterate through directions
|
||
|
MOVES=0
|
||
|
print_map
|
||
|
while read -r DIRECTION
|
||
|
do
|
||
|
|
||
|
# Interpret directions
|
||
|
if [[ $DIRECTION == "^" ]]
|
||
|
then
|
||
|
DIRECTION_VALUE=$UP
|
||
|
elif [[ $DIRECTION == "v" ]]
|
||
|
then
|
||
|
DIRECTION_VALUE=$DOWN
|
||
|
elif [[ $DIRECTION == "<" ]]
|
||
|
then
|
||
|
DIRECTION_VALUE=$LEFT
|
||
|
elif [[ $DIRECTION == ">" ]]
|
||
|
then
|
||
|
DIRECTION_VALUE=$RIGHT
|
||
|
fi
|
||
|
|
||
|
NEXT_POSITION=$(( ROBOT_POSITION + DIRECTION_VALUE ))
|
||
|
|
||
|
# Box in front
|
||
|
if [[ ${MAP_ARRAY[$NEXT_POSITION]} == "[" ]] || \
|
||
|
[[ ${MAP_ARRAY[$NEXT_POSITION]} == "]" ]]
|
||
|
then
|
||
|
#printf "Hit box.\n"
|
||
|
if [[ $DIRECTION_VALUE -eq $LEFT ]] || \
|
||
|
[[ $DIRECTION_VALUE -eq $RIGHT ]]
|
||
|
then
|
||
|
#printf "Left right box movement.\n"
|
||
|
if horizontal_move_box "$NEXT_POSITION" "$DIRECTION_VALUE"
|
||
|
then
|
||
|
move_robot
|
||
|
fi
|
||
|
elif [[ $DIRECTION_VALUE -eq $UP ]] || \
|
||
|
[[ $DIRECTION_VALUE -eq $DOWN ]]
|
||
|
then
|
||
|
#printf "Up down box movement.\n"
|
||
|
if vertical_check_move_box "$NEXT_POSITION" "$DIRECTION_VALUE"
|
||
|
then
|
||
|
vertical_move_box "$NEXT_POSITION" "$DIRECTION_VALUE"
|
||
|
move_robot
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Wall in front, do nothing
|
||
|
elif [[ ${MAP_ARRAY[$NEXT_POSITION]} == "#" ]]
|
||
|
then
|
||
|
#printf "Next: %s Skipping\n" "${MAP_ARRAY[$NEXT_POSITION]}"
|
||
|
:
|
||
|
# Empty space, move forward
|
||
|
elif [[ ${MAP_ARRAY[$NEXT_POSITION]} == "." ]]
|
||
|
then
|
||
|
#printf "Next: %s Move robot forward\n" "${MAP_ARRAY[$NEXT_POSITION]}"
|
||
|
move_robot
|
||
|
fi
|
||
|
(( MOVES++ ))
|
||
|
|
||
|
#print_map
|
||
|
done <<< "$( < "$DIRECTIONS_FILE" paste -s -d "" | sed -E 's/(.)(.)/\1 \2 /g' | tr ' ' '\n' )"
|
||
|
printf "Moves: %s\n" "$MOVES"
|
||
|
|
||
|
print_map
|
||
|
|
||
|
# Calculate GPS values for boxes
|
||
|
SUM=0
|
||
|
BOX_COUNT=0
|
||
|
for (( i=0; i<MAP_LEN; i++ ))
|
||
|
do
|
||
|
if [[ ${MAP_ARRAY[i]} == "[" ]]
|
||
|
then
|
||
|
(( BOX_COUNT++ ))
|
||
|
X=$(( i % MAP_WIDTH ))
|
||
|
Y=$(( i / MAP_WIDTH * 100 ))
|
||
|
GPS=$(( X + Y ))
|
||
|
#printf "Box %s X: %s Y: %s GPS: %s\n" "$i" "$X" "$Y" "$GPS"
|
||
|
(( SUM+=GPS ))
|
||
|
fi
|
||
|
done
|
||
|
printf "Sum: %s\n" "$SUM"
|
||
|
printf "Box count: %s\n" "$BOX_COUNT"
|