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" }