adventofcode/2022/day19/main.go

177 lines
3.6 KiB
Go

package main
import (
"fmt"
"strings"
"time"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
func main() {
fmt.Println()
inp := h.StdinToStringSlice()
part1(inp)
}
func part1(inp []string) {
blueprints := ParseBlueprints(inp)
robots := []Robot{{tp: ResOre}}
var ticks int
resources := make(map[Resource]int)
var done bool
printState(robots, resources)
useBP := blueprints[0]
_ = useBP
// TODO: Get Ratios of needed resources
for !done {
// First check if we can build some bots
if useBP.CanBuild(ResGeode, resources) {
resources = useBP.Build(resGeode, resources)
}
if useBP.CanBuild(ResObsidian, resources) {
resources = useBP.Build(resObsidian, resources)
}
if useBP.CanBuild(ResClay, resources) {
resources = useBP.Build(resClay, resources)
}
// Every tick, each robot gathers one of it's resource
for i := range robots {
resources[robots[i].tp]++
}
ticks++
fmt.Println(h.CLEAR_SCREEN)
printState(robots, resources)
time.Sleep(time.Second / 10)
}
}
func printState(robots []Robot, resources map[Resource]int) {
var oreBots, clayBots, obsBots, geodeBots int
for i := range robots {
switch robots[i].tp {
case ResOre:
oreBots++
case ResClay:
clayBots++
case ResObsidian:
obsBots++
case ResGeode:
geodeBots++
}
}
fmt.Printf(
"Bots: %2d Ore, %2d Clay, %2d Obsidian, %2d Geode\n",
oreBots, clayBots, obsBots, geodeBots)
fmt.Printf("[ Ore : %2d ]\n", resources[ResOre])
fmt.Printf("[ Clay : %2d ]\n", resources[ResClay])
fmt.Printf("[ Obsidian: %2d ]\n", resources[ResObsidian])
fmt.Printf("[ Geode : %2d ]\n", resources[ResGeode])
}
type Resource int
const (
ResOre = iota
ResClay
ResObsidian
ResGeode
ResError
)
type Robot struct {
tp Resource
}
type Cost struct {
res Resource
count int
}
type Blueprint struct {
costs map[Resource][]Cost
}
func (b Blueprint) CanBuild(tp Resource, resources map[Resource]int) bool {
cost := b.costs[tp]
for _, c := range cost {
if resources[c.res] < c.count {
return false
}
}
return true
}
func (b Blueprint) String() string {
ret := fmt.Sprintf("Blueprint contains %d Recipes.\n", len(b.costs))
for _, tp := range []Resource{ResOre, ResClay, ResObsidian, ResGeode} {
if v, ok := b.costs[tp]; ok {
ret = ret + fmt.Sprintf("Each %s robot costs %d %s", tp.String(), v[0].count, v[0].res.String())
if len(v) > 1 {
ret = ret + fmt.Sprintf(" and %d %s", v[1].count, v[1].res.String())
}
ret = ret + ". "
}
}
return ret
}
func ParseBlueprints(inp []string) []Blueprint {
var ret []Blueprint
for i := range inp {
costs := make(map[Resource][]Cost)
wrk := strings.Split(inp[i], ": ")[1]
botReqs := strings.Split(wrk, ".")
for j := range botReqs {
if len(botReqs[j]) > 0 {
fields := strings.Fields(botReqs[j])
bot := ResourceFromString(fields[1])
var req []Cost
req = append(req, Cost{
res: ResourceFromString(fields[5]),
count: h.Atoi(fields[4]),
})
if len(fields) > 6 {
req = append(req, Cost{
res: ResourceFromString(fields[8]),
count: h.Atoi(fields[7]),
})
}
costs[bot] = req
}
}
ret = append(ret, Blueprint{costs: costs})
}
return ret
}
func ResourceFromString(s string) Resource {
switch s {
case "ore":
return ResOre
case "clay":
return ResClay
case "obsidian":
return ResObsidian
case "geode":
return ResGeode
}
return ResError
}
func (r Resource) String() string {
switch r {
case ResOre:
return "ore"
case ResClay:
return "clay"
case ResObsidian:
return "obsidian"
case ResGeode:
return "geode"
}
return "unknown"
}