🌅
This commit is contained in:
171
solutions/day19/day19.go
Normal file
171
solutions/day19/day19.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package day19
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Blueprint struct {
|
||||
blueprintNumber int
|
||||
oreRobotOreCost int
|
||||
clayRobotOreCost int
|
||||
obsRobotOreCost int
|
||||
obsRobotClayCost int
|
||||
geodeRobotOreCost int
|
||||
geodeRobotObsCost int
|
||||
}
|
||||
|
||||
type State struct {
|
||||
minute int
|
||||
ore int
|
||||
clay int
|
||||
obsidian int
|
||||
geodes int
|
||||
|
||||
oreRobots int
|
||||
clayRobots int
|
||||
obsidianRobots int
|
||||
geodeRobots int
|
||||
}
|
||||
|
||||
var initialState State = State{0, 0, 0, 0, 0, 1, 0, 0, 0}
|
||||
|
||||
func copyState(state State) State {
|
||||
return State{
|
||||
state.minute,
|
||||
state.ore,
|
||||
state.clay,
|
||||
state.obsidian,
|
||||
state.geodes,
|
||||
state.oreRobots,
|
||||
state.clayRobots,
|
||||
state.obsidianRobots,
|
||||
state.geodeRobots,
|
||||
}
|
||||
}
|
||||
|
||||
func nextStates(current State, minutes int, blueprint Blueprint) []State {
|
||||
if current.minute == minutes {
|
||||
return []State{}
|
||||
}
|
||||
|
||||
buyNothing := State{
|
||||
current.minute + 1,
|
||||
current.ore + current.oreRobots,
|
||||
current.clay + current.clayRobots,
|
||||
current.obsidian + current.obsidianRobots,
|
||||
current.geodes + current.geodeRobots,
|
||||
current.oreRobots,
|
||||
current.clayRobots,
|
||||
current.obsidianRobots,
|
||||
current.geodeRobots,
|
||||
}
|
||||
|
||||
retval := []State{buyNothing}
|
||||
|
||||
if current.ore >= blueprint.oreRobotOreCost {
|
||||
buyOre := copyState(buyNothing)
|
||||
buyOre.ore -= blueprint.oreRobotOreCost
|
||||
buyOre.oreRobots += 1
|
||||
retval = append(retval, buyOre)
|
||||
}
|
||||
|
||||
if current.ore >= blueprint.clayRobotOreCost {
|
||||
buyClay := copyState(buyNothing)
|
||||
buyClay.ore -= blueprint.clayRobotOreCost
|
||||
buyClay.clayRobots += 1
|
||||
retval = append(retval, buyClay)
|
||||
}
|
||||
|
||||
if current.ore >= blueprint.obsRobotOreCost && current.clay >= blueprint.obsRobotClayCost {
|
||||
buyObsidian := copyState(buyNothing)
|
||||
buyObsidian.ore -= blueprint.obsRobotOreCost
|
||||
buyObsidian.clay -= blueprint.obsRobotClayCost
|
||||
buyObsidian.obsidianRobots += 1
|
||||
retval = append(retval, buyObsidian)
|
||||
}
|
||||
|
||||
if current.ore >= blueprint.geodeRobotOreCost && current.obsidian >= blueprint.geodeRobotObsCost {
|
||||
buyGeode := copyState(buyNothing)
|
||||
buyGeode.ore -= blueprint.geodeRobotOreCost
|
||||
buyGeode.obsidian -= blueprint.geodeRobotObsCost
|
||||
buyGeode.geodeRobots += 1
|
||||
retval = append(retval, buyGeode)
|
||||
}
|
||||
|
||||
return retval
|
||||
}
|
||||
|
||||
func runSimulation(blueprint Blueprint, minutes int) int {
|
||||
visited := map[State]bool{}
|
||||
queue := []State{initialState}
|
||||
bestResult := 0
|
||||
|
||||
for len(queue) > 0 {
|
||||
nextState := queue[len(queue)-1]
|
||||
queue = queue[0 : len(queue)-1]
|
||||
|
||||
_, alreadyDone := visited[nextState]
|
||||
if alreadyDone {
|
||||
continue
|
||||
}
|
||||
visited[nextState] = true
|
||||
|
||||
minutesLeft := minutes - nextState.minute
|
||||
bestPossibleFuture := nextState.geodes + (minutesLeft*(2*nextState.geodeRobots+(minutesLeft-1)))/2
|
||||
if bestPossibleFuture < bestResult {
|
||||
continue
|
||||
}
|
||||
|
||||
newStates := nextStates(nextState, minutes, blueprint)
|
||||
if len(newStates) == 0 {
|
||||
if nextState.geodes > bestResult {
|
||||
bestResult = nextState.geodes
|
||||
}
|
||||
}
|
||||
queue = append(queue, newStates...)
|
||||
}
|
||||
|
||||
return bestResult
|
||||
}
|
||||
|
||||
func Run(filename string) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
fmt.Println("Error opening file:", err)
|
||||
return
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
blueprints := []Blueprint{}
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
var blueprintNumber, oreRobotOre, clayRobotOre, obsRobotOre, obsRobotClay, geodeRobotOre, geodeRobotObs int
|
||||
fmt.Sscanf(line, "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.", &blueprintNumber, &oreRobotOre, &clayRobotOre, &obsRobotOre, &obsRobotClay, &geodeRobotOre, &geodeRobotObs)
|
||||
blueprints = append(blueprints, Blueprint{blueprintNumber, oreRobotOre, clayRobotOre, obsRobotOre, obsRobotClay, geodeRobotOre, geodeRobotObs})
|
||||
}
|
||||
file.Close()
|
||||
|
||||
fmt.Println("Blueprints", blueprints)
|
||||
totalQualityLevel := 0
|
||||
for _, blueprint := range blueprints {
|
||||
geodesHarvested := runSimulation(blueprint, 24)
|
||||
fmt.Println("Found", geodesHarvested, "geodes for blueprint", blueprint.blueprintNumber)
|
||||
totalQualityLevel += geodesHarvested * blueprint.blueprintNumber
|
||||
}
|
||||
fmt.Println("Total quality level of all blueprints at 24 minutes is", totalQualityLevel)
|
||||
|
||||
multipliedGeodes := 1
|
||||
if len(blueprints) > 3 {
|
||||
blueprints = blueprints[0:3]
|
||||
}
|
||||
for _, blueprint := range blueprints {
|
||||
geodesHarvested := runSimulation(blueprint, 32)
|
||||
fmt.Println("Found", geodesHarvested, "geodes for blueprint", blueprint.blueprintNumber)
|
||||
multipliedGeodes *= geodesHarvested
|
||||
}
|
||||
fmt.Println("Multiplied number of geodes of first three blueprints at 32 minutes is", multipliedGeodes)
|
||||
}
|
||||
Reference in New Issue
Block a user