Skip to content

Instantly share code, notes, and snippets.

@rhowe
Created December 16, 2019 11:24
Show Gist options
  • Save rhowe/ce856816a70f599491c3fa28b3b0a377 to your computer and use it in GitHub Desktop.
Save rhowe/ce856816a70f599491c3fa28b3b0a377 to your computer and use it in GitHub Desktop.
14.sh
#!/bin/bash -eu
declare -A stockpile batchsizes recipes
startingore=1000000000000
stockpile[ORE]=$startingore
stockpile[FUEL]=0
batchsizes[ORE]=1
recipefile=$(dirname "$0")/recipes.sh
stock() {
local thing
for thing in "${!stockpile[@]}"; do
echo "$thing: ${stockpile[$thing]} "
done
}
mine() {
case "$1" in
ORE)
stockpile[ORE]=$((${stockpile[ORE]} - $2))
if [ "${stockpile[ORE]}" -lt 0 ]; then
echo "Ran out of ORE! Mined ${stockpile[FUEL]} fuel" >&2
exit
fi
;;
*)
while [ "${stockpile[$1]}" -lt $2 ]; do
"mine_$1"
done
stockpile[$1]=$((${stockpile[$1]}-$2))
;;
esac
}
generate_recipes() {
local -a reactions
mapfile -t reactions
> "$recipefile"
for reaction in "${reactions[@]}"; do
local src=${reaction% =>*}
local -a sources
IFS=' ' read -ra dests <<<"${reaction#* => }"
IFS=, read -ra sources <<<"${src//, /,}"
echo "stockpile[${dests[1]}]=0" >> "$recipefile"
echo "batchsizes[${dests[1]}]=${dests[0]}" >> "$recipefile"
echo "mine_${dests[1]}() {" >> "$recipefile"
for source in "${sources[@]}"; do
amount=${source% *}
ingredient=${source#* }
echo " mine $ingredient $amount" >> "$recipefile"
done
echo " stockpile[${dests[1]}]=\$((\${stockpile[${dests[1]}]}+${dests[0]}))" >> "$recipefile"
echo "}" >> "$recipefile"
done
}
parse() {
local reaction
local -a reactions
mapfile -t reactions < "$1"
for reaction in "${reactions[@]}"; do
local sourcepart=${reaction% =>*}
local -a sources
IFS=' ' read -ra dests <<<"${reaction#* => }"
batchsizes[${dests[1]}]=${dests[0]}
recipes[${dests[1]}]=$sourcepart
done
}
multiply() {
local product=$1 mul=$2 source newsourcestr src qty
local sourcepart=${recipes[$product]}
local -a sources newsources=()
IFS=, read -ra sources <<<"${sourcepart//, /,}"
for source in "${sources[@]}"; do
read -r qty src <<<"$source"
newsources+=("$((qty*mul)) $src")
done
IFS=, newsourcestr="${newsources[*]}"
echo "${newsourcestr//,/, }"
}
optimise() {
local src qty oldsource newsourcepart product oldifs changesmade=1
local -a reactions sources newsources
mapfile -t reactions
while [ "$changesmade" -ne 0 ]; do
changesmade=0
for product in "${!recipes[@]}"; do
newsources=()
sourcepart=${recipes[$product]}
#[ "$product" != WDJKB ] || echo "Examining $product, made of $sourcepart"
IFS=, read -ra sources <<<"${sourcepart//, /,}"
for oldsource in "${sources[@]}"; do
read -r qty src <<<"$oldsource"
#[ "$product" != WDJKB ] || echo "'$oldsource': we need $qty of source $src (${recipes[$src]})"
if [ "$src" != ORE ] && [ "$qty" -ge "${batchsizes[$src]}" ]; then
#[ "$product" != WDJKB ] || echo "this is $((qty / ${batchsizes[$src]}))x more than the batch size with $((qty % ${batchsizes[$src]})) left over"
newpart=$(multiply $src $((qty / ${batchsizes[$src]})))
[ "$((qty % ${batchsizes[$src]}))" -eq 0 ] || newpart="$newpart, $((qty % ${batchsizes[$src]})) $src"
#[ "$product" != WDJKB ] || echo "Replacing $qty $src with $newpart"
newsources+=("$newpart")
changesmade=1
else
newsources+=("$qty $src")
fi
done
oldifs=$IFS
IFS=, newsourcepart="${newsources[*]}"
IFS=$oldifs
newsourcepart="${newsourcepart//,/, }"
newsourcepart="${newsourcepart// / }"
#[ "$product" != WDJKB ] || echo "$product is now made of $newsourcepart"
recipes[$product]="${newsourcepart}"
done
if ! merge; then
changesmade=1
fi
done
}
merge() {
local src qty sourcestr newsourcepart product oldifs changesmade=0
local -a reactions sources newsources
local -A recipeqty
for product in "${!recipes[@]}"; do
newsources=()
for prodsrc in "${!recipes[@]}"; do
recipeqty[$prodsrc]=0
done
recipeqty[ORE]=0
sourcepart=${recipes[$product]}
IFS=, read -ra sources <<<"${sourcepart//, /,}"
for sourcestr in "${sources[@]}"; do
read -r qty src <<<"$sourcestr"
if [ "${recipeqty[$src]}" -ne 0 ]; then
changesmade=1
fi
recipeqty[$src]=$((${recipeqty[$src]}+qty))
done
for src in "${!recipeqty[@]}"; do
[ "${recipeqty[$src]}" -ne 0 ] || continue
newsources+=("${recipeqty[$src]} $src")
done
oldifs=$IFS
IFS=, newsourcepart="${newsources[*]}"
IFS=$oldifs
newsourcepart="${newsourcepart//,/, }"
newsourcepart="${newsourcepart// / }"
recipes[$product]="${newsourcepart}"
done
return $changesmade
}
generate() {
for product in "${!recipes[@]}"; do
echo "${recipes[$product]} => ${batchsizes[$product]} $product"
done
}
parse "$1"
optimise < "$1"
generate | generate_recipes
. "$recipefile"
[ -z "${DEBUG:-}" ] || clear
mine_FUEL
ore_used=$((startingore - ${stockpile[ORE]}))
echo "Used $((ore_used)) ORE for 1 FUEL"
echo "Mining continues"
t0=$((SECONDS-1))
f0=1
o0=${stockpile[ORE]}
fuelrate=-
orerate=-1
while true; do
mine_FUEL
if (( ${stockpile[FUEL]} % 100 == 0)); then
fuelrate=$((((${stockpile[FUEL]}-f0) / (SECONDS-t0))))
orerate=$((((${stockpile[ORE]}-o0) / (SECONDS-t0))))
if [ -z "${DEBUG:-}" ]; then
echo "Making $fuelrate fuel/s using $((-1 * orerate)) ore/s (${stockpile[ORE]} ore left) ETA $(date -d "now + $((${stockpile[ORE]} / (-1 * orerate))) seconds") "
else
out=$(
tput cup 0 0
stock|sort
echo "Making $fuelrate fuel/s using $((-1 * orerate)) ore/s ETA $(date -d "now + $((${stockpile[ORE]} / (-1 * orerate))) seconds") "
)
echo "$out"
fi
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment