This commit is contained in:
2022-12-19 15:07:39 +01:00
parent 3e927f2f70
commit 0aa38a19f1
3 changed files with 250 additions and 0 deletions

210
day19/common/factory.go Normal file
View File

@@ -0,0 +1,210 @@
package common
import (
"bufio"
"strconv"
"strings"
)
type Material byte
const (
Ore Material = iota
Clay
Obsidian
Geode
)
type Robot byte
const (
OreMiner Robot = iota
ClayMiner
ObsidianMiner
GeodeMiner
)
type Factory struct {
id int
materials map[Material]int
robots map[Robot]int
costs map[Robot]map[Material]int
minutesLeft int
builtRobots []Robot
maxProductionRequired map[Material]int
}
func (factory *Factory) clone() *Factory {
newFactory := Factory{factory.id, make(map[Material]int), map[Robot]int{}, factory.costs, factory.minutesLeft, []Robot{}, factory.maxProductionRequired}
for m, v := range factory.materials {
newFactory.materials[m] = v
}
for r, v := range factory.robots {
newFactory.robots[r] = v
}
for i := range factory.builtRobots {
newFactory.builtRobots = append(newFactory.builtRobots, factory.builtRobots[i])
}
return &newFactory
}
func (factory *Factory) GenerateResources() {
for r, v := range factory.robots {
switch r {
case OreMiner:
factory.materials[Ore] += v
case ClayMiner:
factory.materials[Clay] += v
case ObsidianMiner:
factory.materials[Obsidian] += v
case GeodeMiner:
factory.materials[Geode] += v
}
}
for i := range factory.builtRobots {
factory.robots[factory.builtRobots[i]]++
}
factory.builtRobots = []Robot{}
factory.minutesLeft--
}
func (factory *Factory) StartOptimizedProduction() {
factory.GenerateResources()
newFactories := []*Factory{factory.clone(), factory.clone(), factory.clone(), factory.clone()}
for i := range newFactories {
if i == 0 {
for (newFactories[i].materials[Ore] < newFactories[i].costs[GeodeMiner][Ore] ||
newFactories[i].materials[Obsidian] < newFactories[i].costs[GeodeMiner][Obsidian]) &&
newFactories[i].minutesLeft > 0 {
newFactories[i].GenerateResources()
}
if newFactories[i].minutesLeft > 0 {
newFactories[i].builtRobots = []Robot{GeodeMiner}
newFactories[i].materials[Ore] -= newFactories[i].costs[GeodeMiner][Ore]
newFactories[i].materials[Obsidian] -= newFactories[i].costs[GeodeMiner][Obsidian]
newFactories[i].StartOptimizedProduction()
}
} else if i == 1 && newFactories[i].robots[ObsidianMiner] < newFactories[i].maxProductionRequired[Obsidian] {
for (newFactories[i].materials[Ore] < newFactories[i].costs[ObsidianMiner][Ore] ||
newFactories[i].materials[Clay] < newFactories[i].costs[ObsidianMiner][Clay]) &&
newFactories[i].minutesLeft > 0 {
newFactories[i].GenerateResources()
}
if newFactories[i].minutesLeft > 0 {
newFactories[i].builtRobots = []Robot{ObsidianMiner}
newFactories[i].materials[Ore] -= newFactories[i].costs[ObsidianMiner][Ore]
newFactories[i].materials[Clay] -= newFactories[i].costs[ObsidianMiner][Clay]
newFactories[i].StartOptimizedProduction()
}
} else if i == 2 && newFactories[i].robots[ClayMiner] < newFactories[i].maxProductionRequired[Clay] {
for newFactories[i].materials[Ore] < newFactories[i].costs[ClayMiner][Ore] &&
newFactories[i].minutesLeft > 0 {
newFactories[i].GenerateResources()
}
if newFactories[i].minutesLeft > 0 {
newFactories[i].builtRobots = []Robot{ClayMiner}
newFactories[i].materials[Ore] -= newFactories[i].costs[ClayMiner][Ore]
newFactories[i].StartOptimizedProduction()
}
} else if i == 3 && newFactories[i].robots[OreMiner] < newFactories[i].maxProductionRequired[Ore] {
for newFactories[i].materials[Ore] < newFactories[i].costs[OreMiner][Ore] &&
newFactories[i].minutesLeft > 0 {
newFactories[i].GenerateResources()
}
if newFactories[i].minutesLeft > 0 {
newFactories[i].builtRobots = []Robot{OreMiner}
newFactories[i].materials[Ore] -= newFactories[i].costs[OreMiner][Ore]
newFactories[i].StartOptimizedProduction()
}
}
if newFactories[i].materials[Geode] > factory.materials[Geode] {
factory.materials = newFactories[i].materials
factory.robots = newFactories[i].robots
factory.minutesLeft = newFactories[i].minutesLeft
}
}
}
func (factory *Factory) GetQualityLevel() int {
return factory.id * factory.materials[Geode]
}
func (factory *Factory) GetNumberOfGeodes() int {
return factory.materials[Geode]
}
func Parse(scanner bufio.Scanner, limit int, minutesLeft int) []Factory {
factories := []Factory{}
i := 0
for scanner.Scan() {
if limit >= 0 && i >= limit {
break
}
line := scanner.Text()
splittedLine := strings.Split(line, ".")
factory := Factory{}
splittedLine2 := strings.Split(splittedLine[0], " ")
id, _ := strconv.Atoi(splittedLine2[1][:len(splittedLine2[1])-1])
factory.id = id
factory.materials = make(map[Material]int)
factory.materials[Ore] = 0
factory.materials[Clay] = 0
factory.materials[Obsidian] = 0
factory.materials[Geode] = 0
factory.robots = make(map[Robot]int)
factory.robots[OreMiner] = 1
factory.robots[ClayMiner] = 0
factory.robots[ObsidianMiner] = 0
factory.robots[GeodeMiner] = 0
factory.minutesLeft = minutesLeft
factory.maxProductionRequired = make(map[Material]int)
factory.costs = make(map[Robot]map[Material]int)
oreCost, _ := strconv.Atoi(splittedLine2[6])
factory.costs[OreMiner] = make(map[Material]int)
factory.costs[OreMiner][Ore] = oreCost
factory.maxProductionRequired[Ore] = oreCost
splittedLine2 = strings.Split(splittedLine[1], " ")
oreCost, _ = strconv.Atoi(splittedLine2[5])
factory.costs[ClayMiner] = make(map[Material]int)
factory.costs[ClayMiner][Ore] = oreCost
if oreCost > factory.maxProductionRequired[Ore] {
factory.maxProductionRequired[Ore] = oreCost
}
splittedLine2 = strings.Split(splittedLine[2], " ")
oreCost, _ = strconv.Atoi(splittedLine2[5])
clayCost, _ := strconv.Atoi(splittedLine2[8])
factory.costs[ObsidianMiner] = make(map[Material]int)
factory.costs[ObsidianMiner][Ore] = oreCost
factory.costs[ObsidianMiner][Clay] = clayCost
if oreCost > factory.maxProductionRequired[Ore] {
factory.maxProductionRequired[Ore] = oreCost
}
factory.maxProductionRequired[Clay] = clayCost
splittedLine2 = strings.Split(splittedLine[3], " ")
oreCost, _ = strconv.Atoi(splittedLine2[5])
obsidianCost, _ := strconv.Atoi(splittedLine2[8])
factory.costs[GeodeMiner] = make(map[Material]int)
factory.costs[GeodeMiner][Ore] = oreCost
factory.costs[GeodeMiner][Obsidian] = obsidianCost
if oreCost > factory.maxProductionRequired[Ore] {
factory.maxProductionRequired[Ore] = oreCost
}
factory.maxProductionRequired[Obsidian] = obsidianCost
factories = append(factories, factory)
i++
}
return factories
}