diff --git a/src/all/d4.rs b/src/all/d4.rs index 32da52c..71c2e6d 100644 --- a/src/all/d4.rs +++ b/src/all/d4.rs @@ -8,7 +8,7 @@ pub fn p1_brute(input: String) -> u32 { let mut count = 0; for (index, _) in input.match_indices('X') { - let loc = grid.index_to_loc(index).unwrap(); + let loc = grid.shape.index_to_loc(index).unwrap(); for &dir in DirectBoth::ALL { let mut iter = loc.direct_iter(dir, &grid).skip(1).take(3).map(|loc| grid.get(loc)); let chars: [_; 3] = array::from_fn(|_| iter.next().flatten()); @@ -27,7 +27,7 @@ pub fn p2_brute(input: String) -> u32 { let mut count = 0; for (index, _) in input.match_indices('A') { - let loc = grid.index_to_loc(index).unwrap(); + let loc = grid.shape.index_to_loc(index).unwrap(); let matched = [ [DirectDiagonal::LeftUp, DirectDiagonal::RightDown], [DirectDiagonal::RightUp, DirectDiagonal::LeftDown], diff --git a/src/all/d6.rs b/src/all/d6.rs index 42c9dec..5f9b515 100644 --- a/src/all/d6.rs +++ b/src/all/d6.rs @@ -15,12 +15,12 @@ trait LocCounter { fn p1_ticked(input: String) -> u32 { let grid = GridView::new(&input); - let mut loc = grid.index_to_loc(input.find('^').unwrap()).unwrap(); + let mut loc = grid.shape.index_to_loc(input.find('^').unwrap()).unwrap(); let mut direct = DirectTaxicab::Up; let mut collector = CollectorT::new(input.len()); 'ticks: loop { - collector.insert(|| loc, || grid.loc_to_index(loc)); + collector.insert(|| loc, || grid.shape.loc_to_index(loc)); 'directs: loop { match loc.direct(direct, &grid) { @@ -124,7 +124,7 @@ fn is_looping( let mut direct = DirectTaxicab::Up; 'ticks: loop { - if det.insert(|| loc, || grid.loc_to_index(loc), direct) == IsLooped::Repeating { + if det.insert(|| loc, || grid.shape.loc_to_index(loc), direct) == IsLooped::Repeating { return true; } @@ -154,7 +154,7 @@ fn p2_brute(input: String) -> u32 { let input = input.into_bytes(); let mut grid = GridView::new(input); - let initial = grid.index_to_loc(initial_index).unwrap(); + let initial = grid.shape.index_to_loc(initial_index).unwrap(); let mut count = 0; for index in 0..size { diff --git a/src/all/d7.rs b/src/all/d7.rs index 3ccbfbc..ba4a73f 100644 --- a/src/all/d7.rs +++ b/src/all/d7.rs @@ -1,9 +1,9 @@ use std::iter; -fn fast_parse_once(input: &[u8]) -> Option<(&[u8], u64)> { +fn fast_parse_once(input: &[u8], delim: u8) -> Option<(&[u8], u64)> { let mut buf = input; let mut output = 0; - while buf.first().is_some_and(u8::is_ascii_digit) { + while buf.first().is_some_and(|&digit| digit != delim) { output *= 10; let (&first, rest) = buf.split_first().unwrap(); output += u64::from(first - b'0'); @@ -17,11 +17,11 @@ fn fast_parse_once(input: &[u8]) -> Option<(&[u8], u64)> { } } -fn fast_parse_once_reverse(input: &[u8]) -> Option<(&[u8], Operand)> { +fn fast_parse_once_reverse(input: &[u8], delim: u8) -> Option<(&[u8], Operand)> { let mut buf = input; let mut output = 0; let mut unit = 1; - while buf.last().is_some_and(u8::is_ascii_digit) { + while buf.last().is_some_and(|&digit| digit != delim) { let (&last, rest) = buf.split_last().unwrap(); output += u64::from(last - b'0') * unit; unit *= 10; @@ -43,7 +43,7 @@ struct Operand<'a> { fn parse(input: &str) -> impl Iterator { input.lines().map(|line| { - let (operands, result) = fast_parse_once(line.as_bytes()).unwrap(); + let (operands, result) = fast_parse_once(line.as_bytes(), b':').unwrap(); Line { result, operands } }) } @@ -53,7 +53,10 @@ impl<'a> Line<'a> { let mut operands = self.operands; iter::from_fn(move || { operands = operands.trim_ascii_end(); - let (rest, last) = fast_parse_once_reverse(operands)?; + if operands.last() == Some(&b':') { + return None; + } + let (rest, last) = fast_parse_once_reverse(operands, b' ')?; operands = rest; Some(last) }) @@ -102,7 +105,8 @@ pub fn p1_reversed(input: String) -> u64 { } // Try iterating from the back. -// Break early if unable to reverse addition (negative) or multiplication (not divisible). +// Break early if unable to reverse addition (negative), +// concatenation (not divisible after subtraction) or multiplication (not divisible). fn is_valid_reverse_recurse_p2<'a>( result: u64, mut operands: impl Iterator> + Clone, @@ -138,7 +142,7 @@ fn is_valid_reverse_recurse_p2<'a>( } fn strip_base10_suffix<'a>(long: u64, suffix: Operand<'a>) -> Option { - let remain = long - suffix.value; + let remain = long.wrapping_sub(suffix.value); // works on "my input" let unit = 10u64.pow(suffix.bytes.len() as u32); if remain % unit == 0 { Some(remain / unit) diff --git a/src/util.rs b/src/util.rs index f134caa..50f4d21 100644 --- a/src/util.rs +++ b/src/util.rs @@ -5,6 +5,11 @@ use std::iter; #[derive(Clone, Copy)] pub struct GridView { pub input: Input, + pub shape: GridShape, +} + +#[derive(Clone, Copy)] +pub struct GridShape { pub width: u32, pub height: u32, } @@ -13,13 +18,15 @@ impl> GridView { pub fn new(input: Input) -> Self { let width = input.as_ref().iter().position(|&b| b == b'\n').unwrap() as u32 + 1; let height = (input.as_ref().len() as u32).div_ceil(width); - Self { input, width, height } + Self { input, shape: GridShape{width, height} } } pub fn get(&self, loc: GridLoc) -> Option { - self.input.as_ref().get(self.loc_to_index(loc) as usize).copied() + self.input.as_ref().get(self.shape.loc_to_index(loc) as usize).copied() } +} +impl GridShape { pub fn loc_to_index(&self, loc: GridLoc) -> u32 { loc.y * self.width + loc.x } @@ -35,6 +42,18 @@ impl> GridView { } } +impl From> for GridShape { + fn from(grid: GridView) -> Self { + grid.shape + } +} + +impl<'a, Input> From<&'a GridView> for GridShape { + fn from(grid: &'a GridView) -> Self { + grid.shape + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct GridLoc { pub x: u32, @@ -43,21 +62,21 @@ pub struct GridLoc { impl GridLoc { pub fn left(self) -> Option { Some(Self { x: self.x.checked_sub(1)?, y: self.y }) } - pub fn right(self, grid: &GridView>) -> Option { + pub fn right(self, grid: impl Into) -> Option { Some(Self { x: match self.x.checked_add(1)? { - x if x < grid.width - 1 => x, + x if x < grid.into().width - 1 => x, _ => return None, }, y: self.y, }) } pub fn up(self) -> Option { Some(Self { x: self.x, y: self.y.checked_sub(1)? }) } - pub fn down(self, grid: &GridView>) -> Option { + pub fn down(self, grid: impl Into) -> Option { Some(Self { x: self.x, y: match self.y.checked_add(1)? { - y if y < grid.height => y, + y if y < grid.into().height => y, _ => return None, }, })