228 lines
4.2 KiB
Go
228 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const ClearScreen = "\033[H\033[2J"
|
|
|
|
var manager *StepManager
|
|
var TotalWorkers int
|
|
|
|
func main() {
|
|
inp := StdinToStringSlice()
|
|
signTheContract(inp)
|
|
part1()
|
|
manager.resetJobs()
|
|
part2()
|
|
}
|
|
|
|
func signTheContract(inp []string) {
|
|
TotalWorkers = 5
|
|
manager = &StepManager{workers: TotalWorkers}
|
|
for _, v := range inp {
|
|
manager.addOrUpdateStep(v[36], v[5])
|
|
}
|
|
}
|
|
|
|
func part1() {
|
|
fmt.Println("= Part 1 =")
|
|
for !manager.done() {
|
|
manager.part1Act()
|
|
}
|
|
fmt.Println("")
|
|
}
|
|
|
|
func part2() {
|
|
var seconds int
|
|
realtime := true
|
|
for !manager.done() {
|
|
seconds++
|
|
manager.part2Act()
|
|
|
|
fmt.Print(ClearScreen)
|
|
fmt.Println(manager.string())
|
|
fmt.Println("Total Seconds: ", seconds)
|
|
if realtime {
|
|
time.Sleep(time.Millisecond * 125)
|
|
}
|
|
}
|
|
}
|
|
|
|
type StepManager struct {
|
|
steps []*Step
|
|
workers int
|
|
}
|
|
|
|
// In part 1, all steps complete immediately
|
|
func (m *StepManager) part1Act() {
|
|
// Find the next step that should run
|
|
var nextStep *Step
|
|
for i := range m.steps {
|
|
if !m.steps[i].done() && m.steps[i].ready() && (nextStep == nil || nextStep.id > m.steps[i].id) {
|
|
nextStep = m.steps[i]
|
|
}
|
|
}
|
|
nextStep.timeSpent = int(nextStep.id) + 5
|
|
fmt.Print(string(nextStep.id))
|
|
}
|
|
|
|
func (m *StepManager) part2Act() {
|
|
// Clear all done jobs
|
|
for i := range m.steps {
|
|
if m.steps[i].active && m.steps[i].done() {
|
|
m.steps[i].active = false
|
|
m.workers++
|
|
fmt.Println(string(m.steps[i].id))
|
|
}
|
|
}
|
|
// Find all steps that are ready for work
|
|
var waitingSteps []*Step
|
|
for i := range m.steps {
|
|
if m.steps[i].ready() && !m.steps[i].done() && !m.steps[i].active {
|
|
waitingSteps = append(waitingSteps, m.steps[i])
|
|
}
|
|
}
|
|
// If we have any available workers, get them working
|
|
for m.workers > 0 {
|
|
var nextStep *Step
|
|
for i := range waitingSteps {
|
|
if !waitingSteps[i].active && (nextStep == nil || waitingSteps[i].id < nextStep.id) {
|
|
nextStep = waitingSteps[i]
|
|
}
|
|
}
|
|
if nextStep != nil {
|
|
nextStep.active = true
|
|
m.workers--
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
// Increment all active steps
|
|
for i := range m.steps {
|
|
if m.steps[i].active {
|
|
m.steps[i].timeSpent++
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *StepManager) getStep(id byte) (*Step, error) {
|
|
for i := range m.steps {
|
|
if m.steps[i].id == id {
|
|
return m.steps[i], nil
|
|
}
|
|
}
|
|
return nil, errors.New("No step with id " + string(id) + " found.")
|
|
}
|
|
|
|
func (m *StepManager) addOrUpdateStep(id, reqId byte) {
|
|
s, err := m.getStep(id)
|
|
if err != nil {
|
|
s = &Step{id: id}
|
|
}
|
|
r, reqErr := m.getStep(reqId)
|
|
if reqErr != nil {
|
|
r = &Step{id: reqId}
|
|
m.steps = append(m.steps, r)
|
|
}
|
|
s.addRequirement(r)
|
|
if err != nil {
|
|
m.steps = append(m.steps, s)
|
|
}
|
|
}
|
|
|
|
func (m *StepManager) resetJobs() {
|
|
for i := range manager.steps {
|
|
manager.steps[i].timeSpent = 0
|
|
}
|
|
}
|
|
|
|
func (m *StepManager) string() string {
|
|
var ret string
|
|
var stepsDone int
|
|
for i := range manager.steps {
|
|
ret += (manager.steps[i].string() + "\n")
|
|
if manager.steps[i].done() {
|
|
stepsDone++
|
|
}
|
|
}
|
|
pct := 100 * (float64(stepsDone) / float64(len(manager.steps)))
|
|
|
|
filled := int(pct / 10)
|
|
progBar := strings.Repeat("\u2588", filled)
|
|
progBar += strings.Repeat(" ", (10 - filled))
|
|
ret += fmt.Sprintf("Progress: [%s] %d\n", progBar, int(pct))
|
|
ret += fmt.Sprintf("Idle Workers %d/%d", m.workers, TotalWorkers)
|
|
return ret
|
|
}
|
|
|
|
func (m *StepManager) done() bool {
|
|
for i := range m.steps {
|
|
if !m.steps[i].done() {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
type Step struct {
|
|
id byte
|
|
req []*Step
|
|
timeSpent int
|
|
active bool
|
|
}
|
|
|
|
func (s *Step) done() bool {
|
|
return s.timeSpent >= int(s.id)-4
|
|
}
|
|
|
|
func (s *Step) addRequirement(r *Step) {
|
|
for i := range s.req {
|
|
if s.req[i] == r {
|
|
return
|
|
}
|
|
}
|
|
s.req = append(s.req, r)
|
|
}
|
|
|
|
func (s *Step) ready() bool {
|
|
for i := range s.req {
|
|
if !s.req[i].done() {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (s *Step) string() string {
|
|
var ret string
|
|
if s.done() {
|
|
ret += "[✔️ ] "
|
|
} else {
|
|
ret += "[✖️ ] "
|
|
}
|
|
ret += fmt.Sprintf("%s ( %d ): [", string(s.id), s.id)
|
|
for i := range s.req {
|
|
ret += string(s.req[i].id) + " "
|
|
}
|
|
ret += "] "
|
|
if s.active {
|
|
ret += "▶️ "
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func StdinToStringSlice() []string {
|
|
var input []string
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
for scanner.Scan() {
|
|
input = append(input, scanner.Text())
|
|
}
|
|
return input
|
|
}
|