Skip to content

Commit ebf5261

Browse files
committed
Another 2015
1 parent ee08d23 commit ebf5261

4 files changed

Lines changed: 179 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
1313
| [2025](aoc2025) | 14/24 |
1414
| [2024](aoc2024) | 50/50 |
1515
| [2023](aoc2023) | 50/50 |
16-
| [2015](aoc2015) | 12/50 |
16+
| [2015](aoc2015) | 14/50 |
1717

1818
---
1919

aoc2015/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
1212
| [Day 4](https://adventofcode.com/2024/day/4) | [code](src/bin/04.rs) |||
1313
| [Day 5](https://adventofcode.com/2024/day/5) | [code](src/bin/05.rs) |||
1414
| [Day 6](https://adventofcode.com/2024/day/6) | [code](src/bin/06.rs) |||
15-
| [Day 7](https://adventofcode.com/2024/day/7) | [code](src/bin/07.rs) | _ | _ |
15+
| [Day 7](https://adventofcode.com/2024/day/7) | [code](src/bin/07.rs) | | |
1616
| [Day 8](https://adventofcode.com/2024/day/8) | [code](src/bin/08.rs) | _ | _ |
1717
| [Day 9](https://adventofcode.com/2024/day/9) | [code](src/bin/09.rs) | _ | _ |
1818
| [Day 10](https://adventofcode.com/2024/day/10) | [code](src/bin/10.rs) | _ | _ |

aoc2015/data/examples/07.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
123 -> x
2+
456 -> y
3+
x AND y -> a
4+
x OR y -> e
5+
x LSHIFT 2 -> f
6+
y RSHIFT 2 -> g
7+
NOT x -> h
8+
NOT y -> i

aoc2015/src/bin/07.rs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
use std::collections::VecDeque;
2+
3+
use aoc_utils::*;
4+
use itertools::Itertools;
5+
6+
advent_of_code::solution!(7);
7+
8+
type Wire = usize;
9+
10+
#[derive(Debug, Clone, Copy)]
11+
enum Op {
12+
Reg(Wire),
13+
And(Wire, Wire),
14+
AndOne(Wire),
15+
Or(Wire, Wire),
16+
Lshift(Wire, u16),
17+
Rshift(Wire, u16),
18+
Not(Wire),
19+
}
20+
21+
impl Op {
22+
fn parse(input: &str) -> Self {
23+
let parts = input.split_whitespace().collect_vec();
24+
if parts.len() == 1 {
25+
// x
26+
return Op::Reg(str_to_index(parts[0]));
27+
}
28+
if parts.len() == 2 {
29+
// NOT x
30+
return Op::Not(str_to_index(parts[1]));
31+
}
32+
// x OP y
33+
match parts[1] {
34+
"AND" => {
35+
if parts[0] == "1" {
36+
Op::AndOne(str_to_index(parts[2]))
37+
} else {
38+
Op::And(str_to_index(parts[0]), str_to_index(parts[2]))
39+
}
40+
}
41+
"OR" => Op::Or(str_to_index(parts[0]), str_to_index(parts[2])),
42+
"LSHIFT" => Op::Lshift(
43+
str_to_index(parts[0]),
44+
parts[2].parse().expect("Lshift rvalue should be u16"),
45+
),
46+
"RSHIFT" => Op::Rshift(
47+
str_to_index(parts[0]),
48+
parts[2].parse().expect("Rshift rvalue should be u16"),
49+
),
50+
other => panic!("Shouldn't exist {}", other),
51+
}
52+
}
53+
54+
fn handle(&self, regs: &[Option<u16>]) -> Option<u16> {
55+
match self {
56+
Op::Reg(a) => regs[*a],
57+
Op::And(a, b) => match (regs[*a], regs[*b]) {
58+
(None, None) => None,
59+
(None, Some(_)) => None,
60+
(Some(_), None) => None,
61+
(Some(x), Some(y)) => Some(x & y),
62+
},
63+
Op::AndOne(a) => regs[*a].map(|x| x & 1),
64+
Op::Or(a, b) => match (regs[*a], regs[*b]) {
65+
(None, None) => None,
66+
(None, Some(_)) => None,
67+
(Some(_), None) => None,
68+
(Some(x), Some(y)) => Some(x | y),
69+
},
70+
Op::Lshift(a, n) => regs[*a].map(|x| x << n),
71+
Op::Rshift(a, n) => regs[*a].map(|x| x >> n),
72+
Op::Not(a) => regs[*a].map(|x| !x),
73+
}
74+
}
75+
}
76+
77+
#[derive(Clone, Copy)]
78+
enum Assign {
79+
Literal(Wire, u16),
80+
Expr(Wire, Op),
81+
}
82+
83+
fn str_to_index(ident: &str) -> usize {
84+
ident
85+
.bytes()
86+
.fold(0, |num, c| num * 26 + ((c + 1 - b'a') as usize))
87+
- 1
88+
}
89+
90+
fn parse_input(input: &str) -> (Vec<Assign>, Vec<Option<u16>>) {
91+
let max_regs = str_to_index("zz");
92+
let regs: Vec<Option<u16>> = vec![None; max_regs];
93+
let circuit = input.mlines(|s| {
94+
let mut parts = s.split(" -> ");
95+
let op = parts.next().expect("Should be first part");
96+
let wire = parts.next().expect("Should be second part");
97+
let wire = str_to_index(wire.trim());
98+
if let Ok(x) = op.trim().parse::<u16>() {
99+
Assign::Literal(wire, x)
100+
} else {
101+
let expr = Op::parse(op);
102+
Assign::Expr(wire, expr)
103+
}
104+
});
105+
(circuit, regs)
106+
}
107+
108+
fn run_circuit(circuit: &[Assign], regs: &mut [Option<u16>]) {
109+
let mut circuit = circuit
110+
.iter()
111+
.filter(|a| {
112+
if let Assign::Literal(wire, num) = a {
113+
if regs[*wire].is_none() {
114+
// skip literal assignment for b in second run of part 2
115+
regs[*wire] = Some(*num);
116+
}
117+
return false;
118+
}
119+
true
120+
})
121+
.copied()
122+
.collect::<VecDeque<Assign>>();
123+
while !circuit.is_empty() {
124+
let next = circuit.pop_front().unwrap();
125+
let (wire, op) = if let Assign::Expr(wire, op) = &next {
126+
(wire, op)
127+
} else {
128+
panic!("Should only be Exprs left")
129+
};
130+
if let Some(res) = op.handle(regs) {
131+
regs[*wire] = Some(res);
132+
} else {
133+
circuit.push_back(next);
134+
}
135+
}
136+
}
137+
138+
pub fn part_one(input: &str) -> Option<u64> {
139+
let (circuit, mut regs) = parse_input(input);
140+
run_circuit(&circuit, &mut regs);
141+
regs[str_to_index("a")].map(|x| x as u64)
142+
}
143+
144+
pub fn part_two(input: &str) -> Option<u64> {
145+
let (circuit, mut regs) = parse_input(input);
146+
run_circuit(&circuit, &mut regs);
147+
let new_b = regs[str_to_index("a")];
148+
let mut regs = vec![None; regs.len()];
149+
regs[str_to_index("b")] = new_b;
150+
run_circuit(&circuit, &mut regs);
151+
regs[str_to_index("a")].map(|x| x as u64)
152+
}
153+
154+
#[cfg(test)]
155+
mod tests {
156+
use super::*;
157+
158+
#[test]
159+
fn test_part_one() {
160+
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
161+
assert_eq!(result, Some(72));
162+
}
163+
164+
#[test]
165+
fn test_part_two() {
166+
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
167+
assert_eq!(result, Some(72));
168+
}
169+
}

0 commit comments

Comments
 (0)