summaryrefslogtreecommitdiffstats
path: root/2023/rs/code/three/src/main.rs
diff options
context:
space:
mode:
authoralyx <alyx@aleteoryx.me>2023-12-03 02:43:18 -0500
committeralyx <alyx@aleteoryx.me>2023-12-03 02:43:18 -0500
commit21880ee880d321e760b6b560db0696c8af4c98d9 (patch)
treee667793283963370efe40f16adfbec82847f0b8e /2023/rs/code/three/src/main.rs
parentcbea8d91895cd042df62a380bc672422e3837f42 (diff)
downloadadventofcode-21880ee880d321e760b6b560db0696c8af4c98d9.tar.gz
adventofcode-21880ee880d321e760b6b560db0696c8af4c98d9.tar.bz2
adventofcode-21880ee880d321e760b6b560db0696c8af4c98d9.zip
2023.3
Diffstat (limited to '2023/rs/code/three/src/main.rs')
-rw-r--r--2023/rs/code/three/src/main.rs96
1 files changed, 96 insertions, 0 deletions
diff --git a/2023/rs/code/three/src/main.rs b/2023/rs/code/three/src/main.rs
new file mode 100644
index 0000000..c72abe9
--- /dev/null
+++ b/2023/rs/code/three/src/main.rs
@@ -0,0 +1,96 @@
+#![feature(iter_map_windows)]
+
+use std::collections::BTreeSet;
+
+static INPUT: &[u8] = include_bytes!("input.txt");
+
+#[derive(Copy, Clone, Debug)]
+enum LineMaskEntry {
+ Empty,
+ Gear,
+ Number{tag: u32, num: u32}
+}
+
+fn main() {
+ let valueified = INPUT.split(|b| *b == b'\n').filter(|s| !s.is_empty());
+
+ let mut num = 0;
+
+ let (parts_number_sum, gears_mask) = [valueified.clone().next().unwrap()].into_iter().chain(valueified.clone()).chain([valueified.clone().last().unwrap()])
+ .map_windows::<_, _, 3>(|[prev, curr, next]| {
+ let mut numlen = 0;
+ let mut numval = 0;
+
+ let mut acc = 0;
+ let mut linemask = vec![LineMaskEntry::Empty; curr.len()];
+
+ for i in 0..curr.len() {
+ if curr[i] == b'*' { linemask[i] = LineMaskEntry::Gear; }
+
+ if !curr[i].is_ascii_digit() && numlen != 0 {
+ let start = if i - numlen == 0 { i - numlen } else { i - numlen - 1 };
+ let end = i;
+ let window = || start..=end;
+ if prev[window()].into_iter().chain(&curr[window()]).chain(&next[window()]).any(|b| !b.is_ascii_digit() && *b != b'.') {
+ acc += numval;
+
+ linemask[i - numlen .. i].fill(LineMaskEntry::Number{ tag: num, num: numval });
+ num += 1;
+ }
+
+ numlen = 0;
+ numval = 0;
+ }
+ else if curr[i].is_ascii_digit() {
+ numlen += 1;
+ numval *= 10;
+ numval += (curr[i] - b'0') as u32;
+ }
+ }
+
+ if numlen != 0 {
+ let window = || curr.len() - numlen - 1..curr.len();
+ if prev[window()].into_iter().chain(&curr[window()]).chain(&next[window()]).any(|b| !b.is_ascii_digit() && *b != b'.') {
+ acc += numval;
+
+ linemask[curr.len() - numlen .. curr.len()].fill(LineMaskEntry::Number{ tag: num, num: numval });
+ num += 1;
+ }
+ }
+ (acc, linemask)
+ }).fold((0, Vec::new()), |(n, mut v), (a, l)| (n + a, {v.push(l); v}));
+ println!("Sum of valid part numbers: {parts_number_sum}");
+
+
+ let first = vec![LineMaskEntry::Empty; gears_mask[0].len()];
+ let last = first.clone();
+ let gear_ratio_sum = [first].into_iter().chain(gears_mask).chain([last])
+ .map_windows::<_, _, 3>(|[prev, curr, next]| {
+ let mut acc = 0;
+
+ for i in 0..curr.len() {
+ match curr[i] {
+ LineMaskEntry::Gear => {
+ let mut set = BTreeSet::new();
+ for row in [prev, curr, next] {
+ for n in [i - 1, i, i + 1] {
+ if n == 0 || n == row.len() { continue; }
+ if let LineMaskEntry::Number{tag, num} = row[n] {
+ set.insert((tag, num));
+ }
+ }
+ }
+ if set.len() == 2 {
+ let mut iter = set.into_iter();
+ let x = iter.next().unwrap().1;
+ let y = iter.next().unwrap().1;
+ acc += x * y
+ }
+ },
+ _ => ()
+ }
+ }
+ acc
+ }).sum::<u32>();
+ println!("Gear ratio sum: {gear_ratio_sum}");
+}