Advertisement
Guest User

AOD Day 24

a guest
Dec 24th, 2024
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 5.09 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "bufio"
  5.     "flag"
  6.     "fmt"
  7.     "log"
  8.     "os"
  9.     "regexp"
  10.     "slices"
  11.     "strconv"
  12.     "strings"
  13.  
  14.     "github.com/emirpasic/gods/sets/hashset"
  15.     "golang.org/x/exp/rand"
  16. )
  17.  
  18. type Gate struct {
  19.     inp  []string
  20.     gate string
  21. }
  22.  
  23. type Machine struct {
  24.     outToGate map[string]Gate
  25.     wireVal   map[string]int
  26. }
  27.  
  28. func readFile(filename string) (Machine, error) {
  29.     file, err := os.Open(filename)
  30.  
  31.     if err != nil {
  32.         return Machine{}, err
  33.     }
  34.  
  35.     defer file.Close()
  36.  
  37.     scanner := bufio.NewScanner(file)
  38.  
  39.     inpPattern := `(\w{3}): (\d)`
  40.     inpRe := regexp.MustCompile(inpPattern)
  41.     wPattern := `(\w{3}) (\w+) (\w{3}) -> (\w{3})`
  42.     wRe := regexp.MustCompile(wPattern)
  43.  
  44.     wireVal := map[string]int{}
  45.     outToGate := map[string]Gate{}
  46.  
  47.     for scanner.Scan() {
  48.         line := scanner.Text()
  49.  
  50.         if matches := inpRe.FindStringSubmatch(line); len(matches) > 0 {
  51.             v, _ := strconv.ParseInt(matches[2], 10, 64)
  52.             wireVal[matches[1]] = int(v)
  53.         } else if matches := wRe.FindStringSubmatch(line); len(matches) > 0 {
  54.             v, e := outToGate[matches[4]]
  55.  
  56.             if e {
  57.                 log.Fatalf("Expected unique gate for output %v but alreadd found gate %v\n", matches[4], v)
  58.             }
  59.  
  60.             outToGate[matches[4]] = Gate{
  61.                 inp:  []string{matches[1], matches[3]},
  62.                 gate: matches[2],
  63.             }
  64.         }
  65.     }
  66.  
  67.     return Machine{outToGate, wireVal}, nil
  68. }
  69.  
  70. func getWireVal(wire string, mac *Machine, cache *map[string]int, depth int) (int, error) {
  71.     val, exists := (*cache)[wire]
  72.  
  73.     if exists {
  74.         return val, nil
  75.     }
  76.  
  77.     if depth > 200 {
  78.         return -1, fmt.Errorf("Probably a loop here, exist\n")
  79.     }
  80.  
  81.     gate, exists := (*mac).outToGate[wire]
  82.  
  83.     if !exists {
  84.         return -1, fmt.Errorf("Cannot get value for wire %v\n", wire)
  85.     }
  86.  
  87.     v1, _ := getWireVal(gate.inp[0], mac, cache, depth+1)
  88.     v2, _ := getWireVal(gate.inp[1], mac, cache, depth+1)
  89.  
  90.     if gate.gate == "AND" {
  91.         val = v1 & v2
  92.     } else if gate.gate == "OR" {
  93.         val = v1 | v2
  94.     } else if gate.gate == "XOR" {
  95.         val = v1 ^ v2
  96.     }
  97.  
  98.     (*cache)[wire] = val
  99.  
  100.     return val, nil
  101. }
  102.  
  103. func part1(mac Machine) int {
  104.     res := 0
  105.  
  106.     cache := map[string]int{}
  107.  
  108.     for k, v := range mac.wireVal {
  109.         cache[k] = v
  110.     }
  111.  
  112.     for k, _ := range mac.outToGate {
  113.         if k[0] != 'z' {
  114.             continue
  115.         }
  116.  
  117.         val, err := getWireVal(k, &mac, &cache, 0)
  118.  
  119.         if err != nil {
  120.             log.Fatalf("Did not expect error\n")
  121.         }
  122.  
  123.         if val == 0 {
  124.             continue
  125.         }
  126.  
  127.         i, _ := strconv.ParseInt(k[1:], 10, 64)
  128.  
  129.         res += 1 << int(i)
  130.     }
  131.  
  132.     return res
  133. }
  134.  
  135. func getStr(c string, i int) string {
  136.     if i < 10 {
  137.         return c + "0" + strconv.Itoa(i)
  138.     }
  139.  
  140.     return c + strconv.Itoa(i)
  141. }
  142.  
  143. func getFirstWrong(mac Machine) (int, map[string]int, error) {
  144.     cRes := map[string]int{}
  145.     bRes := 100
  146.  
  147.     for i := 0; i <= 10; i++ {
  148.         cache := map[string]int{}
  149.  
  150.         carry := 0
  151.         for b := 0; b <= 44; b++ {
  152.             xStr := getStr("x", b)
  153.             yStr := getStr("y", b)
  154.             zStr := getStr("z", b)
  155.  
  156.             cache[xStr] = rand.Intn(2)
  157.             cache[yStr] = rand.Intn(2)
  158.  
  159.             x := cache[xStr]
  160.             y := cache[yStr]
  161.  
  162.             zCalc, err := getWireVal(zStr, &mac, &cache, 0)
  163.  
  164.             if err != nil {
  165.                 return -1, nil, err
  166.             }
  167.  
  168.             zExp := (x + y + carry) % 2
  169.             carry = (x + y + carry) / 2
  170.  
  171.             if zCalc != zExp && b < bRes {
  172.                 bRes = b
  173.                 cRes = cache
  174.                 break
  175.             }
  176.         }
  177.     }
  178.  
  179.     if bRes == 100 {
  180.         bRes = -1
  181.     }
  182.  
  183.     return bRes, cRes, nil
  184. }
  185.  
  186. func checkMachine(mac *Machine) bool {
  187.     bErr, _, err := getFirstWrong(*mac)
  188.  
  189.     return bErr == -1 && err == nil
  190. }
  191.  
  192. func backTr(b int, mac *Machine, swaps *hashset.Set, ans *hashset.Set) {
  193.     if ans.Size() > 0 {
  194.         return
  195.     }
  196.     // fmt.Printf("Checking %v with swaps\n%v\n", b, swaps)
  197.     if swaps.Size() == 8 {
  198.         if checkMachine(mac) {
  199.             // fmt.Printf("Found machine %v\n", swaps)
  200.  
  201.             for _, v := range swaps.Values() {
  202.                 ans.Add(v)
  203.             }
  204.         }
  205.  
  206.         return
  207.     }
  208.  
  209.     bErr, gts, err := getFirstWrong(*mac)
  210.  
  211.     if bErr < b || err != nil {
  212.         // fmt.Printf("Returning since found error\n")
  213.         return
  214.     }
  215.  
  216.     gts2 := map[string]Gate{}
  217.  
  218.     for k, v := range (*mac).outToGate {
  219.         gts2[k] = v
  220.     }
  221.  
  222.     for s1 := range gts {
  223.         if swaps.Contains(s1) || s1[0] == 'x' || s1[0] == 'y' {
  224.             continue
  225.         }
  226.  
  227.         for s2 := range gts2 {
  228.             if s2 == s1 || swaps.Contains(s2) || s2[0] == 'x' || s2[0] == 'y' {
  229.                 continue
  230.             }
  231.  
  232.             temp := (*mac).outToGate[s1]
  233.             (*mac).outToGate[s1] = (*mac).outToGate[s2]
  234.             (*mac).outToGate[s2] = temp
  235.  
  236.             swaps.Add(s1)
  237.             swaps.Add(s2)
  238.  
  239.             backTr(bErr+1, mac, swaps, ans)
  240.  
  241.             swaps.Remove(s2)
  242.             swaps.Remove(s1)
  243.  
  244.             temp = (*mac).outToGate[s1]
  245.             (*mac).outToGate[s1] = (*mac).outToGate[s2]
  246.             (*mac).outToGate[s2] = temp
  247.         }
  248.     }
  249. }
  250.  
  251. func part2(mac Machine) string {
  252.     swaps := hashset.New()
  253.     ans := hashset.New()
  254.  
  255.     backTr(0, &mac, swaps, ans)
  256.  
  257.     wires := []string{}
  258.  
  259.     for _, wire := range ans.Values() {
  260.         wires = append(wires, wire.(string))
  261.     }
  262.  
  263.     slices.SortFunc(wires, func(a, b string) int {
  264.         return strings.Compare(a, b)
  265.     })
  266.  
  267.     return strings.Join(wires, ",")
  268. }
  269.  
  270. func main() {
  271.     filename := flag.String("file", "24.txt", "file containing input")
  272.  
  273.     flag.Parse()
  274.  
  275.     mac, _ := readFile(*filename)
  276.  
  277.     a1 := part1(mac)
  278.     a2 := part2(mac)
  279.  
  280.     fmt.Printf("Part 1\n%v\nPart 2\n%v\n", a1, a2)
  281. }
  282.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement