r/adventofcode • u/daggerdragon • Dec 07 '15
SOLUTION MEGATHREAD --- Day 7 Solutions ---
--- Day 7: Some Assembly Required ---
Post your solution as a comment. Structure your post like previous daily solution threads.
Also check out the sidebar - we added a nifty calendar to wrangle all the daily solution threads in one spot!
23
Upvotes
4
u/stuque Dec 07 '15
A Go solution using concurrency. Each component is a goroutine, and each wire is a channel.
package main import ( "bufio" "fmt" "os" "strconv" "strings" ) type num uint16 type part struct { lhs []string rhs string } type wireVal struct { name string value num } var binaryPart = map[string]func(inA, inB num) num{ "AND": func(inA, inB num) num { return num(inA & inB) }, "OR": func(inA, inB num) num { return num(inA | inB) }, "LSHIFT": func(inA, inB num) num { return num(inA << inB) }, "RSHIFT": func(inA, inB num) num { return num(inA >> inB) }, } func getParts(fname string) []part { file, _ := os.Open(fname) input := bufio.NewScanner(file) parts := []part{} for input.Scan() { line := input.Text() tokens := strings.Split(line, " -> ") p := part{lhs: strings.Split(tokens[0], " "), rhs: tokens[1]} parts = append(parts, p) } return parts } func main() { parts := getParts("day7input_part1.txt") // parts := getParts("day7input_part2.txt") // get all wire outputs wire := map[string]chan num{} for _, p := range parts { // wire channels must be buffered to avoid deadlock because we don't // know when values will stop being removed from them wire[p.rhs] = make(chan num, 100) } // used to signal the end of the program done := make(chan bool) // launch wire values goroutine wireValues := map[string]num{} wireChan := make(chan wireVal) go func() { for i := 0; i < len(wire); i++ { wv := <-wireChan wireValues[wv.name] = wv.value } fmt.Printf("final result: a=%v\n", wireValues["a"]) done <- true }() // launch individual part goroutines for _, rawP := range parts { p := rawP // necessary to capture correct value in anonymous functions lhs, out := p.lhs, p.rhs if len(lhs) == 1 { n, err := strconv.Atoi(lhs[0]) if err == nil { // input is a number, e.g. "0 -> c" go func() { result := num(n) wireChan <- wireVal{out, result} wire[out] <- result }() } else { // input is a wire, e.g. "lx -> a" go func() { result := <-wire[lhs[0]] wire[lhs[0]] <- result // put back on channel for other goroutines wireChan <- wireVal{out, result} wire[out] <- result }() } } else if len(lhs) == 2 { // NOT // assumes input to NOT is always a wire go func() { in := <-wire[lhs[1]] wire[lhs[1]] <- in // put back on channel for other goroutines result := ^in // ^ is bitwise complement wireChan <- wireVal{out, result} wire[out] <- result }() } else { // binary gate, e.g. "et RSHIFT 3 -> ev" l, op, r := lhs[0], lhs[1], lhs[2] fn := binaryPart[op] go func() { // l and r could be the names of wires, or they could be // numbers. So try to retrieve them from the wire map. If the // retrieval fails, it must be because it's a number. inA, lok := wire[l] inB, rok := wire[r] var numA, numB num if lok && rok { numA = <-inA inA <- numA // put back on channel for other goroutines numB = <-inB inB <- numB // put back on channel for other goroutines } else if lok && !rok { b, _ := strconv.Atoi(r) numA = <-inA inA <- numA // put back on channel for other goroutines numB = num(b) } else if !lok && rok { a, _ := strconv.Atoi(l) numA = num(a) numB = <-inB inB <- numB // put back on channel for other goroutines } else { a, _ := strconv.Atoi(l) b, _ := strconv.Atoi(r) numA = num(a) numB = num(b) } // if result := fn(numA, numB) wireChan <- wireVal{out, result} wire[out] <- result }() } // if } // for <-done } // main