summaryrefslogtreecommitdiffstats
path: root/2015/rs/code/seven/src/main.rs
blob: ec2c3166b00b3120352a302ad79d4111d6c85aea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use std::collections::HashMap;

static INPUT: &[u8] = include_bytes!("input.txt");

#[derive(Debug, Copy, Clone)]
enum WireOrLiteral {
  Wire([u8; 2]),
  Literal(u16)
}

#[derive(Debug, Copy, Clone)]
enum Connection {
  Direct(WireOrLiteral),
  Not   (WireOrLiteral),
  And   (WireOrLiteral, WireOrLiteral),
  Or    (WireOrLiteral, WireOrLiteral),
  LShift(WireOrLiteral, WireOrLiteral),
  RShift(WireOrLiteral, WireOrLiteral),
}

#[derive(Debug, Copy, Clone)]
enum Cache {
  Cached(u16),
  Uncached(Connection)
}

fn main() {
  let valueified = INPUT
    .split(|b| *b == b'\n').filter(|b| !b.is_empty())
    .map(|line| {
      let mut bits = line.split(|b| *b == b'-');
      let (rhs, lhs) = (bits.next().unwrap().strip_suffix(b" ").unwrap(), bits.next().unwrap().strip_prefix(b"> ").unwrap());
      let mut cmdbits = rhs.split(|b| *b == b' ');
      let cmdbits = (cmdbits.next().unwrap(), cmdbits.next().unwrap_or(&[]), cmdbits.next().unwrap_or(&[]));

      let connection = match cmdbits {
        (wol, &[], &[]) => Connection::Direct(parse_wol(wol)),
        (b"NOT", wol, &[]) => Connection::Not(parse_wol(wol)),
        (wol1, b"AND", wol2) => Connection::And(parse_wol(wol1), parse_wol(wol2)),
        (wol1, b"OR", wol2) => Connection::Or(parse_wol(wol1), parse_wol(wol2)),
        (wol1, b"LSHIFT", wol2) => Connection::LShift(parse_wol(wol1), parse_wol(wol2)),
        (wol1, b"RSHIFT", wol2) => Connection::RShift(parse_wol(wol1), parse_wol(wol2)),
        _ => unreachable!()
      };

      let wire = [lhs[0], *lhs.get(1).unwrap_or(&0)];

      (wire, Cache::Uncached(connection))
    })
    .collect::<HashMap<[u8; 2], Cache>>();

  let mut part1 = valueified.clone();
  let a_val = walk(*b"a\0", &mut part1);
  println!("a: {a_val}");


  let mut part2 = valueified.clone();
  part2.insert(*b"b\0", Cache::Uncached(Connection::Direct(WireOrLiteral::Literal(a_val))));
  let a_val_2 = walk(*b"a\0", &mut part2);
  println!("a with b={a_val}: {a_val_2}");
}

fn parse_wol(bytes: &[u8]) -> WireOrLiteral {
  if bytes.iter().all(u8::is_ascii_digit) {
    WireOrLiteral::Literal(std::str::from_utf8(bytes).unwrap().parse().unwrap())
  } else {
    WireOrLiteral::Wire([bytes[0], *bytes.get(1).unwrap_or(&0)])
  }
}

fn walk(key: [u8; 2], map: &mut HashMap<[u8; 2], Cache>) -> u16 {
  match map[&key] {
    Cache::Cached(val) => val,
    Cache::Uncached(conn) => {
      let val = match conn {
        Connection::Direct(wol) => get_wol(wol, map),
        Connection::Not(wol) => !get_wol(wol, map),
        Connection::And(wol1, wol2) => get_wol(wol1, map) & get_wol(wol2, map),
        Connection::Or(wol1, wol2) => get_wol(wol1, map) | get_wol(wol2, map),
        Connection::LShift(wol1, wol2) => get_wol(wol1, map) << get_wol(wol2, map),
        Connection::RShift(wol1, wol2) => get_wol(wol1, map) >> get_wol(wol2, map)
      };
      map.insert(key, Cache::Cached(val));
      val
    }
  }
}

fn get_wol(wol: WireOrLiteral, map: &mut HashMap<[u8; 2], Cache>) -> u16 {
  match wol {
    WireOrLiteral::Wire(wire) => walk(wire, map),
    WireOrLiteral::Literal(literal) => literal
  }
}