package main import ( "fmt" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) type blueprint struct { id int oreBot oreBot clayBot clayBot obsidianBot obsidianBot geodeBot geodeBot } type oreBot struct{ oreCost int } type clayBot struct{ oreCost int } type obsidianBot struct{ oreCost, clayCost int } type geodeBot struct{ oreCost, obsidianCost int } var globalBest = 0 func main() { blueprints := parseInput(h.StdinToStringSlice()) part1(blueprints) part2(blueprints) } func part1(blueprints []blueprint) { result := 0 for _, bp := range blueprints { result += bp.id * search(bp, 0, 0, 0, 24, 1, 0, 0, 0, 0) globalBest = 0 } fmt.Println("# Part 1") fmt.Println(result) fmt.Println() } func part2(blueprints []blueprint) { if len(blueprints) < 3 { fmt.Println("# Part 2") fmt.Println("Error: Not enough Blueprints") return } result := 1 for i := 0; i < 3; i++ { result *= search(blueprints[i], 0, 0, 0, 32, 1, 0, 0, 0, 0) globalBest = 0 } fmt.Println("# Part 2") fmt.Println(result) } func search(bp blueprint, ore, clay, obs, time, oreBots, clayBots, obsidianBots, geodeBots, geodes int) int { if time == 0 || globalBest >= geodes+rangeSum(geodeBots, geodeBots+time-1) { return 0 } if oreBots >= bp.geodeBot.oreCost && obsidianBots >= bp.geodeBot.obsidianCost { return rangeSum(geodeBots, geodeBots+time-1) } oreLimitHit := oreBots >= h.Max(bp.geodeBot.oreCost, h.Max(bp.clayBot.oreCost, bp.obsidianBot.oreCost)) clayLimitHit := clayBots >= bp.obsidianBot.clayCost obsLimitHit := obsidianBots >= bp.geodeBot.obsidianCost best := 0 if !oreLimitHit { best = h.Max( best, geodeBots+search( bp, ore+oreBots, clay+clayBots, obs+obsidianBots, time-1, oreBots, clayBots, obsidianBots, geodeBots, geodes+geodeBots)) } if ore >= bp.oreBot.oreCost && !oreLimitHit { best = h.Max( best, geodeBots+search( bp, ore-bp.oreBot.oreCost+oreBots, clay+clayBots, obs+obsidianBots, time-1, oreBots+1, clayBots, obsidianBots, geodeBots, geodes+geodeBots)) } if ore >= bp.clayBot.oreCost && !clayLimitHit { best = h.Max( best, geodeBots+search( bp, ore-bp.clayBot.oreCost+oreBots, clay+clayBots, obs+obsidianBots, time-1, oreBots, clayBots+1, obsidianBots, geodeBots, geodes+geodeBots)) } if ore >= bp.obsidianBot.oreCost && clay >= bp.obsidianBot.clayCost && !obsLimitHit { best = h.Max( best, geodeBots+search( bp, ore-bp.obsidianBot.oreCost+oreBots, clay-bp.obsidianBot.clayCost+clayBots, obs+obsidianBots, time-1, oreBots, clayBots, obsidianBots+1, geodeBots, geodes+geodeBots)) } if ore >= bp.geodeBot.oreCost && obs >= bp.geodeBot.obsidianCost { best = h.Max( best, geodeBots+search( bp, ore-bp.geodeBot.oreCost+oreBots, clay+clayBots, obs-bp.geodeBot.obsidianCost+obsidianBots, time-1, oreBots, clayBots, obsidianBots, geodeBots+1, geodes+geodeBots)) } globalBest = h.Max(best, globalBest) return best } func rangeSum(first, last int) int { return last*(last+1)/2 - ((first - 1) * first / 2) } func parseInput(inp []string) []blueprint { var ret []blueprint var id int oreBot := oreBot{} clayBot := clayBot{} obsidianBot := obsidianBot{} geodeBot := geodeBot{} for i := range inp { fmt.Sscanf(inp[i], "Blueprint %d: Each ore robot costs %d ore. Each clay robot costs %d ore. Each obsidian robot costs %d ore and %d clay. Each geode robot costs %d ore and %d obsidian.", &id, &oreBot.oreCost, &clayBot.oreCost, &obsidianBot.oreCost, &obsidianBot.clayCost, &geodeBot.oreCost, &geodeBot.obsidianCost) ret = append(ret, blueprint{id, oreBot, clayBot, obsidianBot, geodeBot}) } return ret }