Day 14 complete

This commit is contained in:
2022-06-12 11:21:40 -05:00
parent 060cfeb610
commit 7c4033a8d1
2 changed files with 78 additions and 83 deletions

View File

@ -2,6 +2,7 @@ package days
import ( import (
"fmt" "fmt"
"math"
"strconv" "strconv"
"strings" "strings"
@ -21,7 +22,7 @@ type Day14 struct {
func (d *Day14) Parse() { func (d *Day14) Parse() {
d.leftovers = make(map[string]int) d.leftovers = make(map[string]int)
lines := u.GetStringLines("14s2") lines := u.GetStringLines("14p")
d.reactions = make([]reaction, len(lines)) d.reactions = make([]reaction, len(lines))
for i, line := range lines { for i, line := range lines {
sides := strings.Split(line, " => ") sides := strings.Split(line, " => ")
@ -53,97 +54,74 @@ func (d Day14) Num() int {
return 14 return 14
} }
func (d Day14) getOreRequiredFor(chem string, amt int) (int, int) { func (d *Day14) oreRequiredStock(qty int64) int64 {
requiredOre := 0 oreRequired := int64(0)
for _, reaction := range d.reactions { needs := map[string]int64{
if reaction.output.First == chem { "FUEL": qty,
// if oreAmt, exists := reaction.inputs["ORE"]; exists && len(reaction.inputs) == 1 { }
// if d.leftovers[chem] >= amt { excess := make(map[string]int64)
// d.leftovers[chem] -= amt
// return 0, amt
// }
// produced := reaction.output.Second getFromExcess := func(qty int64, chemical string) int64 {
// for produced < amt { inStock := excess[chemical]
// requiredOre += oreAmt qty -= inStock
// produced += reaction.output.Second excess[chemical] = int64(math.Min(math.Abs(float64(qty)), 0))
// } return inStock - excess[chemical]
// requiredOre += oreAmt }
// if produced > amt {
// d.leftovers[chem] += produced - amt for len(needs) > 0 {
// } keys := u.MapKeys(needs)
// return requiredOre, produced chemical := keys[len(keys)-1]
// } else { qtyRequired := needs[chemical]
for inChem, inAmt := range reaction.inputs { delete(needs, chemical)
produced := 0
if d.leftovers[inChem] >= inAmt { fromExcess := getFromExcess(qtyRequired, chemical)
d.leftovers[inChem] -= inAmt qtyRequired -= fromExcess
produced = inAmt
} else { reaction := d.getReactionProducing(chemical)
for produced < inAmt { qtyProduced := int64(reaction.output.Second)
madeOre, madeChem := d.getOreRequiredFor(inChem, inAmt) ingredients := reaction.inputs
produced += madeChem
requiredOre += madeOre n := int64(math.Ceil(float64(qtyRequired) / float64(qtyProduced)))
}
if produced > inAmt { excess[chemical] = (qtyProduced * n) - qtyRequired
d.leftovers[inChem] += produced - inAmt for ingredient, qtyIngredient := range ingredients {
} if ingredient == "ORE" {
} oreRequired += int64(int64(qtyIngredient) * n)
} else {
needs[ingredient] += int64(qtyIngredient) * n
} }
// }
} }
} }
return requiredOre, 0 return oreRequired
} }
func (d *Day14) Part1() string { func (d *Day14) Part1() string {
fuelReaction := d.getReactionProducing("FUEL") neededOre := d.oreRequiredStock(1)
if fuelReaction == nil { return fmt.Sprintf("%s%d%s", u.TextBold, neededOre, u.TextReset)
panic("")
}
neededMaterial := map[string]int{
"FUEL": 1,
}
var recurse func(neededMaterial map[string]int) map[string]int
recurse = func(neededMaterial map[string]int) map[string]int {
neededInputs := make(map[string]int)
for chem, amt := range neededMaterial {
reaction := d.getReactionProducing(chem)
if reaction == nil {
continue
}
produced := reaction.output.Second
reactionsNeeded := 1
for produced < amt {
produced += reaction.output.Second
reactionsNeeded++
}
for inChem, inAmt := range reaction.inputs {
neededInputs[inChem] += inAmt * reactionsNeeded
}
}
if len(neededInputs) > 0 {
recursed := recurse(neededInputs)
for k, v := range recursed {
neededInputs[k] += v
}
}
return neededInputs
}
recursed := recurse(neededMaterial)
fmt.Println(len(recursed))
ore := 0
for inChem, inAmt := range fuelReaction.inputs {
requiredOre, _ := d.getOreRequiredFor(inChem, inAmt)
ore += requiredOre
}
return fmt.Sprintf("%s%d%s", u.TextBold, ore, u.TextReset)
} }
func (d *Day14) Part2() string { func (d *Day14) Part2() string {
return "" oreAvailable := int64(1000000000000)
estimate := oreAvailable / d.oreRequiredStock(1)
high := estimate * 2
low := estimate
lastSuccess := low
lastFailure := high
fuelProduced := low
for math.Abs(float64(lastFailure)-float64(lastSuccess)) > 1 {
oreConsumed := d.oreRequiredStock(fuelProduced)
if oreConsumed < oreAvailable {
lastSuccess = fuelProduced
fuelProduced += (lastFailure - lastSuccess) / 2
} else {
lastFailure = fuelProduced
fuelProduced -= (lastFailure - lastSuccess) / 2
}
}
return fmt.Sprintf("%s%d%s", u.TextBold, lastSuccess, u.TextReset)
} }

17
utilities/map.go Normal file
View File

@ -0,0 +1,17 @@
package utilities
func MapKeys[T comparable, U any](m map[T]U) []T {
r := make([]T, 0, len(m))
for k := range m {
r = append(r, k)
}
return r
}
func MapValues[T comparable, U any](m map[T]U) []U {
r := make([]U, 0, len(m))
for _, v := range m {
r = append(r, v)
}
return r
}