aboutsummaryrefslogtreecommitdiff
path: root/2022/16/b.rs
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2025-07-03 08:10:28 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2025-07-03 08:10:28 +0200
commitda1e366c3d6fd6b746a7eb34cf7124adcbd15805 (patch)
treea955e3a95c31873700e81cada90757f1c8fc21a0 /2022/16/b.rs
parent6b89133a79e798edadca7eb59800441535e97670 (diff)
downloadaoc-da1e366c3d6fd6b746a7eb34cf7124adcbd15805.tar.gz
aoc-da1e366c3d6fd6b746a7eb34cf7124adcbd15805.zip
16 part 1 works, but I made some changes afterwards
Diffstat (limited to '2022/16/b.rs')
-rw-r--r--2022/16/b.rs216
1 files changed, 216 insertions, 0 deletions
diff --git a/2022/16/b.rs b/2022/16/b.rs
new file mode 100644
index 0000000..defd5d1
--- /dev/null
+++ b/2022/16/b.rs
@@ -0,0 +1,216 @@
1use std::cmp::{max, Eq, PartialEq};
2use std::collections::HashMap;
3use std::hash::{Hash, Hasher};
4
5#[derive(Debug, Clone)]
6struct Node {
7 name: u16,
8 rate: usize,
9 neighbors: Vec<u16>,
10 valve_on: bool
11}
12
13#[derive(Debug, Clone)]
14struct Map {
15 index: HashMap<u16, usize>,
16 nodes: Vec<Node>,
17 pos: u16
18}
19
20fn getname(line: &str) -> u16 {
21 100 * (line.chars().nth(0).unwrap() as u16) +
22 (line.chars().nth(1).unwrap() as u16)
23}
24
25impl Node {
26 fn from_line(line: &str) -> Node {
27 let name = getname(&line[6..]);
28 let j = line.find(';').unwrap();
29 let rate = line[23..j].parse::<usize>().unwrap();
30 let mut neighbors = vec![];
31 let mut i = j+24;
32 // "tunnels lead to valves" vs "tunnel lead to valve"
33 // What kind of sadistic animal made these inputs?
34 if line.chars().nth(i).unwrap() == ' ' { i += 1; }
35 while i < line.len() {
36 neighbors.push(getname(&line[i..]));
37 i += 4;
38 }
39 Node { name, rate, neighbors, valve_on: false }
40 }
41}
42
43impl Map {
44 fn from_stdin() -> Map {
45 let mut line = String::new();
46 let mut nodes = Vec::<Node>::new();
47 while std::io::stdin().read_line(&mut line).unwrap() > 0 {
48 let node = Node::from_line(&line);
49 if nodes.len() > 0 && node.name == getname("AA") {
50 nodes.push(nodes[0].clone());
51 nodes[0] = node;
52 } else {
53 nodes.push(node);
54 }
55 line.clear();
56 }
57 let index = nodes.iter()
58 .enumerate()
59 .map(|(i, n)| (n.name, i))
60 .collect::<HashMap<_, _>>();
61 Map { index, nodes, pos: getname("AA") }
62 }
63
64 fn get_state(&self) -> usize {
65 let mut i: usize = 0;
66 let mut tot: usize = 0;
67 for n in &self.nodes {
68 if n.rate == 0 { continue; }
69 if n.valve_on { tot += 1 << i; }
70 i += 1;
71 }
72 tot * self.nodes.len() + self.index[&self.pos]
73 }
74
75 fn set_state(&mut self, state: usize) {
76 let mut s = state;
77 let len = self.nodes.len();
78 self.pos = self.nodes[s%len].name;
79 s /= len;
80 for i in 0..len {
81 if self.nodes[i].rate == 0 { continue; }
82 self.nodes[i].valve_on = s % 2 == 1;
83 s /= 2;
84 }
85 }
86
87 fn state_max(&self) -> usize {
88 let mut i: usize = 0;
89 let mut tot: usize = 0;
90 for n in &self.nodes {
91 if n.rate == 0 { continue; }
92 tot += 1 << i;
93 i += 1;
94 }
95 let len = self.nodes.len();
96 tot * len + len
97 }
98
99 fn released_pressure(&self) -> usize {
100 self.nodes.iter()
101 .map(|n| if n.valve_on { n.rate } else { 0 })
102 .sum()
103 }
104
105/*
106 fn most_pressure(&self, minutes: usize) -> usize {
107 let n = self.state_max();
108 let mut t = vec![0 as usize; n];
109 let mut u = vec![0 as usize; n];
110 let mut map = self.clone();
111
112 // Setup table for last minute
113 for s in 0..n {
114 map.set_state(s);
115 t[s] = map.released_pressure();
116 }
117
118 // Dynamic programming counting back to 0 minutes
119 for i in (0..minutes).rev() {
120 // Double buffer technique so we don't have to swap vectors
121 let (current, next) = if i % 2 == minutes % 2 {
122 (&mut t, &mut u)
123 } else {
124 (&mut u, &mut t)
125 };
126 for s in 0..n {
127 map.set_state(s);
128 let pos = map.pos;
129 let mut k = 0;
130 let ind = map.index[&pos];
131 let p = map.released_pressure();
132
133 // Try turning on the valve
134 if map.nodes[ind].rate > 0 && !map.nodes[ind].valve_on {
135 map.nodes[ind].valve_on = true;
136 k = max(k, p + next[map.get_state()]);
137 map.nodes[ind].valve_on = false;
138 }
139
140 // Try moving to a neighbor
141 for v in &map.nodes[ind].neighbors {
142 map.pos = *v;
143 k = max(k, p + next[map.get_state()]);
144 }
145 current[s] = k;
146 }
147 }
148 if 0 == minutes % 2 { t[0] } else { u[0] }
149 }
150*/
151
152 fn most_pressure(&self, minutes: usize) -> usize {
153 let n = self.state_max();
154 let mut t = vec![0 as usize; n];
155 let mut u = vec![0 as usize; n];
156 let mut map = self.clone();
157
158 // Setup table for last minute
159 for s in 0..n {
160 map.set_state(s);
161 t[s] = map.released_pressure();
162 }
163
164 // Dynamic programming counting back to 0 minutes
165 for i in (0..minutes).rev() {
166 // Double buffer technique so we don't have to swap vectors
167 let (current, next) = if i % 2 == minutes % 2 {
168 (&mut t, &mut u)
169 } else {
170 (&mut u, &mut t)
171 };
172 for s in 0..n {
173 map.set_state(s);
174 let pos = map.pos;
175 let mut k = 0;
176 let ind = map.index[&pos];
177 let p = map.released_pressure();
178
179 // Try turning on the valve
180 if map.nodes[ind].rate > 0 && !map.nodes[ind].valve_on {
181 map.nodes[ind].valve_on = true;
182 k = max(k, p + next[map.get_state()]);
183 map.nodes[ind].valve_on = false;
184 }
185
186 // Try moving to a neighbor
187 for v in &map.nodes[ind].neighbors {
188 map.pos = *v;
189 k = max(k, p + next[map.get_state()]);
190 }
191 current[s] = k;
192 }
193 }
194 if 0 == minutes % 2 { t[0] } else { u[0] }
195 }
196}
197
198impl PartialEq for Map {
199 fn eq(&self, other: &Self) -> bool {
200 self.get_state() == other.get_state()
201 }
202}
203
204impl Eq for Map {}
205
206impl Hash for Map {
207 fn hash<H: Hasher>(&self, hasher: &mut H) {
208 hasher.write_usize(self.get_state());
209 }
210}
211
212fn main() {
213 let map = Map::from_stdin();
214 let mut t = HashMap::<Map, usize>::new();
215 println!("{}", map.most_pressure(29, t));
216}

Generated with cgit - Back to sebastiano.tronto.net