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"
|
2024-12-17 15:48:25 +08:00
|
|
|
CHECKPOINT_ARRAY_LEN=${#CHECKPOINT_ARRAY[@]}
|
2024-12-16 19:14:02 +08:00
|
|
|
|
|
|
|
# Iterate over checkpoints and print pairings
|
|
|
|
declare -A CHECKPOINT_PAIRS
|
|
|
|
declare -A CHECKPOINT_PAIR_WEIGHTS
|
2024-12-17 15:48:25 +08:00
|
|
|
PREV_UP=$(( 2 * 5 * 7 ))
|
|
|
|
PREV_DOWN=$(( 3 * 5 * 7 ))
|
|
|
|
PREV_LEFT=$(( 2 * 3 * 5 ))
|
|
|
|
PREV_RIGHT=$(( 2 * 3 * 7 ))
|
2024-12-16 19:14:02 +08:00
|
|
|
get_weight_change () {
|
|
|
|
local POSITION=$1
|
|
|
|
local NEXT_POSITION=$2
|
|
|
|
local DIRECTION=$3
|
2024-12-17 15:48:25 +08:00
|
|
|
# Check if next position is moving in line with the previous direction
|
|
|
|
if [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_UP ]] && [[ $(( DIRECTION % PREV_UP )) -eq 0 ]]
|
2024-12-16 19:14:02 +08:00
|
|
|
then
|
|
|
|
printf "1"
|
|
|
|
return 0
|
2024-12-17 15:48:25 +08:00
|
|
|
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_DOWN ]] && [[ $(( DIRECTION % PREV_DOWN )) -eq 0 ]]
|
2024-12-16 19:14:02 +08:00
|
|
|
then
|
|
|
|
printf "1"
|
|
|
|
return 0
|
2024-12-17 15:48:25 +08:00
|
|
|
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_LEFT ]] && [[ $(( DIRECTION % PREV_LEFT )) -eq 0 ]]
|
2024-12-16 19:14:02 +08:00
|
|
|
then
|
|
|
|
printf "1"
|
|
|
|
return 0
|
2024-12-17 15:48:25 +08:00
|
|
|
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_RIGHT ]] && [[ $(( DIRECTION % PREV_RIGHT )) -eq 0 ]]
|
2024-12-16 19:14:02 +08:00
|
|
|
then
|
|
|
|
printf "1"
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
# For different directions, weight change is 1000
|
|
|
|
printf "1000"
|
|
|
|
}
|
|
|
|
recurse_travel () {
|
2024-12-17 15:48:25 +08:00
|
|
|
local POSITION=$1 # Current position
|
|
|
|
local CHECKPOINT=$2 # Previous checkpoint
|
|
|
|
local DIRECTION=$3 # Allowed adjacent tiles
|
|
|
|
local WEIGHT=$4 # Weightage so far
|
|
|
|
|
2024-12-16 19:14:02 +08:00
|
|
|
# Search adjacent tiles
|
|
|
|
# Recurse if it's movable
|
|
|
|
# Add a checkpoint pair and weights if checkpoint found
|
2024-12-17 15:48:25 +08:00
|
|
|
# 2 : Up
|
|
|
|
# 3 : Down
|
|
|
|
# 5 : Left
|
|
|
|
# 7 : Right
|
|
|
|
if [[ $(( DIRECTION % 2 )) -eq 0 ]]
|
2024-12-16 19:14:02 +08:00
|
|
|
then
|
2024-12-17 15:48:25 +08:00
|
|
|
local UP=$(( POSITION + DIR_UP ))
|
|
|
|
if [[ $UP -gt 0 ]]
|
2024-12-16 19:14:02 +08:00
|
|
|
then
|
2024-12-17 15:48:25 +08:00
|
|
|
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["$CHECKPOINT-$UP"]=0
|
|
|
|
CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$UP"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
|
|
|
fi
|
2024-12-16 19:14:02 +08:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
if [[ $(( DIRECTION % 3 )) -eq 0 ]] && [[ $DOWN -lt $MAP_LEN ]]
|
|
|
|
then
|
2024-12-17 15:48:25 +08:00
|
|
|
local DOWN=$(( POSITION + DIR_DOWN ))
|
|
|
|
if [[ $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["$CHECKPOINT-$DOWN"]=0
|
|
|
|
CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$DOWN"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
|
|
|
fi
|
2024-12-16 19:14:02 +08:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
if [[ $(( DIRECTION % 5 )) -eq 0 ]]
|
|
|
|
then
|
2024-12-17 15:48:25 +08:00
|
|
|
local LEFT=$(( POSITION + DIR_LEFT ))
|
2024-12-16 19:14:02 +08:00
|
|
|
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" )
|
2024-12-17 15:48:25 +08:00
|
|
|
CHECKPOINT_PAIRS["$CHECKPOINT-$LEFT"]=0
|
|
|
|
CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$LEFT"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
2024-12-16 19:14:02 +08:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
if [[ $(( DIRECTION % 7 )) -eq 0 ]]
|
|
|
|
then
|
2024-12-17 15:48:25 +08:00
|
|
|
local RIGHT=$(( POSITION + DIR_RIGHT ))
|
2024-12-16 19:14:02 +08:00
|
|
|
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" )
|
2024-12-17 15:48:25 +08:00
|
|
|
CHECKPOINT_PAIRS["$CHECKPOINT-$RIGHT"]=0
|
|
|
|
CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$RIGHT"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
2024-12-16 19:14:02 +08:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|
2024-12-17 15:48:25 +08:00
|
|
|
ITER=99999
|
2024-12-16 19:14:02 +08:00
|
|
|
for CHECKPOINT in "${!CHECKPOINT_ARRAY[@]}"
|
|
|
|
do
|
2024-12-17 15:48:25 +08:00
|
|
|
recurse_travel "$CHECKPOINT" "$CHECKPOINT" "$(( 2 * 3 * 5 * 7 ))" "0"
|
|
|
|
(( ITER-- ))
|
|
|
|
if [[ $ITER -eq 0 ]] ; then break ;fi
|
2024-12-16 19:14:02 +08:00
|
|
|
done
|
|
|
|
for CHECKPOINT in "${!CHECKPOINT_PAIRS[@]}"
|
|
|
|
do
|
2024-12-17 15:48:25 +08:00
|
|
|
printf "Dest %s from checkpoint %s\n" "${CHECKPOINT_PAIRS[$CHECKPOINT]}" "$CHECKPOINT"
|
|
|
|
done | sort
|
2024-12-16 19:14:02 +08:00
|
|
|
for CHECKPOINT in "${!CHECKPOINT_PAIR_WEIGHTS[@]}"
|
|
|
|
do
|
|
|
|
printf "Weight %s for checkpoint pair %s\n" "${CHECKPOINT_PAIR_WEIGHTS[$CHECKPOINT]}" "$CHECKPOINT"
|
2024-12-17 15:48:25 +08:00
|
|
|
done | sort
|
|
|
|
|
|
|
|
if [[ ${#CHECKPOINT_PAIRS[@]} -ne ${#CHECKPOINT_PAIR_WEIGHTS[@]} ]]
|
|
|
|
then
|
|
|
|
printf "Checkpoint count with weight counts do not match.\n"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Map out full paths for calculate final results for it
|
|
|
|
# Quite akin to BFS
|
|
|
|
declare -A FINAL_PATH
|
|
|
|
FINAL_PATH[$START_POSITION]=0
|
|
|
|
for (( i=0 ; i<CHECKPOINT_ARRAY_LEN ; i+= 1 )) # Start to end should only have these many iterations
|
|
|
|
do
|
|
|
|
for PATH in "${!FINAL_PATH[@]}"
|
|
|
|
do
|
|
|
|
CHECKPOINT=${PATH##*-}
|
|
|
|
PATH_SCORE=${FINAL_PATH[$PATH]}
|
|
|
|
if [[ $CHECKPOINT -eq $END_POSITION ]] # This path has completed
|
|
|
|
then
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
for NEXT_CHECKPOINT in "${!CHECKPOINT_ARRAY[@]}" # Check if there is a next mapping
|
|
|
|
do
|
|
|
|
if [[ $PATH =~ -$NEXT_CHECKPOINT- ]]; then continue; fi # Prevent loops
|
|
|
|
PAIR="$CHECKPOINT-$NEXT_CHECKPOINT"
|
|
|
|
if [[ -v CHECKPOINT_PAIRS[$PAIR] ]]
|
|
|
|
then
|
|
|
|
FINAL_PATH["$PATH-$NEXT_CHECKPOINT"]=$(( PATH_SCORE + ${CHECKPOINT_PAIR_WEIGHTS[$PAIR]} ))
|
|
|
|
unset "FINAL_PATH[$PATH]"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
done
|
2024-12-16 19:14:02 +08:00
|
|
|
done
|
|
|
|
|
2024-12-17 15:48:25 +08:00
|
|
|
for PATH in "${!FINAL_PATH[@]}"
|
|
|
|
do
|
|
|
|
END=${PATH##*-}
|
|
|
|
if [[ $END == "$END_POSITION" ]]
|
|
|
|
then
|
|
|
|
printf "Path: %s weight: %s \n" "$PATH" "${FINAL_PATH[$PATH]}"
|
|
|
|
fi
|
|
|
|
done
|
2024-12-16 19:14:02 +08:00
|
|
|
|
2024-12-17 15:48:25 +08:00
|
|
|
#print_map
|