mirror of
https://github.com/Noratrieb/advent-of-code.git
synced 2026-01-16 18:45:02 +01:00
start day 8
This commit is contained in:
parent
f933f33ceb
commit
8e51f43402
10 changed files with 1163 additions and 0 deletions
45
2023/day08/src/lib.rs
Normal file
45
2023/day08/src/lib.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
mod p1basic;
|
||||
mod p2basic;
|
||||
|
||||
use helper::{Day, Variants};
|
||||
|
||||
pub fn main() {
|
||||
helper::main::<Day08>(include_str!("../input.txt"));
|
||||
}
|
||||
|
||||
struct Day08;
|
||||
|
||||
helper::define_variants! {
|
||||
day => crate::Day08;
|
||||
part1 {
|
||||
basic => crate::p1basic::part1;
|
||||
}
|
||||
part2 {
|
||||
basic => crate::p2basic::part2;
|
||||
}
|
||||
}
|
||||
|
||||
impl Day for Day08 {
|
||||
fn part1() -> Variants {
|
||||
part1_variants!(construct_variants)
|
||||
}
|
||||
|
||||
fn part2() -> Variants {
|
||||
part2_variants!(construct_variants)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
helper::tests! {
|
||||
day08 Day08;
|
||||
part1 {
|
||||
"../input_small1.txt" => 6;
|
||||
"../input.txt" => 12361;
|
||||
}
|
||||
part2 {
|
||||
"../input_small2.txt" => 6;
|
||||
"../input.txt" => 0;
|
||||
}
|
||||
}
|
||||
|
||||
helper::benchmarks! {}
|
||||
3
2023/day08/src/main.rs
Normal file
3
2023/day08/src/main.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
day08::main();
|
||||
}
|
||||
87
2023/day08/src/p1basic.rs
Normal file
87
2023/day08/src/p1basic.rs
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Map {
|
||||
instructions: Vec<Instruction>,
|
||||
nodes: Vec<Node>,
|
||||
aaa: usize,
|
||||
zzz: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node {
|
||||
left_right: [usize; 2],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Instruction {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
fn parse(input: &str) -> Map {
|
||||
let mut lines = input.lines();
|
||||
let instructions = lines
|
||||
.next()
|
||||
.unwrap()
|
||||
.bytes()
|
||||
.map(|b| match b {
|
||||
b'R' => Instruction::Right,
|
||||
b'L' => Instruction::Left,
|
||||
_ => panic!(),
|
||||
})
|
||||
.collect();
|
||||
let _ = lines.next().unwrap();
|
||||
|
||||
let mut names = HashMap::new();
|
||||
let mut aaa = 0;
|
||||
let mut zzz = 0;
|
||||
let nodes = lines
|
||||
.enumerate()
|
||||
.map(|(i, line)| {
|
||||
let (name, next) = line.split_once(" = ").unwrap();
|
||||
names.insert(name, i);
|
||||
if name == "AAA" {
|
||||
aaa = i;
|
||||
} else if name == "ZZZ" {
|
||||
zzz = i;
|
||||
}
|
||||
let (left, right) = next
|
||||
.strip_prefix("(")
|
||||
.unwrap()
|
||||
.strip_suffix(")")
|
||||
.unwrap()
|
||||
.split_once(", ")
|
||||
.unwrap();
|
||||
(left, right)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let nodes = nodes
|
||||
.into_iter()
|
||||
.map(|(left, right)| Node {
|
||||
left_right: [*names.get(left).unwrap(), *names.get(right).unwrap()],
|
||||
})
|
||||
.collect();
|
||||
|
||||
Map {
|
||||
instructions,
|
||||
nodes,
|
||||
aaa,
|
||||
zzz,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn part1(input: &str) -> u64 {
|
||||
let map = parse(input);
|
||||
|
||||
let mut next = map.instructions.iter().cycle();
|
||||
let mut node = map.aaa;
|
||||
let mut i = 0;
|
||||
while node != map.zzz {
|
||||
node = map.nodes[node].left_right[*next.next().unwrap() as usize];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
i
|
||||
}
|
||||
198
2023/day08/src/p2basic.rs
Normal file
198
2023/day08/src/p2basic.rs
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Map {
|
||||
instructions: Vec<Instruction>,
|
||||
nodes: Vec<Node>,
|
||||
a_nodes: Vec<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node {
|
||||
left_right: [usize; 2],
|
||||
z: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Instruction {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
fn parse(input: &str) -> Map {
|
||||
let mut lines = input.lines();
|
||||
let instructions = lines
|
||||
.next()
|
||||
.unwrap()
|
||||
.bytes()
|
||||
.map(|b| match b {
|
||||
b'R' => Instruction::Right,
|
||||
b'L' => Instruction::Left,
|
||||
_ => panic!(),
|
||||
})
|
||||
.collect();
|
||||
let _ = lines.next().unwrap();
|
||||
|
||||
let mut names = HashMap::new();
|
||||
let mut a_nodes = Vec::new();
|
||||
|
||||
let nodes = lines
|
||||
.enumerate()
|
||||
.map(|(i, line)| {
|
||||
let (name, next) = line.split_once(" = ").unwrap();
|
||||
names.insert(name, i);
|
||||
if name.ends_with('A') {
|
||||
a_nodes.push(i);
|
||||
}
|
||||
let z = name.ends_with('Z');
|
||||
let (left, right) = next
|
||||
.strip_prefix("(")
|
||||
.unwrap()
|
||||
.strip_suffix(")")
|
||||
.unwrap()
|
||||
.split_once(", ")
|
||||
.unwrap();
|
||||
|
||||
(left, right, z)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let nodes = nodes
|
||||
.into_iter()
|
||||
.map(|(left, right, z)| Node {
|
||||
left_right: [*names.get(left).unwrap(), *names.get(right).unwrap()],
|
||||
z,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Map {
|
||||
instructions,
|
||||
nodes,
|
||||
a_nodes,
|
||||
}
|
||||
}
|
||||
|
||||
fn optimize(nodes: &mut [Node]) {
|
||||
let mut optimized = true;
|
||||
while optimized {
|
||||
optimized = false;
|
||||
for node_idx in 0..nodes.len() {
|
||||
let node = &nodes[node_idx];
|
||||
if node.z {
|
||||
continue;
|
||||
}
|
||||
if node.left_right[0] == node.left_right[1] {
|
||||
let replace = node.left_right[0];
|
||||
|
||||
for i in 0..nodes.len() {
|
||||
let node = &mut nodes[i];
|
||||
if node.left_right[0] == node_idx {
|
||||
node.left_right[0] = replace;
|
||||
optimized = true;
|
||||
}
|
||||
if node.left_right[1] == node_idx {
|
||||
node.left_right[1] = replace;
|
||||
optimized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// example:
|
||||
// idx 0 cycles every 2 instructions
|
||||
// idx 1 cycles every 3 instructions
|
||||
|
||||
// lcm(2, 3) = 6
|
||||
|
||||
// we're conservatively overcounting a bit sometimes
|
||||
// idx 0 cycles every 1 sequences (in reality, 1)
|
||||
// idx 1 cycles every 3 sequences (in realtiy, 1.5)
|
||||
|
||||
// lcm(1, 3) = 3 (3 * 2 = 6)
|
||||
|
||||
fn find_the_cycles(map: &Map) -> Vec<usize> {
|
||||
let mut periods = Vec::new();
|
||||
for start in &map.a_nodes {
|
||||
println!("node {start}");
|
||||
let mut locations = HashMap::new();
|
||||
let mut node = *start;
|
||||
let mut period = 0_usize;
|
||||
loop {
|
||||
for next in &map.instructions {
|
||||
node = map.nodes[node].left_right[*next as usize];
|
||||
}
|
||||
let end_location = node;
|
||||
println!("{end_location}");
|
||||
if let Some(start) = locations.get(&end_location) {
|
||||
assert_eq!(*start, 0);
|
||||
periods.push(period - start);
|
||||
break;
|
||||
}
|
||||
locations.insert(end_location, period);
|
||||
period += 1;
|
||||
}
|
||||
}
|
||||
periods
|
||||
}
|
||||
|
||||
pub fn part2(input: &str) -> u64 {
|
||||
let mut map = parse(input);
|
||||
|
||||
//optimize(&mut map.nodes);
|
||||
let cycles = find_the_cycles(&map);
|
||||
dbg!(&cycles);
|
||||
//return 0;
|
||||
|
||||
let count_to_z = cycles
|
||||
.iter()
|
||||
.zip(&map.a_nodes)
|
||||
.map(|(period, node)| {
|
||||
let mut node = *node;
|
||||
for next in &map.instructions {
|
||||
node = map.nodes[node].left_right[*next as usize];
|
||||
}
|
||||
|
||||
for (i, next) in map
|
||||
.instructions
|
||||
.iter()
|
||||
.cycle()
|
||||
.take(map.instructions.len() * period)
|
||||
.enumerate()
|
||||
{
|
||||
node = map.nodes[node].left_right[*next as usize];
|
||||
if map.nodes[node].z {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
unreachable!()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
dbg!(&count_to_z);
|
||||
|
||||
let mut next = map.instructions.iter().cycle();
|
||||
let mut nodes = map.a_nodes;
|
||||
let mut i = 0;
|
||||
|
||||
loop {
|
||||
let mut count = 0;
|
||||
|
||||
let next = next.next().unwrap();
|
||||
nodes.iter_mut().for_each(|node| {
|
||||
*node = map.nodes[*node].left_right[*next as usize];
|
||||
|
||||
if map.nodes[*node].z {
|
||||
count += 1;
|
||||
}
|
||||
});
|
||||
i += 1;
|
||||
|
||||
if count == nodes.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue