diff --git a/rs/src/day10.rs b/rs/src/day10.rs index b8ed0ae6..adf38292 100644 --- a/rs/src/day10.rs +++ b/rs/src/day10.rs @@ -11,19 +11,19 @@ enum Direction { } #[dynamic] -static LUT: BTreeMap<(Direction, char), Direction> = [ - ((Direction::U, '|'), Direction::U), - ((Direction::U, '7'), Direction::L), - ((Direction::U, 'F'), Direction::R), - ((Direction::L, '-'), Direction::L), - ((Direction::L, 'F'), Direction::D), - ((Direction::L, 'L'), Direction::U), - ((Direction::D, '|'), Direction::D), - ((Direction::D, 'L'), Direction::R), - ((Direction::D, 'J'), Direction::L), - ((Direction::R, '-'), Direction::R), - ((Direction::R, 'J'), Direction::U), - ((Direction::R, '7'), Direction::D), +static LUT: BTreeMap<(Direction, u8), Direction> = [ + ((Direction::U, b'|'), Direction::U), + ((Direction::U, b'7'), Direction::L), + ((Direction::U, b'F'), Direction::R), + ((Direction::L, b'-'), Direction::L), + ((Direction::L, b'F'), Direction::D), + ((Direction::L, b'L'), Direction::U), + ((Direction::D, b'|'), Direction::D), + ((Direction::D, b'L'), Direction::R), + ((Direction::D, b'J'), Direction::L), + ((Direction::R, b'-'), Direction::R), + ((Direction::R, b'J'), Direction::U), + ((Direction::R, b'7'), Direction::D), ] .into(); @@ -36,10 +36,10 @@ fn step((y, x): (usize, usize), dir: Direction) -> Option<(usize, usize)> { }) } -fn part1_helper(maze: &[&str]) -> Option> { +fn part1_helper(maze: &[&[u8]]) -> Option> { for (y, line) in maze.iter().enumerate() { - for (x, char) in line.char_indices() { - if char != 'S' { + for (x, char) in line.iter().enumerate() { + if *char != b'S' { continue; } let start_pos = (y, x); @@ -47,8 +47,7 @@ fn part1_helper(maze: &[&str]) -> Option> { let mut pos = start_pos; let mut path = iter::from_fn(|| { pos = step(pos, dir)?; - dir = - *LUT.get(&(dir, maze[pos.0..].iter().next()?[pos.1..].chars().next()?))?; + dir = *LUT.get(&(dir, maze[pos.0][pos.1]))?; Some(pos) }) .collect::>(); @@ -63,11 +62,11 @@ fn part1_helper(maze: &[&str]) -> Option> { } pub fn part1(data: &str) -> Option { - Some(part1_helper(&data.lines().collect::>())?.len() / 2) + Some(part1_helper(&data.lines().map(|line| line.as_bytes()).collect::>())?.len() / 2) } pub fn part2(data: &str) -> Option { - let path = part1_helper(&data.lines().collect::>())?; + let path = part1_helper(&data.lines().map(|line| line.as_bytes()).collect::>())?; let (n, m) = path .iter() .zip(path[1..].iter().chain(path.iter())) diff --git a/rs/src/day11.rs b/rs/src/day11.rs index 7d6ce9c7..d9162109 100644 --- a/rs/src/day11.rs +++ b/rs/src/day11.rs @@ -1,26 +1,22 @@ fn solve(data: &str, n: usize) -> usize { - let lines = data.lines().collect::>(); + let mut counts = Vec::::new(); solve1( - &lines - .iter() - .map(|line| line.chars().filter(|&c| c == '#').count()) - .collect::>(), - n, - ) + solve1( - &(0..lines - .iter() - .map(|line| line.len()) - .max() - .unwrap_or_default()) - .map(|x| { - lines - .iter() - .filter(|line| line[x..].starts_with('#')) - .count() + &data + .lines() + .map(|line| { + let mut count = 0; + counts.extend(std::iter::repeat(0).take(line.len()).skip(counts.len())); + for (i, c) in line.char_indices() { + if c == '#' { + counts[i] += 1; + count += 1; + } + } + count }) .collect::>(), n, - ) + ) + solve1(&counts, n) } fn solve1(data: &[usize], n: usize) -> usize { diff --git a/rs/src/day12.rs b/rs/src/day12.rs index 61af5337..f5a446a1 100644 --- a/rs/src/day12.rs +++ b/rs/src/day12.rs @@ -8,7 +8,8 @@ fn solve(line: &str) -> Option { .map(|x| x.parse::().ok()) .collect::>>()?; let string = Itertools::intersperse([&lhs; N].into_iter(), &"?") - .flat_map(|s| s.chars()) + .flat_map(|s| s.as_bytes()) + .copied() .collect::>(); let runs = [&rhs; N].into_iter().flatten().copied().collect::>(); let last_run = runs.last()?; @@ -16,9 +17,9 @@ fn solve(line: &str) -> Option { (0..string.len()) .map(|i| { if i + last_run > string.len() - || i != 0 && string[i - 1] == '#' - || string[i..i + last_run].iter().any(|&c| c == '.') - || string[i + last_run..].iter().any(|&c| c == '#') + || i != 0 && string[i - 1] == b'#' + || string[i..i + last_run].iter().any(|&c| c == b'.') + || string[i + last_run..].iter().any(|&c| c == b'#') { 0 } else { @@ -30,9 +31,9 @@ fn solve(line: &str) -> Option { (0..string.len()) .map(|i| { if i + run >= string.len() - || i != 0 && string[i - 1] == '#' - || string[i..i + run].iter().any(|&c| c == '.') - || string[i + run] == '#' + || i != 0 && string[i - 1] == b'#' + || string[i..i + run].iter().any(|&c| c == b'.') + || string[i + run] == b'#' { 0 } else { @@ -41,8 +42,8 @@ fn solve(line: &str) -> Option { .zip( string[i + run + 1..] .iter() - .take_while(|&&c| c != '#') - .chain([&'#']), + .take_while(|&&c| c != b'#') + .chain([&b'#']), ) .map(|(&count, _)| count) .sum() @@ -54,7 +55,7 @@ fn solve(line: &str) -> Option { Some( counts .into_iter() - .zip(string.into_iter().take_while(|&c| c != '#').chain(['#'])) + .zip(string.into_iter().take_while(|&c| c != b'#').chain([b'#'])) .map(|(count, _)| count) .sum(), ) diff --git a/rs/src/day13.rs b/rs/src/day13.rs index b587f08d..ad81699f 100644 --- a/rs/src/day13.rs +++ b/rs/src/day13.rs @@ -4,19 +4,14 @@ fn find_reflection bool>(data: &[T], eq: F) -> usize .unwrap_or_default() } -fn solve bool>(lines: &[&str], eq: F) -> usize { +fn solve bool>(lines: &[&[u8]], eq: F) -> usize { let width = lines .iter() .map(|line| line.len()) .max() .unwrap_or_default(); let transpose = (0..width) - .map(|i| { - lines - .iter() - .flat_map(|line| line[i..i + 1].chars()) - .collect::() - }) + .map(|i| lines.iter().map(|line| line[i]).collect::>()) .collect::>(); let transpose = transpose.iter().map(|line| &line[..]).collect::>(); @@ -26,9 +21,13 @@ fn solve bool>(lines: &[&str], eq: F) -> usize { pub fn part1(data: &str) -> usize { data.split("\n\n") .map(|group| { - solve(&group.lines().collect::>(), |x, y| { - x.iter().rev().zip(y.iter()).all(|(a, b)| a == b) - }) + solve( + &group + .lines() + .map(|line| line.as_bytes()) + .collect::>(), + |x, y| x.iter().rev().zip(y.iter()).all(|(a, b)| a == b), + ) }) .sum() } @@ -36,14 +35,20 @@ pub fn part1(data: &str) -> usize { pub fn part2(data: &str) -> usize { data.split("\n\n") .map(|group| { - solve(&group.lines().collect::>(), |x, y| { - let mut iter = x - .iter() - .rev() - .zip(y.iter()) - .flat_map(|(a, b)| a.chars().zip(b.chars()).filter(|(c, d)| c != d)); - iter.next().is_some() && iter.next().is_none() - }) + solve( + &group + .lines() + .map(|line| line.as_bytes()) + .collect::>(), + |x, y| { + let mut iter = x + .iter() + .rev() + .zip(y.iter()) + .flat_map(|(a, b)| a.iter().zip(b.iter()).filter(|(c, d)| c != d)); + iter.next().is_some() && iter.next().is_none() + }, + ) }) .sum() } diff --git a/rs/src/day16.rs b/rs/src/day16.rs index b0bd5c84..8b0c6edb 100644 --- a/rs/src/day16.rs +++ b/rs/src/day16.rs @@ -12,21 +12,21 @@ enum Direction { } #[dynamic] -static LUT: BTreeMap<(Direction, char), &'static [Direction]> = { +static LUT: BTreeMap<(Direction, u8), &'static [Direction]> = { static DIRECTIONS: [Direction; 4] = [Direction::U, Direction::D, Direction::L, Direction::R]; [ - ((Direction::U, '/'), &DIRECTIONS[3..4]), - ((Direction::U, '\\'), &DIRECTIONS[2..3]), - ((Direction::U, '-'), &DIRECTIONS[2..4]), - ((Direction::L, '/'), &DIRECTIONS[1..2]), - ((Direction::L, '\\'), &DIRECTIONS[0..1]), - ((Direction::L, '|'), &DIRECTIONS[0..2]), - ((Direction::D, '/'), &DIRECTIONS[2..3]), - ((Direction::D, '\\'), &DIRECTIONS[3..4]), - ((Direction::D, '-'), &DIRECTIONS[2..4]), - ((Direction::R, '/'), &DIRECTIONS[0..1]), - ((Direction::R, '\\'), &DIRECTIONS[1..2]), - ((Direction::R, '|'), &DIRECTIONS[0..2]), + ((Direction::U, b'/'), &DIRECTIONS[3..4]), + ((Direction::U, b'\\'), &DIRECTIONS[2..3]), + ((Direction::U, b'-'), &DIRECTIONS[2..4]), + ((Direction::L, b'/'), &DIRECTIONS[1..2]), + ((Direction::L, b'\\'), &DIRECTIONS[0..1]), + ((Direction::L, b'|'), &DIRECTIONS[0..2]), + ((Direction::D, b'/'), &DIRECTIONS[2..3]), + ((Direction::D, b'\\'), &DIRECTIONS[3..4]), + ((Direction::D, b'-'), &DIRECTIONS[2..4]), + ((Direction::R, b'/'), &DIRECTIONS[0..1]), + ((Direction::R, b'\\'), &DIRECTIONS[1..2]), + ((Direction::R, b'|'), &DIRECTIONS[0..2]), ] .into() }; @@ -40,14 +40,11 @@ fn step(y: usize, x: usize, dir: Direction) -> Option<(usize, usize)> { }) } -fn fill(data: &[&str], y: usize, x: usize, d: Direction) -> Option { +fn fill(data: &[&[u8]], y: usize, x: usize, d: Direction) -> Option { let mut stack = vec![(y, x, d)]; let mut visited = stack.iter().copied().collect::>(); while let Some((y, x, d)) = stack.pop() { - for &d in *LUT - .get(&(d, data[y][x..].chars().next()?)) - .unwrap_or(&&[d][..]) - { + for &d in *LUT.get(&(d, data[y][x])).unwrap_or(&&[d][..]) { let Some((y, x)) = step(y, x, d) else { continue; }; @@ -66,11 +63,16 @@ fn fill(data: &[&str], y: usize, x: usize, d: Direction) -> Option { } pub fn part1(data: &str) -> Option { - fill(&data.lines().collect::>(), 0, 0, Direction::R) + fill( + &data.lines().map(|line| line.as_bytes()).collect::>(), + 0, + 0, + Direction::R, + ) } pub fn part2(data: &str) -> Option { - let data = data.lines().collect::>(); + let data = data.lines().map(|line| line.as_bytes()).collect::>(); (0..data.len()) .map(|y| (y, 0, Direction::R)) .chain((0..data.first()?.len()).map(|x| (0, x, Direction::D))) diff --git a/rs/src/day17.rs b/rs/src/day17.rs index c5040ca6..12c499d9 100644 --- a/rs/src/day17.rs +++ b/rs/src/day17.rs @@ -42,7 +42,7 @@ where P: Fn(usize) -> bool, F: Fn(Direction, usize) -> T, T: IntoIterator, - ::Item: Into, + T::Item: Into, { let maze = data .lines() diff --git a/rs/src/day19.rs b/rs/src/day19.rs index b2e6a5d5..6a805038 100644 --- a/rs/src/day19.rs +++ b/rs/src/day19.rs @@ -3,32 +3,33 @@ use std::collections::HashMap; type Comparison = (char, Ordering, u32); type Rule<'a> = Vec<(&'a str, Option)>; +type Point = (T, T, T, T); -#[derive(Clone, Debug)] -struct Point { - x: T, - m: T, - a: T, - s: T, +trait Index { + type Item; + fn get(&self, key: char) -> Option<&Self::Item>; + fn get_mut(&mut self, key: char) -> Option<&mut Self::Item>; } -impl Point { - fn get(&self, key: char) -> Option<&T> { +impl Index for Point { + type Item = T; + + fn get(&self, key: char) -> Option<&Self::Item> { match key { - 'x' => Some(&self.x), - 'm' => Some(&self.m), - 'a' => Some(&self.a), - 's' => Some(&self.s), + 'x' => Some(&self.0), + 'm' => Some(&self.1), + 'a' => Some(&self.2), + 's' => Some(&self.3), _ => None, } } - fn get_mut(&mut self, key: char) -> Option<&mut T> { + fn get_mut(&mut self, key: char) -> Option<&mut Self::Item> { match key { - 'x' => Some(&mut self.x), - 'm' => Some(&mut self.m), - 'a' => Some(&mut self.a), - 's' => Some(&mut self.s), + 'x' => Some(&mut self.0), + 'm' => Some(&mut self.1), + 'a' => Some(&mut self.2), + 's' => Some(&mut self.3), _ => None, } } @@ -79,12 +80,7 @@ fn parse_point(line: &str) -> Option> { return None; } } - Some(Point { - x: x?, - m: m?, - a: a?, - s: s?, - }) + Some((x?, m?, a?, s?)) } pub fn part1(data: &str) -> u32 { @@ -110,7 +106,7 @@ pub fn part1(data: &str) -> u32 { .0; } if name == "A" { - Some(point.x + point.m + point.a + point.s) + Some(point.0 + point.1 + point.2 + point.3) } else { None } @@ -119,51 +115,42 @@ pub fn part1(data: &str) -> u32 { } fn part2_helper(rules: &HashMap<&str, Rule>, name: &str, bounds: Point<(u32, u32)>) -> u64 { - let Point { - x: (x0, x1), - m: (m0, m1), - a: (a0, a1), - s: (s0, s1), - } = bounds; + let ((x0, x1), (m0, m1), (a0, a1), (s0, s1)) = bounds; if x0 > x1 || m0 > m1 || a0 > a1 || s0 > s1 { return 0; } if name == "A" { - return (x1 - x0 + 1) as u64 - * (m1 - m0 + 1) as u64 - * (a1 - a0 + 1) as u64 - * (s1 - s0 + 1) as u64; + return u64::from(x1 - x0 + 1) + * u64::from(m1 - m0 + 1) + * u64::from(a1 - a0 + 1) + * u64::from(s1 - s0 + 1); } let Some(rule) = rules.get(name) else { return 0; }; rule.iter() - .scan( - Some(bounds.clone()), - |st, &(name, comparison)| -> Option { - let Some((key, ordering, value)) = comparison else { - return Some(part2_helper(rules, name, st.take()?)); - }; - let mut bounds = st.clone()?; - let Some(((lo0, hi0), (lo1, hi1))) = - bounds.get_mut(key).zip(st.as_mut()?.get_mut(key)) - else { - return Some(0); - }; - if ordering < Ordering::Greater { - *hi0 = min(*hi0, value - 1); - *lo1 = max(*lo1, value); - } - if ordering > Ordering::Less { - *lo0 = max(*lo0, value + 1); - *hi1 = min(*hi1, value); - } - if lo1 > hi1 { - *st = None; - } - Some(part2_helper(rules, name, bounds)) - }, - ) + .scan(Some(bounds), |st, &(name, comparison)| -> Option { + let Some((key, ordering, value)) = comparison else { + return Some(part2_helper(rules, name, st.take()?)); + }; + let mut bounds = (*st)?; + let Some(((lo0, hi0), (lo1, hi1))) = bounds.get_mut(key).zip(st.as_mut()?.get_mut(key)) + else { + return Some(0); + }; + if ordering < Ordering::Greater { + *hi0 = min(*hi0, value - 1); + *lo1 = max(*lo1, value); + } + if ordering > Ordering::Less { + *lo0 = max(*lo0, value + 1); + *hi1 = min(*hi1, value); + } + if lo1 > hi1 { + *st = None; + } + Some(part2_helper(rules, name, bounds)) + }) .sum() } @@ -175,12 +162,7 @@ pub fn part2(data: &str) -> u64 { .map_while(parse_rule) .collect::>(), "in", - Point { - x: (1, 4000), - m: (1, 4000), - a: (1, 4000), - s: (1, 4000), - }, + ((1, 4000), (1, 4000), (1, 4000), (1, 4000)), ) }