Skip to content

Commit

Permalink
Day 12. Advent of bash is getting slow - if you are stupid. My first …
Browse files Browse the repository at this point in the history
…solution managed to solve part 1, but was horribly slow for part 2. I basically made my own algorithm. Then I implemented BFS since that is apparantly good (haha).. BFS took 20 seconds for part 1, and then for part 2 I created a nice little bug. I did a BFS for each starting point. 20 seconds times about 688 starting points quickly becomes 3 hours of execution time. Then I did a BFS with multiple starting points and solved it in 24 seconds.
  • Loading branch information
01ste02 committed Dec 12, 2022
1 parent 515adbe commit fca8471
Show file tree
Hide file tree
Showing 4 changed files with 346 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ I realized that my commit-messages are a bit of a comedy show around day 6, so t
* Day 9. Bash. No sleep. Fell asleep between the parts... ~ *Interesting day. Since I do not modify my code AT ALL after getting the star, the first code is a miracle that it works. Stupid me missunderstood how the tail moves relative the body - and set it to move to the coords that the head last had before the distance between the two grew too large. This works for part one, but not part two. In part two, I spent a lot of time on debugging this. And fell asleep - I was working on a backup mailserver all night long for a critical system that might go down as my part of Sweden faces the risk of rolling blackouts right now. When I woke up, I made a new method that moved correctly - but it is UGLY. As a part of my debugging, I rendered each updated frame of the movement process. This is SLOW. Whilst being really late for work, I let the script run for 20 minutes and did not get a complete answer. Then I stopped it and remembered to remove my rendering, after which I got a sollution in 5 seconds (with some debug printing, but no rendering). I should really just never print anything. I hate printing delays. This was the worst day in a LONG time for me......*
* Day 10. Advent of Bash STRONK!! I made it! This day was quite quick and easy, but still fun. I dabbled in a better way of drawing in the terminal - one where I can actually replace characters instead of redrawing everything for every frame. ~ *Really, really happy right now. I made a bet with some people that I would last until at least day 10 with Bash - and I completed that now. It has been significantly easier than I thought, and a lot more fun than I could have imagined. Amazing day to complete my Bash bet on, and now I am publicly vowing to do at least day 20 in Bash. No force pushes here... No... No... I also climbed to 7th place at Dsek AoC :)*
* Day 11. Advent of bash is working, but slow. Interesting to handle such large numbers, and modulo might be the way to go. The slowness of bash loops and array access is getting to me. But the worst part it the time it takes to spawn subprocesses, for example sed. ~ *Really fun day, but I had to sit and wait a whole lot. Slowly starting to regret my promise yesterday, because if the rest is going to be this hard to complete quickly.. It took about 5 minutes for part 2 to run, and that is after I optimized it as far as I could think of. Seems like I will be spending a lot of time just staring at the console...*
* Day 12. Advent of bash is getting slow - if you are stupid. My first solution managed to solve part 1, but was horribly slow for part 2. I basically made my own algorithm. Then I implemented BFS since that is apparantly good (haha).. BFS took 20 seconds for part 1, and then for part 2 I created a nice little bug. I did a BFS for each starting point. 20 seconds times about 688 starting points quickly becomes 3 hours of execution time. Then I did a BFS with multiple starting points and solved it in 24 seconds. ~ *The first real algorithm was fun, but bash really shows how slow it is to allocate memory. When doing BFS, the debug printouts really slowed down when I reached a point that had not visited before. But when I found a point I had already visited, and the parent array was allocated, it REALLY sped up. For future days I will have to remember to use actual algorithms, and look up how to malloc in bash...... Otherwise I might slip from 6th place and have to wait for hours for my scripts to run... Hope it is possible to malloc...*
124 changes: 124 additions & 0 deletions day12/find_any_path_bfs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/bin/bash
if [ "$#" -gt 0 ]; then
printf '%s\n' "$@"
fi

declare -A map

row=0
startQueue=( )

while IFS= read -r string; do
sX=0
sY=0
map[$row]=$string
row=$(($row+1))
tX=0

for char in $(echo $string | sed -e 's/\(.\)/\1\n/g'); do
if [[ "$char" == "S" || "$char" == "a" ]]; then
echo "Starting at $tX,$(($row-1))"
startQueue+=("$tX,$(($row-1))")
fi
tX=$(($tX+1))
done
done


function getKeyCode () {
local X=$1
local Y=$2
char="${map[$Y]:$X:1}"
if [[ "$char" == "E" ]]; then
echo $(printf %d "'z")
elif [[ "$char" == "S" ]]; then
echo $(printf %d "'a")
else
echo $(printf %d "'${map[$Y]:$X:1}")
fi
}

