2017 Day 07 Complete
This commit is contained in:
parent
aa678bf4ff
commit
287c764399
189
2017/day07/day07.go
Normal file
189
2017/day07/day07.go
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
Name string
|
||||||
|
Parent string
|
||||||
|
Children []string
|
||||||
|
Num int
|
||||||
|
}
|
||||||
|
|
||||||
|
// A list of all nodes we've added
|
||||||
|
var track map[string]*Node
|
||||||
|
var root *Node
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
track = make(map[string]*Node)
|
||||||
|
inp := StdinToStrings()
|
||||||
|
totalWeight := 0
|
||||||
|
for i := range inp {
|
||||||
|
n := parseNode(inp[i])
|
||||||
|
totalWeight += n.Num
|
||||||
|
updateNodeInTrack(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("=== Results ===")
|
||||||
|
n := findRoot()
|
||||||
|
fmt.Println("Root Node: " + n.Name)
|
||||||
|
fmt.Println("Total Weight:", totalWeight, "\n")
|
||||||
|
|
||||||
|
imb, _ := findImbalance(n.Name)
|
||||||
|
imbChain := []string{n.Name, imb}
|
||||||
|
fmt.Println("")
|
||||||
|
for imb != "" {
|
||||||
|
fmt.Println("Imbalance on", imb)
|
||||||
|
imb, _ = findImbalance(imb)
|
||||||
|
fmt.Println("")
|
||||||
|
if imb != "" {
|
||||||
|
imbChain = append(imbChain, imb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(imbChain) > 2 {
|
||||||
|
// imbChain[len(imbChain)-3] is the parent
|
||||||
|
parent := imbChain[len(imbChain)-2]
|
||||||
|
// imbChain[len(imbChain)-2] should be the one that needs balancing
|
||||||
|
target := imbChain[len(imbChain)-1]
|
||||||
|
fmt.Println("Balance At:", target)
|
||||||
|
_, propWeight := findImbalance(parent)
|
||||||
|
|
||||||
|
currWeight := getWeight(target)
|
||||||
|
|
||||||
|
fmt.Println("\nAdjust weight of", target, "to:", (track[target].Num + (propWeight - currWeight)))
|
||||||
|
} else {
|
||||||
|
fmt.Println("Couldn't find an imbalance")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// findImbalance returns the wrongly balanced node name
|
||||||
|
// along with the weight that it _should_ be
|
||||||
|
func findImbalance(nm string) (string, int) {
|
||||||
|
fmt.Println(nm, ">>")
|
||||||
|
weightTracker := make(map[int]int)
|
||||||
|
chldWeights := getChildWeights(nm)
|
||||||
|
for k, v := range chldWeights {
|
||||||
|
fmt.Println(" ", k, " (", track[k].Num, ") :", v)
|
||||||
|
weightTracker[v]++
|
||||||
|
}
|
||||||
|
// Now find the different one
|
||||||
|
var properWeight int
|
||||||
|
var wrongNode string
|
||||||
|
for k, v := range weightTracker {
|
||||||
|
if v == 1 {
|
||||||
|
for chK, chV := range chldWeights {
|
||||||
|
if chV == k {
|
||||||
|
wrongNode = chK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
properWeight = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wrongNode, properWeight
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChildWeights(nm string) map[string]int {
|
||||||
|
ret := make(map[string]int)
|
||||||
|
for k := range track {
|
||||||
|
if strings.HasSuffix(getLineage(k), nm+" < "+k) {
|
||||||
|
ret[k] = getWeight(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func getWeight(nm string) int {
|
||||||
|
var weight int
|
||||||
|
for i := range track {
|
||||||
|
if strings.Contains(getLineage(i), nm+" <") {
|
||||||
|
weight += track[i].Num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return weight + track[nm].Num
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLineage(nm string) string {
|
||||||
|
ret := ""
|
||||||
|
if i, ok := track[nm]; ok {
|
||||||
|
ret = getLineage(i.Parent) + " < " + nm
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func findRoot() *Node {
|
||||||
|
for i := range track {
|
||||||
|
if track[i].Parent == "" {
|
||||||
|
return track[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateNodeInTrack(n *Node) *Node {
|
||||||
|
if _, ok := track[n.Name]; !ok {
|
||||||
|
// We need to add it
|
||||||
|
track[n.Name] = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now update all child nodes already on the track with this as their parent
|
||||||
|
for j := range n.Children {
|
||||||
|
updateNodeInTrack(&Node{Name: n.Children[j], Parent: n.Name})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now update the other values, if we've got 'em
|
||||||
|
if n.Num > 0 {
|
||||||
|
track[n.Name].Num = n.Num
|
||||||
|
}
|
||||||
|
if n.Parent != "" {
|
||||||
|
track[n.Name].Parent = n.Parent
|
||||||
|
}
|
||||||
|
return track[n.Name]
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseNode(inp string) *Node {
|
||||||
|
n := new(Node)
|
||||||
|
pts := strings.Split(inp, " ")
|
||||||
|
for i := range pts {
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
n.Name = pts[i]
|
||||||
|
case 1:
|
||||||
|
n.Num = Atoi(pts[i][1 : len(pts[i])-1])
|
||||||
|
case 2: // The arrow
|
||||||
|
continue
|
||||||
|
default: // All children
|
||||||
|
childName := pts[i]
|
||||||
|
if strings.HasSuffix(childName, ",") {
|
||||||
|
childName = childName[:len(childName)-1]
|
||||||
|
}
|
||||||
|
n.Children = append(n.Children, childName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func StdinToStrings() []string {
|
||||||
|
var input []string
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
for scanner.Scan() {
|
||||||
|
input = append(input, scanner.Text())
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
|
||||||
|
func Atoi(i string) int {
|
||||||
|
var ret int
|
||||||
|
var err error
|
||||||
|
if ret, err = strconv.Atoi(i); err != nil {
|
||||||
|
log.Fatal("Invalid Atoi")
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
1281
2017/day07/input
Normal file
1281
2017/day07/input
Normal file
File diff suppressed because it is too large
Load Diff
128
2017/day07/problem
Normal file
128
2017/day07/problem
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
Advent of Code
|
||||||
|
|
||||||
|
--- Day 7: Recursive Circus ---
|
||||||
|
|
||||||
|
Wandering further through the circuits of the computer, you come upon a tower
|
||||||
|
of programs that have gotten themselves into a bit of trouble. A recursive
|
||||||
|
algorithm has gotten out of hand, and now they're balanced precariously in a
|
||||||
|
large tower.
|
||||||
|
|
||||||
|
One program at the bottom supports the entire tower. It's holding a large
|
||||||
|
disc, and on the disc are balanced several more sub-towers. At the bottom of
|
||||||
|
these sub-towers, standing on the bottom disc, are other programs, each
|
||||||
|
holding their own disc, and so on. At the very tops of these
|
||||||
|
sub-sub-sub-...-towers, many programs stand simply keeping the disc below
|
||||||
|
them balanced but with no disc of their own.
|
||||||
|
|
||||||
|
You offer to help, but first you need to understand the structure of these
|
||||||
|
towers. You ask each program to yell out their name, their weight, and (if
|
||||||
|
they're holding a disc) the names of the programs immediately above them
|
||||||
|
balancing on that disc. You write this information down (your puzzle input).
|
||||||
|
Unfortunately, in their panic, they don't do this in an orderly fashion; by
|
||||||
|
the time you're done, you're not sure which program gave which information.
|
||||||
|
|
||||||
|
For example, if your list is the following:
|
||||||
|
|
||||||
|
pbga (66)
|
||||||
|
xhth (57)
|
||||||
|
ebii (61)
|
||||||
|
havc (66)
|
||||||
|
ktlj (57)
|
||||||
|
fwft (72) -> ktlj, cntj, xhth
|
||||||
|
qoyq (66)
|
||||||
|
padx (45) -> pbga, havc, qoyq
|
||||||
|
tknk (41) -> ugml, padx, fwft
|
||||||
|
jptl (61)
|
||||||
|
ugml (68) -> gyxo, ebii, jptl
|
||||||
|
gyxo (61)
|
||||||
|
cntj (57)
|
||||||
|
|
||||||
|
...then you would be able to recreate the structure of the towers that looks
|
||||||
|
like this:
|
||||||
|
|
||||||
|
gyxo
|
||||||
|
/
|
||||||
|
ugml - ebii
|
||||||
|
/ \
|
||||||
|
| jptl
|
||||||
|
|
|
||||||
|
| pbga
|
||||||
|
/ /
|
||||||
|
tknk --- padx - havc
|
||||||
|
\ \
|
||||||
|
| qoyq
|
||||||
|
|
|
||||||
|
| ktlj
|
||||||
|
\ /
|
||||||
|
fwft - cntj
|
||||||
|
\
|
||||||
|
xhth
|
||||||
|
|
||||||
|
In this example, tknk is at the bottom of the tower (the bottom program), and
|
||||||
|
is holding up ugml, padx, and fwft. Those programs are, in turn, holding up
|
||||||
|
other programs; in this example, none of those programs are holding up any
|
||||||
|
other programs, and are all the tops of their own towers. (The actual tower
|
||||||
|
balancing in front of you is much larger.)
|
||||||
|
|
||||||
|
Before you're ready to help them, you need to make sure your information is
|
||||||
|
correct. What is the name of the bottom program?
|
||||||
|
|
||||||
|
Your puzzle answer was ___________.
|
||||||
|
|
||||||
|
--- Part Two ---
|
||||||
|
|
||||||
|
The programs explain the situation: they can't get down. Rather, they could
|
||||||
|
get down, if they weren't expending all of their energy trying to keep the
|
||||||
|
tower balanced. Apparently, one program has the wrong weight, and until it's
|
||||||
|
fixed, they're stuck here.
|
||||||
|
|
||||||
|
For any program holding a disc, each program standing on that disc forms a
|
||||||
|
sub-tower. Each of those sub-towers are supposed to be the same weight, or
|
||||||
|
the disc itself isn't balanced. The weight of a tower is the sum of the
|
||||||
|
weights of the programs in that tower.
|
||||||
|
|
||||||
|
In the example above, this means that for ugml's disc to be balanced, gyxo,
|
||||||
|
ebii, and jptl must all have the same weight, and they do: 61.
|
||||||
|
|
||||||
|
However, for tknk to be balanced, each of the programs standing on its disc
|
||||||
|
and all programs above it must each match. This means that the following sums
|
||||||
|
must all be the same:
|
||||||
|
|
||||||
|
* ugml + (gyxo + ebii + jptl) = 68 + (61 + 61 + 61) = 251
|
||||||
|
* padx + (pbga + havc + qoyq) = 45 + (66 + 66 + 66) = 243
|
||||||
|
* fwft + (ktlj + cntj + xhth) = 72 + (57 + 57 + 57) = 243
|
||||||
|
|
||||||
|
As you can see, tknk's disc is unbalanced: ugml's stack is heavier than the
|
||||||
|
other two. Even though the nodes above ugml are balanced, ugml itself is too
|
||||||
|
heavy: it needs to be 8 units lighter for its stack to weigh 243 and keep the
|
||||||
|
towers balanced. If this change were made, its weight would be 60.
|
||||||
|
|
||||||
|
Given that exactly one program is the wrong weight, what would its weight
|
||||||
|
need to be to balance the entire tower?
|
||||||
|
|
||||||
|
Your puzzle answer was ______.
|
||||||
|
|
||||||
|
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||||
|
|
||||||
|
At this point, you should return to your advent calendar and try another
|
||||||
|
puzzle.
|
||||||
|
|
||||||
|
If you still want to see it, you can get your puzzle input.
|
||||||
|
|
||||||
|
References
|
||||||
|
|
||||||
|
Visible links
|
||||||
|
. http://adventofcode.com/
|
||||||
|
. http://adventofcode.com/2017/about
|
||||||
|
. http://adventofcode.com/2017/support
|
||||||
|
. http://adventofcode.com/2017/events
|
||||||
|
. http://adventofcode.com/2017/settings
|
||||||
|
. http://adventofcode.com/2017/auth/logout
|
||||||
|
. http://adventofcode.com/2017
|
||||||
|
. http://adventofcode.com/2017
|
||||||
|
. http://adventofcode.com/2017/leaderboard
|
||||||
|
. http://adventofcode.com/2017/stats
|
||||||
|
. http://adventofcode.com/2017/sponsors
|
||||||
|
. http://adventofcode.com/2017/sponsors
|
||||||
|
. http://adventofcode.com/2017
|
||||||
|
. http://adventofcode.com/2017/day/7/input
|
Loading…
Reference in New Issue
Block a user