aoc

My solutions for the Advent of Code
git clone https://git.tronto.net/aoc
Download | Log | Files | Refs | README

commit a65fa49611fd79f66e5d0aec828864cf6c4a089b
parent 0b96ba14f37aa50c59979169ae476634356c5438
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Thu,  3 Jul 2025 08:10:28 +0200

16 part 1 works, but I made some changes afterwards

Diffstat:
A2022/16/a.rs | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A2022/16/b.rs | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A2022/16/input | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
A2022/16/test | 10++++++++++
4 files changed, 412 insertions(+), 0 deletions(-)

diff --git a/2022/16/a.rs b/2022/16/a.rs @@ -0,0 +1,135 @@ +use std::cmp::max; +use std::collections::HashMap; + +#[derive(Debug, Clone)] +struct Node { + name: u16, + rate: usize, + neighbors: Vec<u16> +} + +#[derive(Debug, Copy, Clone)] +struct MapState { + valves: usize, + pos_ind: usize, + max_pos: usize +} + +#[derive(Debug, Clone)] +struct Map { + index: HashMap<u16, usize>, + nodes: Vec<Node> +} + +fn getname(line: &str) -> u16 { + 100 * (line.chars().nth(0).unwrap() as u16) + + (line.chars().nth(1).unwrap() as u16) +} + +impl Node { + fn from_line(line: &str) -> Node { + let name = getname(&line[6..]); + let j = line.find(';').unwrap(); + let rate = line[23..j].parse::<usize>().unwrap(); + let mut neighbors = vec![]; + let mut i = j+24; + // "tunnels lead to valves" vs "tunnel lead to valve" + // What kind of sadistic animal made these inputs? + if line.chars().nth(i).unwrap() == ' ' { i += 1; } + while i < line.len() { + neighbors.push(getname(&line[i..])); + i += 4; + } + Node { name, rate, neighbors } + } +} + +impl Map { + fn from_stdin() -> Map { + let mut line = String::new(); + let mut nodes = Vec::<Node>::new(); + while std::io::stdin().read_line(&mut line).unwrap() > 0 { + let node = Node::from_line(&line); + if nodes.len() > 0 && node.name == getname("AA") { + nodes.push(nodes[0].clone()); + nodes[0] = node; + } else { + nodes.push(node); + } + line.clear(); + } + let index = nodes.iter() + .enumerate() + .map(|(i, n)| (n.name, i)) + .collect::<HashMap<_, _>>(); + Map { index, nodes } + } + + fn state_max(&self) -> usize { + let mut i: usize = 0; + let mut tot: usize = 0; + for n in &self.nodes { + if n.rate == 0 { continue; } + tot += 1 << i; + i += 1; + } + let len = self.nodes.len(); + tot * len + len + } + + fn released_pressure(&self) -> usize { + self.nodes.iter() + .map(|n| if n.valve_on { n.rate } else { 0 }) + .sum() + } + + fn most_pressure(&self, minutes: usize) -> usize { + let n = self.state_max(); + let mut t = vec![0 as usize; n]; + let mut u = vec![0 as usize; n]; + let mut map = self.clone(); + + // Setup table for last minute + for s in 0..n { + map.set_state(s); + t[s] = map.released_pressure(); + } + + // Dynamic programming counting back to 0 minutes + for i in (0..minutes).rev() { + // Double buffer technique so we don't have to swap vectors + let (current, next) = if i % 2 == minutes % 2 { + (&mut t, &mut u) + } else { + (&mut u, &mut t) + }; + for s in 0..n { + map.set_state(s); + let pos = map.pos; + let mut k = 0; + let ind = map.index[&pos]; + let p = map.released_pressure(); + + // Try turning on the valve + if map.nodes[ind].rate > 0 && !map.nodes[ind].valve_on { + map.nodes[ind].valve_on = true; + k = max(k, p + next[map.get_state()]); + map.nodes[ind].valve_on = false; + } + + // Try moving to a neighbor + for v in &map.nodes[ind].neighbors { + map.pos = *v; + k = max(k, p + next[map.get_state()]); + } + current[s] = k; + } + } + if 0 == minutes % 2 { t[0] } else { u[0] } + } +} + +fn main() { + let map = Map::from_stdin(); + println!("{}", map.most_pressure(29)); +} diff --git a/2022/16/b.rs b/2022/16/b.rs @@ -0,0 +1,216 @@ +use std::cmp::{max, Eq, PartialEq}; +use std::collections::HashMap; +use std::hash::{Hash, Hasher}; + +#[derive(Debug, Clone)] +struct Node { + name: u16, + rate: usize, + neighbors: Vec<u16>, + valve_on: bool +} + +#[derive(Debug, Clone)] +struct Map { + index: HashMap<u16, usize>, + nodes: Vec<Node>, + pos: u16 +} + +fn getname(line: &str) -> u16 { + 100 * (line.chars().nth(0).unwrap() as u16) + + (line.chars().nth(1).unwrap() as u16) +} + +impl Node { + fn from_line(line: &str) -> Node { + let name = getname(&line[6..]); + let j = line.find(';').unwrap(); + let rate = line[23..j].parse::<usize>().unwrap(); + let mut neighbors = vec![]; + let mut i = j+24; + // "tunnels lead to valves" vs "tunnel lead to valve" + // What kind of sadistic animal made these inputs? + if line.chars().nth(i).unwrap() == ' ' { i += 1; } + while i < line.len() { + neighbors.push(getname(&line[i..])); + i += 4; + } + Node { name, rate, neighbors, valve_on: false } + } +} + +impl Map { + fn from_stdin() -> Map { + let mut line = String::new(); + let mut nodes = Vec::<Node>::new(); + while std::io::stdin().read_line(&mut line).unwrap() > 0 { + let node = Node::from_line(&line); + if nodes.len() > 0 && node.name == getname("AA") { + nodes.push(nodes[0].clone()); + nodes[0] = node; + } else { + nodes.push(node); + } + line.clear(); + } + let index = nodes.iter() + .enumerate() + .map(|(i, n)| (n.name, i)) + .collect::<HashMap<_, _>>(); + Map { index, nodes, pos: getname("AA") } + } + + fn get_state(&self) -> usize { + let mut i: usize = 0; + let mut tot: usize = 0; + for n in &self.nodes { + if n.rate == 0 { continue; } + if n.valve_on { tot += 1 << i; } + i += 1; + } + tot * self.nodes.len() + self.index[&self.pos] + } + + fn set_state(&mut self, state: usize) { + let mut s = state; + let len = self.nodes.len(); + self.pos = self.nodes[s%len].name; + s /= len; + for i in 0..len { + if self.nodes[i].rate == 0 { continue; } + self.nodes[i].valve_on = s % 2 == 1; + s /= 2; + } + } + + fn state_max(&self) -> usize { + let mut i: usize = 0; + let mut tot: usize = 0; + for n in &self.nodes { + if n.rate == 0 { continue; } + tot += 1 << i; + i += 1; + } + let len = self.nodes.len(); + tot * len + len + } + + fn released_pressure(&self) -> usize { + self.nodes.iter() + .map(|n| if n.valve_on { n.rate } else { 0 }) + .sum() + } + +/* + fn most_pressure(&self, minutes: usize) -> usize { + let n = self.state_max(); + let mut t = vec![0 as usize; n]; + let mut u = vec![0 as usize; n]; + let mut map = self.clone(); + + // Setup table for last minute + for s in 0..n { + map.set_state(s); + t[s] = map.released_pressure(); + } + + // Dynamic programming counting back to 0 minutes + for i in (0..minutes).rev() { + // Double buffer technique so we don't have to swap vectors + let (current, next) = if i % 2 == minutes % 2 { + (&mut t, &mut u) + } else { + (&mut u, &mut t) + }; + for s in 0..n { + map.set_state(s); + let pos = map.pos; + let mut k = 0; + let ind = map.index[&pos]; + let p = map.released_pressure(); + + // Try turning on the valve + if map.nodes[ind].rate > 0 && !map.nodes[ind].valve_on { + map.nodes[ind].valve_on = true; + k = max(k, p + next[map.get_state()]); + map.nodes[ind].valve_on = false; + } + + // Try moving to a neighbor + for v in &map.nodes[ind].neighbors { + map.pos = *v; + k = max(k, p + next[map.get_state()]); + } + current[s] = k; + } + } + if 0 == minutes % 2 { t[0] } else { u[0] } + } +*/ + + fn most_pressure(&self, minutes: usize) -> usize { + let n = self.state_max(); + let mut t = vec![0 as usize; n]; + let mut u = vec![0 as usize; n]; + let mut map = self.clone(); + + // Setup table for last minute + for s in 0..n { + map.set_state(s); + t[s] = map.released_pressure(); + } + + // Dynamic programming counting back to 0 minutes + for i in (0..minutes).rev() { + // Double buffer technique so we don't have to swap vectors + let (current, next) = if i % 2 == minutes % 2 { + (&mut t, &mut u) + } else { + (&mut u, &mut t) + }; + for s in 0..n { + map.set_state(s); + let pos = map.pos; + let mut k = 0; + let ind = map.index[&pos]; + let p = map.released_pressure(); + + // Try turning on the valve + if map.nodes[ind].rate > 0 && !map.nodes[ind].valve_on { + map.nodes[ind].valve_on = true; + k = max(k, p + next[map.get_state()]); + map.nodes[ind].valve_on = false; + } + + // Try moving to a neighbor + for v in &map.nodes[ind].neighbors { + map.pos = *v; + k = max(k, p + next[map.get_state()]); + } + current[s] = k; + } + } + if 0 == minutes % 2 { t[0] } else { u[0] } + } +} + +impl PartialEq for Map { + fn eq(&self, other: &Self) -> bool { + self.get_state() == other.get_state() + } +} + +impl Eq for Map {} + +impl Hash for Map { + fn hash<H: Hasher>(&self, hasher: &mut H) { + hasher.write_usize(self.get_state()); + } +} + +fn main() { + let map = Map::from_stdin(); + let mut t = HashMap::<Map, usize>::new(); + println!("{}", map.most_pressure(29, t)); +} diff --git a/2022/16/input b/2022/16/input @@ -0,0 +1,51 @@ +Valve OS has flow rate=0; tunnels lead to valves EE, CL +Valve EN has flow rate=0; tunnels lead to valves CL, GV +Valve RR has flow rate=24; tunnels lead to valves FS, YP +Valve VB has flow rate=20; tunnels lead to valves UU, EY, SG, ZB +Valve UU has flow rate=0; tunnels lead to valves OT, VB +Valve WH has flow rate=0; tunnels lead to valves CS, JS +Valve OF has flow rate=25; tunnel leads to valve YM +Valve TY has flow rate=0; tunnels lead to valves AA, GQ +Valve RV has flow rate=0; tunnels lead to valves BT, YX +Valve GK has flow rate=0; tunnels lead to valves GD, AA +Valve EL has flow rate=0; tunnels lead to valves EK, EE +Valve OT has flow rate=9; tunnels lead to valves YR, BJ, OX, UU, HJ +Valve DG has flow rate=11; tunnels lead to valves BN, QE +Valve YR has flow rate=0; tunnels lead to valves OT, YX +Valve GV has flow rate=0; tunnels lead to valves AA, EN +Valve BN has flow rate=0; tunnels lead to valves DG, LU +Valve FS has flow rate=0; tunnels lead to valves TI, RR +Valve DW has flow rate=0; tunnels lead to valves SS, MS +Valve DJ has flow rate=0; tunnels lead to valves KY, GD +Valve BJ has flow rate=0; tunnels lead to valves OT, BT +Valve KY has flow rate=0; tunnels lead to valves EE, DJ +Valve YP has flow rate=0; tunnels lead to valves YM, RR +Valve LU has flow rate=0; tunnels lead to valves BN, CS +Valve OX has flow rate=0; tunnels lead to valves OT, XD +Valve ZB has flow rate=0; tunnels lead to valves VB, PP +Valve CL has flow rate=10; tunnels lead to valves KQ, EN, OS, MQ +Valve XD has flow rate=0; tunnels lead to valves KR, OX +Valve YM has flow rate=0; tunnels lead to valves OF, YP +Valve EY has flow rate=0; tunnels lead to valves MS, VB +Valve KQ has flow rate=0; tunnels lead to valves CS, CL +Valve SS has flow rate=0; tunnels lead to valves AA, DW +Valve SG has flow rate=0; tunnels lead to valves VB, KR +Valve EE has flow rate=22; tunnels lead to valves XR, OS, KY, EL +Valve OI has flow rate=0; tunnels lead to valves RE, MS +Valve QE has flow rate=0; tunnels lead to valves DG, GD +Valve GD has flow rate=3; tunnels lead to valves GK, DJ, MQ, QE, JS +Valve EK has flow rate=23; tunnel leads to valve EL +Valve GQ has flow rate=0; tunnels lead to valves CS, TY +Valve CS has flow rate=7; tunnels lead to valves GQ, WH, KQ, LU +Valve MS has flow rate=4; tunnels lead to valves HJ, EY, DW, OI +Valve XR has flow rate=0; tunnels lead to valves EE, AA +Valve RE has flow rate=6; tunnels lead to valves TI, PP, OI +Valve KR has flow rate=17; tunnels lead to valves XD, SG +Valve BT has flow rate=15; tunnels lead to valves BJ, RV +Valve PP has flow rate=0; tunnels lead to valves RE, ZB +Valve TI has flow rate=0; tunnels lead to valves RE, FS +Valve HJ has flow rate=0; tunnels lead to valves OT, MS +Valve AA has flow rate=0; tunnels lead to valves GK, GV, SS, XR, TY +Valve MQ has flow rate=0; tunnels lead to valves GD, CL +Valve JS has flow rate=0; tunnels lead to valves GD, WH +Valve YX has flow rate=5; tunnels lead to valves YR, RV diff --git a/2022/16/test b/2022/16/test @@ -0,0 +1,10 @@ +Valve AA has flow rate=0; tunnels lead to valves DD, II, BB +Valve BB has flow rate=13; tunnels lead to valves CC, AA +Valve CC has flow rate=2; tunnels lead to valves DD, BB +Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE +Valve EE has flow rate=3; tunnels lead to valves FF, DD +Valve FF has flow rate=0; tunnels lead to valves EE, GG +Valve GG has flow rate=0; tunnels lead to valves FF, HH +Valve HH has flow rate=22; tunnel leads to valve GG +Valve II has flow rate=0; tunnels lead to valves AA, JJ +Valve JJ has flow rate=21; tunnel leads to valve II