function findPossiblePaths () {
local X=$1
local Y=$2

possibilities=""
for x in $(seq $(($X-1)) $(($X+1))); do
for y in $(seq $(($Y-1)) $(($Y+1))); do
#echo " Checking $x $y" >&2
if ! [[ $X -eq $x && $Y -eq $y ]] && [[ $x -ge 0 && $x -lt ${#map[0]} && $y -ge 0 && $y -lt $row ]] && [[ $x -eq $X || $y -eq $Y ]] ; then
current=$(getKeyCode $X $Y)
next=$(getKeyCode $x $y)
#echo " $x $y passed the coord check, onto keycode $current $next" >&2
if [[ "$current $(($current+1))" == *"$next"* ]] || [[ $next -lt $current && ! $next -eq 83 ]] || [[ $current -eq 83 ]]; then
#echo " $x $y was valid" >&2
possibilities="$x,$y $possibilities"
fi
fi
done
done
#echo $possibilities >&2
echo $possibilities
}


declare -A visited

declare -A distances

for x in $(seq 0 $((${#map[0]}-1))); do # Mark all as not visited
for y in $(seq 0 $(($row-1))); do
visited["$x,$y"]=0
done
done


queue=( )

for point in ${startQueue[@]}; do
visited["$point"]=1
queue+=("$point")
done
declare -A parents

target=""
while [ ${#queue[@]} -gt 0 ]; do
elem=${queue[0]}
queue=("${queue[@]:1}")

IFS="," read -ra coords <<< $elem
#echo "Elem: $elem Pos: ${map[${coords[1]}]:${coords[0]}:1}"
if [[ "${map[${coords[1]}]:${coords[0]}:1}" == "E" ]]; then
echo "FOUND IT! $elem"
target=$elem
fi

for coord in $(findPossiblePaths ${coords[0]} ${coords[1]}); do
IFS="," read -ra xy <<< $coord
if [[ ${visited["${xy[0]},${xy[1]}"]} -eq 0 ]]; then
queue+=("${xy[0]},${xy[1]}")
visited["${xy[0]},${xy[1]}"]=1
parents["${xy[0]},${xy[1]}"]="${coords[0]},${coords[1]}"
fi
done
done
par=$target
#echo " TARGET: $target"
steps=1
while [[ 1 -eq 1 ]]; do
IFS="," read -ra coords <<< $par
parent=${parents[$par]}
#echo " par: $par Parent: $parent"
for elem in ${startQueue[@]}; do
if [[ "$elem" == "$parent" ]]; then
echo "Steps to find: $steps"
distances["$startX,$startY"]=$steps
exit
fi
done
par=$parent
steps=$(($steps+1))
done
108 changes: 108 additions & 0 deletions day12/find_path.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/bin/bash
if [ "$#" -gt 0 ]; then
printf '%s\n' "$@"
fi

declare -A map

row=0
startX=0
startY=0
while IFS= read -r string; do
map[$row]=$string
row=$(($row+1))
if [[ "$string" == *"S"* ]]; then
rest=${string#*"S"}
startX=$(( ${#string} - ${#rest} - 1 ))
startY=$(($row-1))
fi
done

numSpots=$(($row*${#map[0]}))
echo "Starting point: $startX $startY numSpots: $numSpots"


function getKeyCode () {
local X=$1
local Y=$2
char="${map[$Y]:$X:1}"
if [[ "$char" == "E" ]]; then
echo $(printf %d "'z")
else
echo $(printf %d "'${map[$Y]:$X:1}")
fi
}

function findPossiblePaths () {
local X=$1
local Y=$2
local fromX=$3
local fromY=$4

possibilities=""
for x in $(seq $(($X-1)) $(($X+1))); do
for y in $(seq $(($Y-1)) $(($Y+1))); do
#echo " Checking $x $y" >&2
if ! [[ $fromX -eq $x && $fromY -eq $y ]] && ! [[ $X -eq $x && $Y -eq $y ]] && [[ $x -ge 0 && $x -lt ${#map[0]} && $y -ge 0 && $y -lt $row ]] && [[ $x -eq $X || $y -eq $Y ]] ; then
current=$(getKeyCode $X $Y)
next=$(getKeyCode $x $y)
#echo " $x $y passed the coord check, onto keycode $current $next" >&2
if [[ "$current $(($current+1))" == *"$next"* ]] || [[ $next -lt $current && ! $next -eq 83 ]] || [[ $current -eq 83 ]]; then
#echo " $x $y was valid" >&2
if [[ $next -ge $current ]]; then
possibilities="$x,$y $possibilities"
else
possibilities="$possibilities $x,$y "
fi
fi
fi
done
done
#echo $possibilities >&2
echo $possibilities
}

function tryPath () {
local distance=$1
local X=$2
local Y=$3
local lastX=$4
local lastY=$5

distance=$(($distance+1))
echo "X: $X Y: $Y Row: ${map[$Y]} Current char: ${map[$Y]:$X:1} Distance: $distance" >&2

if [[ "${map[$Y]:$X:1}" == "E" ]]; then
#I am at the target, return
echo "Found it at $X $Y, distance $(($distance-1))!" >&2
echo $(($distance-1))
sleep 5
elif [[ $distance -le $numSpots ]]; then

declare -A paths
counter=0
for coord in $(findPossiblePaths $X $Y $lastX $lastY); do
counter=$(($counter+1))
IFS="," read -ra xy <<< $coord
#sleep 1
paths[$counter]=$(tryPath $distance ${xy[0]} ${xy[1]} $X $Y)
done

#sleep 1
if [[ $counter -eq 0 ]]; then #No paths could be tried
echo " No goal" >&2
echo "-"
else
IFS=$'\n' sorted=($(sort -n <<<"${paths[*]}"))
echo " Returning ${sorted[0]}"
echo ${sorted[0]}
fi
else
echo " Too great distance" >&2
echo "-"
fi
}



echo "Shortest path? $(tryPath 0 $startX $startY $startX $startY)"
113 changes: 113 additions & 0 deletions day12/find_path_bfs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/bin/bash
if [ "$#" -gt 0 ]; then
printf '%s\n' "$@"
fi

declare -A map
declare -A visited

row=0
startX=0
startY=0
while IFS= read -r string; do
map[$row]=$string
row=$(($row+1))
if [[ "$string" == *"S"* ]]; then
rest=${string#*"S"}
startX=$(( ${#string} - ${#rest} - 1 ))
startY=$(($row-1))
fi
done

numSpots=$(($row*${#map[0]}))
echo "Starting point: $startX $startY numSpots: $numSpots"

for x in $(seq 0 $((${#map[0]}-1))); do # Mark all as not visited
for y in $(seq 0 $(($row-1))); do
visited["$x,$y"]=0
done
done



function getKeyCode () {
local X=$1
local Y=$2
char="${map[$Y]:$X:1}"
if [[ "$char" == "E" ]]; then
echo $(printf %d "'z")
else
echo $(printf %d "'${map[$Y]:$X:1}")
fi
}

function findPossiblePaths () {
local X=$1
local Y=$2

possibilities=""
for x in $(seq $(($X-1)) $(($X+1))); do
for y in $(seq $(($Y-1)) $(($Y+1))); do
#echo " Checking $x $y" >&2
if ! [[ $X -eq $x && $Y -eq $y ]] && [[ $x -ge 0 && $x -lt ${#map[0]} && $y -ge 0 && $y -lt $row ]] && [[ $x -eq $X || $y -eq $Y ]] ; then
current=$(getKeyCode $X $Y)
next=$(getKeyCode $x $y)
#echo " $x $y passed the coord check, onto keycode $current $next" >&2
if [[ "$current $(($current+1))" == *"$next"* ]] || [[ $next -lt $current && ! $next -eq 83 ]] || [[ $current -eq 83 ]]; then
#echo " $x $y was valid" >&2
possibilities="$x,$y $possibilities"
fi
fi
done
done
echo $possibilities >&2
echo $possibilities
}




visited["$startX,$startY"]=1

queue=( )


declare -A parents

target=""
queue+=("$startX,$startY")
while [ ${#queue[@]} -gt 0 ]; do
elem=${queue[0]}
queue=("${queue[@]:1}")

IFS="," read -ra coords <<< $elem
echo "Elem: $elem Pos: ${map[${coords[1]}]:${coords[0]}:1}"
if [[ "${map[${coords[1]}]:${coords[0]}:1}" == "E" ]]; then
echo "FOUND IT! $elem"
target=$elem
fi

for coord in $(findPossiblePaths ${coords[0]} ${coords[1]}); do
IFS="," read -ra xy <<< $coord
if [[ ${visited["${xy[0]},${xy[1]}"]} -eq 0 ]]; then
queue+=("${xy[0]},${xy[1]}")
visited["${xy[0]},${xy[1]}"]=1
parents["${xy[0]},${xy[1]}"]="${coords[0]},${coords[1]}"
fi
done
done
par=$target
steps=1
while [[ 1 -eq 1 ]]; do
IFS="," read -ra coords <<< $par
parent=${parents[$par]}
echo "par: $par Parent: $parent"
if [[ "$parent" == "$startX,$startY" ]]; then
echo "Steps to find: $steps"
exit
fi
par=$parent
steps=$(($steps+1))
done

0 comments on commit fca8471

Please sign in to comment.