mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-06-03 02:38:28 +02:00
164 lines
3.7 KiB
Go
164 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"math"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/alexchao26/advent-of-code-go/mathy"
|
|
"github.com/alexchao26/advent-of-code-go/util"
|
|
)
|
|
|
|
func main() {
|
|
var part int
|
|
flag.IntVar(&part, "part", 1, "part 1 or 2")
|
|
flag.Parse()
|
|
fmt.Println("Running part", part)
|
|
|
|
if part == 1 {
|
|
ans := part1(util.ReadFile("./input.txt"))
|
|
fmt.Println("Output:", ans)
|
|
} else {
|
|
ans := part2(util.ReadFile("./input.txt"), 5, 60)
|
|
fmt.Println("Output:", ans)
|
|
}
|
|
}
|
|
|
|
func part1(input string) string {
|
|
graph := parseInputs(input)
|
|
|
|
completedSteps := make(map[string]bool)
|
|
var stepsOrder string
|
|
|
|
for len(completedSteps) != len(graph) {
|
|
var readySteps []string
|
|
|
|
for name, prereqs := range graph {
|
|
if completedSteps[name] {
|
|
continue
|
|
}
|
|
|
|
prereqsReady := true
|
|
for _, v := range prereqs {
|
|
if !completedSteps[v] {
|
|
prereqsReady = false
|
|
break
|
|
}
|
|
}
|
|
if prereqsReady {
|
|
readySteps = append(readySteps, name)
|
|
}
|
|
}
|
|
|
|
// run the lowest ready step
|
|
sort.Strings(readySteps)
|
|
completedSteps[readySteps[0]] = true
|
|
stepsOrder += readySteps[0]
|
|
}
|
|
|
|
return stepsOrder
|
|
}
|
|
|
|
func part2(input string, workers, fudgeTime int) int {
|
|
graph := parseInputs(input)
|
|
|
|
stepsCompletedAt := make(map[string]int, len(graph))
|
|
|
|
workerLogs := make([][]string, workers)
|
|
for i := 0; i < workers; i++ {
|
|
workerLogs[i] = []string{}
|
|
}
|
|
|
|
for time := 0; len(stepsCompletedAt) < len(graph); time++ {
|
|
availableWorkers := []int{}
|
|
for i, w := range workerLogs {
|
|
if time >= len(w) {
|
|
availableWorkers = append(availableWorkers, i)
|
|
}
|
|
}
|
|
|
|
if len(availableWorkers) > 0 {
|
|
// get ready steps
|
|
var readySteps []string
|
|
|
|
for name, prereqs := range graph {
|
|
if stepsCompletedAt[name] != 0 {
|
|
continue
|
|
}
|
|
|
|
prereqsCompletionTimes := make([]int, len(prereqs))
|
|
// might want more data here
|
|
for _, pre := range prereqs {
|
|
if stepsCompletedAt[pre] == 0 {
|
|
prereqsCompletionTimes = append(prereqsCompletionTimes, math.MaxInt32)
|
|
} else {
|
|
prereqsCompletionTimes = append(prereqsCompletionTimes, stepsCompletedAt[pre]+1)
|
|
}
|
|
}
|
|
|
|
if len(prereqsCompletionTimes) == 0 {
|
|
readySteps = append(readySteps, name)
|
|
} else {
|
|
earliestScheduleTime := mathy.MaxInt(prereqsCompletionTimes...)
|
|
if earliestScheduleTime <= time {
|
|
readySteps = append(readySteps, name)
|
|
}
|
|
}
|
|
}
|
|
|
|
// schedule steps that are ready
|
|
sort.Strings(readySteps)
|
|
|
|
for _, step := range readySteps {
|
|
if len(availableWorkers) > 0 {
|
|
for i := timeForStep(step, fudgeTime); i > 0; i-- {
|
|
workerLogs[availableWorkers[0]] = append(workerLogs[availableWorkers[0]], step)
|
|
}
|
|
// set time this step is done at
|
|
stepsCompletedAt[step] = len(workerLogs[availableWorkers[0]])
|
|
// remove worker from available "pool"
|
|
availableWorkers = availableWorkers[1:]
|
|
}
|
|
}
|
|
}
|
|
|
|
// fill out empty time elements in any workerLogs
|
|
for i := range workerLogs {
|
|
for len(workerLogs[i]) < time {
|
|
workerLogs[i] = append(workerLogs[i], "-")
|
|
}
|
|
}
|
|
}
|
|
|
|
var longestLength int
|
|
for _, w := range workerLogs {
|
|
if len(w) > longestLength {
|
|
longestLength = len(w)
|
|
}
|
|
}
|
|
return longestLength
|
|
}
|
|
|
|
func parseInputs(input string) map[string][]string {
|
|
graphValToPrereqs := make(map[string][]string)
|
|
lines := strings.Split(input, "\n")
|
|
for _, inst := range lines {
|
|
words := strings.Split(inst, " ")
|
|
if len(words) < 8 {
|
|
continue
|
|
}
|
|
graphValToPrereqs[words[7]] = append(graphValToPrereqs[words[7]], words[1])
|
|
if len(graphValToPrereqs[words[1]]) == 0 {
|
|
graphValToPrereqs[words[1]] = []string{}
|
|
}
|
|
}
|
|
return graphValToPrereqs
|
|
}
|
|
|
|
func timeForStep(char string, fudgeFactor int) int {
|
|
byteDiff := []byte(char)[0] - byte('A')
|
|
return fudgeFactor + int(byteDiff) + 1
|
|
}
|