aboutsummaryrefslogtreecommitdiff
path: root/2022/16/a.rs
diff options
context:
space:
mode:
Diffstat (limited to '2022/16/a.rs')
-rw-r--r--2022/16/a.rs135
1 files changed, 135 insertions, 0 deletions
diff --git a/2022/16/a.rs b/2022/16/a.rs
new file mode 100644
index 0000000..d6f3569
--- /dev/null
+++ b/2022/16/a.rs
@@ -0,0 +1,135 @@
1use std::cmp::max;
2use std::collections::HashMap;
3
4#[derive(Debug, Clone)]
5struct Node {
6 name: u16,
7 rate: usize,
8 neighbors: Vec<u16>
9}
10
11#[derive(Debug, Copy, Clone)]
12struct MapState {
13 valves: usize,
14 pos_ind: usize,
15 max_pos: usize
16}
17
18#[derive(Debug, Clone)]
19struct Map {
20 index: HashMap<u16, usize>,
21 nodes: Vec<Node>
22}
23
24fn getname(line: &str) -> u16 {
25 100 * (line.chars().nth(0).unwrap() as u16) +
26 (line.chars().nth(1).unwrap() as u16)
27}
28
29impl Node {
30 fn from_line(line: &str) -> Node {
31 let name = getname(&line[6..]);
32 let j = line.find(';').unwrap();
33 let rate = line[23..j].parse::<usize>().unwrap();
34 let mut neighbors = vec![];
35 let mut i = j+24;
36 // "tunnels lead to valves" vs "tunnel lead to valve"
37 // What kind of sadistic animal made these inputs?
38 if line.chars().nth(i).unwrap() == ' ' { i += 1; }
39 while i < line.len() {
40 neighbors.push(getname(&line[i..]));
41 i += 4;
42 }
43 Node { name, rate, neighbors }
44 }
45}
46
47impl Map {
48 fn from_stdin() -> Map {
49 let mut line = String::new();
50 let mut nodes = Vec::<Node>::new();
51 while std::io::stdin().read_line(&mut line).unwrap() > 0 {
52 let node = Node::from_line(&line);
53 if nodes.len() > 0 && node.name == getname("AA") {
54 nodes.push(nodes[0].clone());
55 nodes[0] = node;
56 } else {
57 nodes.push(node);
58 }
59 line.clear();
60 }
61 let index = nodes.iter()
62 .enumerate()
63 .map(|(i, n)| (n.name, i))
64 .collect::<HashMap<_, _>>();
65 Map { index, nodes }
66 }
67
68 fn state_max(&self) -> usize {
69 let mut i: usize = 0;
70 let mut tot: usize = 0;
71 for n in &self.nodes {
72 if n.rate == 0 { continue; }
73 tot += 1 << i;
74 i += 1;
75 }
76 let len = self.nodes.len();
77 tot * len + len
78 }
79
80 fn released_pressure(&self) -> usize {
81 self.nodes.iter()
82 .map(|n| if n.valve_on { n.rate } else { 0 })
83 .sum()
84 }
85
86 fn most_pressure(&self, minutes: usize) -> usize {
87 let n = self.state_max();
88 let mut t = vec![0 as usize; n];
89 let mut u = vec![0 as usize; n];
90 let mut map = self.clone();
91
92 // Setup table for last minute
93 for s in 0..n {
94 map.set_state(s);
95 t[s] = map.released_pressure();
96 }
97
98 // Dynamic programming counting back to 0 minutes
99 for i in (0..minutes).rev() {
100 // Double buffer technique so we don't have to swap vectors
101 let (current, next) = if i % 2 == minutes % 2 {
102 (&mut t, &mut u)
103 } else {
104 (&mut u, &mut t)
105 };
106 for s in 0..n {
107 map.set_state(s);
108 let pos = map.pos;
109 let mut k = 0;
110 let ind = map.index[&pos];
111 let p = map.released_pressure();
112
113 // Try turning on the valve
114 if map.nodes[ind].rate > 0 && !map.nodes[ind].valve_on {
115 map.nodes[ind].valve_on = true;
116 k = max(k, p + next[map.get_state()]);
117 map.nodes[ind].valve_on = false;
118 }
119
120 // Try moving to a neighbor
121 for v in &map.nodes[ind].neighbors {
122 map.pos = *v;
123 k = max(k, p + next[map.get_state()]);
124 }
125 current[s] = k;
126 }
127 }
128 if 0 == minutes % 2 { t[0] } else { u[0] }
129 }
130}
131
132fn main() {
133 let map = Map::from_stdin();
134 println!("{}", map.most_pressure(29));
135}

Generated with cgit - Back to sebastiano.tronto.net