package days import ( "fmt" "strconv" "strings" u "parnic.com/aoc2019/utilities" ) type reaction struct { inputs map[string]int output u.Pair[string, int] } type Day14 struct { reactions []reaction leftovers map[string]int } func (d *Day14) Parse() { d.leftovers = make(map[string]int) lines := u.GetStringLines("14s2") d.reactions = make([]reaction, len(lines)) for i, line := range lines { sides := strings.Split(line, " => ") inputs := strings.Split(sides[0], ", ") output := sides[1] outPair := strings.Split(output, " ") outAmt, _ := strconv.Atoi(outPair[0]) d.reactions[i].output = u.Pair[string, int]{First: outPair[1], Second: outAmt} d.reactions[i].inputs = make(map[string]int) for _, input := range inputs { pair := strings.Split(input, " ") d.reactions[i].inputs[pair[1]], _ = strconv.Atoi(pair[0]) } } } func (d Day14) getReactionProducing(chem string) *reaction { for _, reaction := range d.reactions { if reaction.output.First == chem { return &reaction } } return nil } func (d Day14) Num() int { return 14 } func (d Day14) getOreRequiredFor(chem string, amt int) (int, int) { requiredOre := 0 for _, reaction := range d.reactions { if reaction.output.First == chem { // if oreAmt, exists := reaction.inputs["ORE"]; exists && len(reaction.inputs) == 1 { // if d.leftovers[chem] >= amt { // d.leftovers[chem] -= amt // return 0, amt // } // produced := reaction.output.Second // for produced < amt { // requiredOre += oreAmt // produced += reaction.output.Second // } // requiredOre += oreAmt // if produced > amt { // d.leftovers[chem] += produced - amt // } // return requiredOre, produced // } else { for inChem, inAmt := range reaction.inputs { produced := 0 if d.leftovers[inChem] >= inAmt { d.leftovers[inChem] -= inAmt produced = inAmt } else { for produced < inAmt { madeOre, madeChem := d.getOreRequiredFor(inChem, inAmt) produced += madeChem requiredOre += madeOre } if produced > inAmt { d.leftovers[inChem] += produced - inAmt } } } // } } } return requiredOre, 0 } func (d *Day14) Part1() string { fuelReaction := d.getReactionProducing("FUEL") if fuelReaction == nil { 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 { return "" }