Files
advent-of-code/2024/day-16/solution-1.sh

197 lines
5.6 KiB
Bash
Raw Normal View History

2024-12-16 19:14:02 +08:00
#!/usr/bin/env bash
FUNCNEST=99999
FILE=test-input-1
# Load map
read -r -a MAP_ARRAY <<< "$( < "$FILE" paste -s -d "" | sed -E 's/(.)(.)/\1 \2 /g' )"
#read -r -a CHECKPOINT_ARRAY <<< "$( < "$FILE" paste -s -d "" | sed -E 's/(.)(.)/\1 \2 /g' )"
MAP_WIDTH=$(( $( head -1 "$FILE" | wc -c ) -1 ))
MAP_LEN=${#MAP_ARRAY[@]}
MAP_HEIGHT=$( < "$FILE" wc -l )
printf "Map len: %s Map width: %s Map height: %s\n" "$MAP_LEN" "$MAP_WIDTH" "$MAP_HEIGHT"
DIR_UP=$(( - MAP_WIDTH ))
DIR_DOWN=$MAP_WIDTH
DIR_LEFT=-1
DIR_RIGHT=1
print_map () {
printf "%s " "${MAP_ARRAY[@]}" | fold -w $(( MAP_WIDTH * 2 ))
printf "\n"
}
# Get starting position
for (( i=0; i<MAP_LEN; i++ ))
do
if [[ ${MAP_ARRAY[$i]} == "S" ]]
then
START_POSITION=$i
MAP_ARRAY[START_POSITION]="X"
break
fi
done
printf "Start position: %s\n" "$START_POSITION"
# Get end position
for (( i=0; i<MAP_LEN; i++ ))
do
if [[ ${MAP_ARRAY[$i]} == "E" ]]
then
END_POSITION=$i
MAP_ARRAY[END_POSITION]="X"
break
fi
done
printf "End position: %s\n" "$END_POSITION"
print_map
# Mark all checkpoints
declare -A CHECKPOINT_ARRAY
CHECKPOINT_ARRAY[$START_POSITION]=0
for (( i=0; i<MAP_LEN; i++ ))
do
if [[ ${MAP_ARRAY[$i]} != "." ]] ;then continue ;fi
STEP=$i
ADJ_COUNT=0
UP=$(( STEP + DIR_UP ))
DOWN=$(( STEP + DIR_DOWN ))
LEFT=$(( STEP + DIR_LEFT ))
RIGHT=$(( STEP + DIR_RIGHT ))
if [[ ${MAP_ARRAY[$UP]} == "." ]] && [[ $UP -gt 0 ]]
then
(( ADJ_COUNT++ ))
fi
if [[ ${MAP_ARRAY[$DOWN]} == "." ]] && [[ $DOWN -lt $MAP_LEN ]]
then
(( ADJ_COUNT++ ))
fi
if [[ ${MAP_ARRAY[$LEFT]} == "." ]]
then
(( ADJ_COUNT++ ))
fi
if [[ ${MAP_ARRAY[$RIGHT]} == "." ]]
then
(( ADJ_COUNT++ ))
fi
if [[ $ADJ_COUNT -gt 2 ]]
then
MAP_ARRAY[STEP]=X
CHECKPOINT_ARRAY[$STEP]=0
fi
done
CHECKPOINT_ARRAY[$END_POSITION]=0
printf "%s " "${!CHECKPOINT_ARRAY[@]}"
printf "\n"
# Iterate over checkpoints and print pairings
declare -A CHECKPOINT_PAIRS
declare -A CHECKPOINT_PAIR_WEIGHTS
get_weight_change () {
local POSITION=$1
local NEXT_POSITION=$2
local DIRECTION=$3
# For same directions, weight change is 1
if [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_UP ]] && [[ $(( DIRECTION % 2 )) -eq 0 ]]
then
printf "1"
return 0
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_DOWN ]] && [[ $(( DIRECTION % 3 )) -eq 0 ]]
then
printf "1"
return 0
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_LEFT ]] && [[ $(( DIRECTION % 5 )) -eq 0 ]]
then
printf "1"
return 0
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_RIGHT ]] && [[ $(( DIRECTION % 7 )) -eq 0 ]]
then
printf "1"
return 0
fi
# For different directions, weight change is 1000
printf "1000"
}
recurse_travel () {
local POSITION=$1
local CHECKPOINT=$2
local DIRECTION=$3
local WEIGHT=$4
local UP=$(( POSITION - MAP_WIDTH ))
local DOWN=$(( POSITION + MAP_WIDTH ))
local LEFT=$(( POSITION - 1 ))
local RIGHT=$(( POSITION + 1 ))
# Search adjacent tiles
# Recurse if it's movable
# Add a checkpoint pair and weights if checkpoint found
if [[ $(( DIRECTION % 2 )) -eq 0 ]] && [[ $UP -gt 0 ]]
then
if [[ ${MAP_ARRAY[$UP]} == "." ]]
then
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$UP" "$DIRECTION" )
recurse_travel "$UP" "$CHECKPOINT" "$(( 2 * 5 * 7 ))" "$(( WEIGHT + WEIGHT_CHANGE ))"
elif [[ -v CHECKPOINT_ARRAY[$UP] ]]
then
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$UP" "$DIRECTION" )
CHECKPOINT_PAIRS[$UP]=$CHECKPOINT
CHECKPOINT_PAIR_WEIGHTS["$UP-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE ))
fi
fi
if [[ $(( DIRECTION % 3 )) -eq 0 ]] && [[ $DOWN -lt $MAP_LEN ]]
then
if [[ ${MAP_ARRAY[$DOWN]} == "." ]]
then
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$DOWN" "$DIRECTION" )
recurse_travel "$DOWN" "$CHECKPOINT" "$(( 3 * 5 * 7 ))" "$(( WEIGHT + WEIGHT_CHANGE ))"
elif [[ -v CHECKPOINT_ARRAY[$DOWN] ]]
then
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$DOWN" "$DIRECTION" )
CHECKPOINT_PAIRS[$DOWN]=$CHECKPOINT
CHECKPOINT_PAIR_WEIGHTS["$DOWN-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE ))
fi
fi
if [[ $(( DIRECTION % 5 )) -eq 0 ]]
then
if [[ ${MAP_ARRAY[$LEFT]} == "." ]]
then
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$LEFT" "$DIRECTION" )
recurse_travel "$LEFT" "$CHECKPOINT" "$(( 2 * 3 * 5 ))" "$(( WEIGHT + WEIGHT_CHANGE ))"
elif [[ -v CHECKPOINT_ARRAY[$LEFT] ]]
then
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$LEFT" "$DIRECTION" )
CHECKPOINT_PAIRS[$LEFT]=$CHECKPOINT
CHECKPOINT_PAIR_WEIGHTS["$LEFT-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE ))
fi
fi
if [[ $(( DIRECTION % 7 )) -eq 0 ]]
then
if [[ ${MAP_ARRAY[$RIGHT]} == "." ]]
then
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$RIGHT" "$DIRECTION" )
recurse_travel "$RIGHT" "$CHECKPOINT" "$(( 2 * 3 * 7 ))" "$(( WEIGHT + WEIGHT_CHANGE ))"
elif [[ -v CHECKPOINT_ARRAY[$RIGHT] ]]
then
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$RIGHT" "$DIRECTION" )
CHECKPOINT_PAIRS[$RIGHT]=$CHECKPOINT
CHECKPOINT_PAIR_WEIGHTS["$RIGHT-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE ))
fi
fi
}
for CHECKPOINT in "${!CHECKPOINT_ARRAY[@]}"
do
recurse_travel "$CHECKPOINT" "$CHECKPOINT" "$CHECKPOINT" "$(( 2 * 3 * 5 * 7 ))" "0"
done
for CHECKPOINT in "${!CHECKPOINT_PAIRS[@]}"
do
printf "DEST %s from checkpoint %s\n" "${CHECKPOINT_PAIRS[$CHECKPOINT]}" "$CHECKPOINT"
done
for CHECKPOINT in "${!CHECKPOINT_PAIR_WEIGHTS[@]}"
do
printf "Weight %s for checkpoint pair %s\n" "${CHECKPOINT_PAIR_WEIGHTS[$CHECKPOINT]}" "$CHECKPOINT"
done
# Score the path
#
print_map