124 lines
3.6 KiB
Go
124 lines
3.6 KiB
Go
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
|
|
}
|