Add bisect utility
This is too common of an optimization to not have this readily accessible. And I kinda like how this worked out, too. Go is fun.
This commit is contained in:
24
days/14.go
24
days/14.go
@ -104,26 +104,10 @@ func (d *Day14) Part1() string {
|
||||
func (d *Day14) Part2() string {
|
||||
oreAvailable := int64(1000000000000)
|
||||
estimate := oreAvailable / d.getOreRequiredForFuel(1)
|
||||
|
||||
high := estimate * 2
|
||||
low := estimate
|
||||
|
||||
lastSuccess := low
|
||||
lastFailure := high
|
||||
fuelProduced := low
|
||||
|
||||
for math.Abs(float64(lastFailure-lastSuccess)) > 1 {
|
||||
oreConsumed := d.getOreRequiredForFuel(fuelProduced)
|
||||
adjustment := (lastFailure - lastSuccess) / 2
|
||||
if oreConsumed < oreAvailable {
|
||||
lastSuccess = fuelProduced
|
||||
} else {
|
||||
lastFailure = fuelProduced
|
||||
adjustment = -adjustment
|
||||
}
|
||||
|
||||
fuelProduced += adjustment
|
||||
}
|
||||
lastSuccess := u.Bisect(estimate, estimate*2, 1, func(val int64) bool {
|
||||
oreConsumed := d.getOreRequiredForFuel(val)
|
||||
return oreConsumed < oreAvailable
|
||||
})
|
||||
|
||||
return fmt.Sprintf("Maximum fuel we can make from 1 trillion ore: %s%d%s", u.TextBold, lastSuccess, u.TextReset)
|
||||
}
|
||||
|
28
utilities/bisect.go
Normal file
28
utilities/bisect.go
Normal file
@ -0,0 +1,28 @@
|
||||
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 {
|
||||
currVal := low
|
||||
|
||||
for T(math.Abs(float64(high-low))) > threshold {
|
||||
currVal = low + ((high - low) / 2)
|
||||
success := tryFunc(currVal)
|
||||
if success {
|
||||
low = currVal
|
||||
} else {
|
||||
high = currVal
|
||||
}
|
||||
}
|
||||
|
||||
return currVal
|
||||
}
|
Reference in New Issue
Block a user