This one's part 1 destroyed me. I had a very difficult time, trying 3 separate approaches, each one of which worked for most cases but eventually fell apart on the 5th sample or my actual puzzle input. I ended up tweaking and rewriting until I landed on this which wasn't far off from what I was trying to do previously, but I had been overcomplicating things. Part 2 surprised me in that I expected a simple "ore available divided by ore needed for 1 fuel" would solve it, but of course the excess chemicals produced in any given reaction meant that it wasn't that simple. So this approach uses that estimate as a lower bound, since it always underestimates, and then bisects its way to the solution (starting at the lower bound and adding 1 each time took too long). I'm sure a smarter upper bound choice could lower the runtime of this by a bit, but runtime isn't bad enough right now for me to try any additional optimizations.
27 lines
773 B
Go
27 lines
773 B
Go
package utilities
|
|
|
|
import (
|
|
"math"
|
|
)
|
|
|
|
// Bisect takes a known-good low and known-bad high value as the bounds
|
|
// to bisect, and a function to test each value for success or failure.
|
|
// If the function succeeds, the value is adjusted toward the maximum,
|
|
// and if the function fails, the value is adjusted toward the minimum.
|
|
// The final value is returned when the difference between the success
|
|
// and the failure is less than or equal to the acceptance threshold
|
|
// (usually 1, for integers).
|
|
func Bisect[T Number](low, high, threshold T, tryFunc func(val T) bool) T {
|
|
for T(math.Abs(float64(high-low))) > threshold {
|
|
currVal := low + ((high - low) / 2)
|
|
success := tryFunc(currVal)
|
|
if success {
|
|
low = currVal
|
|
} else {
|
|
high = currVal
|
|
}
|
|
}
|
|
|
|
return low
|
|
}
|