diff --git a/2024/day-15/solution-2.sh b/2024/day-15/solution-2.sh new file mode 100644 index 0000000..0dfc5a6 --- /dev/null +++ b/2024/day-15/solution-2.sh @@ -0,0 +1,290 @@ +#!/usr/bin/env bash + +FUNCNEST=99999 +MAP_FILE=input-map +DIRECTIONS_FILE=input-movements +MAP_WIDTH=$(( ( $( head -1 "$MAP_FILE" | wc -c ) -1 ) * 2 )) +MAP_HEIGHT=$( < "$MAP_FILE" wc -l ) + +# 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 TEST_ARRAY <<< "$( + < "$MAP_FILE" paste -s -d "" | + sed -E ' + s/#/##/g; + s/\./../g; + s/@/@./g; + s/O/[]/g; + s/(.)(.)/\1 \2 /g' +)" +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" +} + +# Count boxes +#BOX_COUNT=0 +#for (( i=0; i" ]] + 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 X_L ? X_L : X_R )) + #Y=$(( Y_T > Y_B ? Y_B : Y_T )) + 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" + #if [[ $GPS -lt 0 ]] ; then printf "Negative GPS: %s for box %s\n" "$GPS" "$i"; continue; fi + (( SUM+=GPS )) + fi +done +printf "Sum: %s\n" "$SUM" +printf "Box count: %s\n" "$BOX_COUNT" + +# Compare and test if walls have moved +for (( i=0; i