First (unsuccessful) attempt at day 7.1.
This commit is contained in:
parent
0388b57112
commit
f6ea56d266
29
2018/day07-1.go
Normal file
29
2018/day07-1.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"internal/tree"
|
||||||
|
"internal/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
data := util.ReadInput()
|
||||||
|
|
||||||
|
// Build a tree of dependencies.
|
||||||
|
root := tree.BuildDependencyTree(data)
|
||||||
|
|
||||||
|
// Walk the tree and determine the correct ordering.
|
||||||
|
order := tree.FindOrder(root)
|
||||||
|
|
||||||
|
output := strings.Builder{}
|
||||||
|
for _, node := range order {
|
||||||
|
if node.Name == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
output.WriteRune(node.Name)
|
||||||
|
}
|
||||||
|
fmt.Println(output.String())
|
||||||
|
}
|
44
2018/internal/tree/breadthfirst.go
Normal file
44
2018/internal/tree/breadthfirst.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// BreadthFirstOrder and its companion functions ended up not giving the
|
||||||
|
// right solution, but I'm leaving them here as a useful generic tree
|
||||||
|
// algorithm.
|
||||||
|
package tree
|
||||||
|
|
||||||
|
func BreadthFirstOrder(root *Node) []*Node {
|
||||||
|
seen := make(map[rune]bool)
|
||||||
|
return breadthFirstOrderR(root, seen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findTreeRoot(depMap map[rune]*Node) *Node {
|
||||||
|
for _, node := range depMap {
|
||||||
|
if len(node.Parents) == 0 {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func breadthFirstOrderR(node *Node, seen map[rune]bool) []*Node {
|
||||||
|
order := []*Node{}
|
||||||
|
|
||||||
|
// handle root
|
||||||
|
if len(node.Parents) == 0 {
|
||||||
|
order = append(order, node)
|
||||||
|
seen[node.Name] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// add children we haven't seen before
|
||||||
|
for _, child := range node.Children {
|
||||||
|
if _, ok := seen[child.Name]; !ok {
|
||||||
|
order = append(order, child)
|
||||||
|
seen[child.Name] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
for _, child := range node.Children {
|
||||||
|
order = append(order, breadthFirstOrderR(child, seen)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return order
|
||||||
|
}
|
33
2018/internal/tree/debug.go
Normal file
33
2018/internal/tree/debug.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package tree
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DebugPrintTree(root *Node) {
|
||||||
|
debugPrintTreeR(root, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func debugPrintTreeR(node *Node, level int) {
|
||||||
|
for i := 0; i < level; i++ {
|
||||||
|
fmt.Printf(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugPrintNode(node)
|
||||||
|
|
||||||
|
for _, child := range node.Children {
|
||||||
|
debugPrintTreeR(child, level+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DebugPrintNode(node *Node) {
|
||||||
|
fmt.Printf("%c @ %p. Children: ", node.Name, node)
|
||||||
|
for _, child := range node.Children {
|
||||||
|
fmt.Printf("%c ", child.Name)
|
||||||
|
}
|
||||||
|
fmt.Printf("Parents: ")
|
||||||
|
for _, parent := range node.Parents {
|
||||||
|
fmt.Printf("%c ", parent.Name)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
51
2018/internal/tree/findorder.go
Normal file
51
2018/internal/tree/findorder.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package tree
|
||||||
|
|
||||||
|
import "fmt" // debug
|
||||||
|
|
||||||
|
// FindOrder determines the correct order according to these rules:
|
||||||
|
// 1. A node cannot come before all of its parents have been included.
|
||||||
|
// 2. At any given time, the lowest-lettered step must be executed.
|
||||||
|
func FindOrder(root *Node) []*Node {
|
||||||
|
seen := make(map[rune]bool)
|
||||||
|
return findOrderR(root, seen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findOrderR(node *Node, seen map[rune]bool) []*Node {
|
||||||
|
order := []*Node{}
|
||||||
|
|
||||||
|
// debug
|
||||||
|
fmt.Printf("In node: %c | Children: ", node.Name)
|
||||||
|
for _, child := range node.Children {
|
||||||
|
fmt.Printf("%c ", child.Name)
|
||||||
|
}
|
||||||
|
fmt.Printf("| Parents: ")
|
||||||
|
for _, parent := range node.Parents {
|
||||||
|
fmt.Printf("%c ", parent.Name)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
// end debug
|
||||||
|
|
||||||
|
// add the node, but only if all its parents have been seen
|
||||||
|
if len(node.Parents) == 0 {
|
||||||
|
seen[node.Name] = true
|
||||||
|
} else {
|
||||||
|
for _, parent := range node.Parents {
|
||||||
|
if _, ok := seen[parent.Name]; !ok {
|
||||||
|
return order
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := seen[node.Name]; !ok {
|
||||||
|
order = append(order, node)
|
||||||
|
fmt.Printf("Added node: %c\n", node.Name)
|
||||||
|
seen[node.Name] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
for _, child := range node.Children {
|
||||||
|
order = append(order, findOrderR(child, seen)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return order
|
||||||
|
}
|
67
2018/internal/tree/tree.go
Normal file
67
2018/internal/tree/tree.go
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
package tree
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
Name rune
|
||||||
|
Parents []*Node
|
||||||
|
Children []*Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildDependencyTree parses the input and returns the root node.
|
||||||
|
func BuildDependencyTree(data []string) *Node {
|
||||||
|
depMap := make(map[rune]*Node)
|
||||||
|
parentRegex := regexp.MustCompile("Step ([A-Z]) must")
|
||||||
|
childRegex := regexp.MustCompile("step ([A-Z]) can begin")
|
||||||
|
|
||||||
|
for _, line := range data {
|
||||||
|
parent := rune(parentRegex.FindSubmatch([]byte(line))[1][0])
|
||||||
|
child := rune(childRegex.FindSubmatch([]byte(line))[1][0])
|
||||||
|
|
||||||
|
// Create the nodes if they don't exist
|
||||||
|
if depMap[parent] == nil {
|
||||||
|
depMap[parent] = &Node{Name: parent}
|
||||||
|
}
|
||||||
|
if depMap[child] == nil {
|
||||||
|
depMap[child] = &Node{Name: child}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get each node and add the dependency info.
|
||||||
|
pNode := depMap[parent]
|
||||||
|
cNode := depMap[child]
|
||||||
|
|
||||||
|
pNode.Children = append(pNode.Children, cNode)
|
||||||
|
cNode.Parents = append(cNode.Parents, pNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort the children in each node
|
||||||
|
for _, node := range depMap {
|
||||||
|
sortChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return BuildTreeRoot(depMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortChildren(node *Node) {
|
||||||
|
children := node.Children
|
||||||
|
sort.Slice(children[:], func(i, j int) bool {
|
||||||
|
return children[i].Name < children[j].Name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildTreeRoot(depMap map[rune]*Node) *Node {
|
||||||
|
root := &Node{Name: 0}
|
||||||
|
|
||||||
|
for _, node := range depMap {
|
||||||
|
if len(node.Parents) == 0 {
|
||||||
|
root.Children = append(root.Children, node)
|
||||||
|
node.Parents = append(node.Parents, root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortChildren(root)
|
||||||
|
return root
|
||||||
|
}
|
14
2018/internal/util/strings.go
Normal file
14
2018/internal/util/strings.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
func ReverseString(s string) string {
|
||||||
|
runes := []rune(s)
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
j := len(runes) - 1
|
||||||
|
for i < j {
|
||||||
|
runes[i], runes[j] = runes[j], runes[i]
|
||||||
|
i++
|
||||||
|
j--
|
||||||
|
}
|
||||||
|
return string(runes)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user