summaryrefslogtreecommitdiffstats
path: root/src/bin
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2023-12-03 00:47:43 -0500
committerJesse Luehrs <doy@tozt.net>2023-12-03 00:47:43 -0500
commit6c05e1f8daffabd71be5aac7c0bc9d7586b5c359 (patch)
treedd619560f7a8aad91e30ca068df1e7b6b6d59ccf /src/bin
parentf6a8a5ef3ecb69962ca2dbd09327639bd959dc8f (diff)
downloadadvent-of-code-6c05e1f8daffabd71be5aac7c0bc9d7586b5c359.tar.gz
advent-of-code-6c05e1f8daffabd71be5aac7c0bc9d7586b5c359.zip
day 3
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/2023/day3.rs114
-rw-r--r--src/bin/2023/main.rs2
2 files changed, 116 insertions, 0 deletions
diff --git a/src/bin/2023/day3.rs b/src/bin/2023/day3.rs
new file mode 100644
index 0000000..2f7dcb0
--- /dev/null
+++ b/src/bin/2023/day3.rs
@@ -0,0 +1,114 @@
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+use advent_of_code::prelude::*;
+
+pub fn parse(fh: File) -> Result<Grid<u8>> {
+ Ok(parse::grid(parse::raw_lines(fh), |c, _, _| c))
+}
+
+pub fn part1(schematic: Grid<u8>) -> Result<i64> {
+ let mut numbers = vec![];
+ for row in schematic.each_row() {
+ let mut current_number = None;
+ for col in schematic.each_col() {
+ let c = schematic[row][col];
+ if c.is_ascii_digit() {
+ match current_number {
+ Some(n) => {
+ current_number = Some(n * 10 + i64::from(c - b'0'))
+ }
+ None => current_number = Some(i64::from(c - b'0')),
+ }
+ } else if let Some(n) = current_number.take() {
+ numbers.push((n, row, col));
+ }
+ }
+ if let Some(n) = current_number.take() {
+ numbers.push((n, row, schematic.cols()));
+ }
+ }
+
+ let mut total = 0;
+ 'number: for (n, row, col) in numbers {
+ let len = n.ilog10() + 1;
+ for offset in 0..=n.ilog10() {
+ let col = Col(col.0 - usize::try_from(offset).unwrap() - 1);
+ for (row, col) in schematic.adjacent(row, col, true) {
+ let c = schematic[row][col];
+ if !c.is_ascii_digit() && c != b'.' {
+ total += n;
+ continue 'number;
+ }
+ }
+ }
+ }
+
+ Ok(total)
+}
+
+pub fn part2(schematic: Grid<u8>) -> Result<i64> {
+ let mut numbers = vec![];
+ for row in schematic.each_row() {
+ let mut current_number = None;
+ for col in schematic.each_col() {
+ let c = schematic[row][col];
+ if c.is_ascii_digit() {
+ match current_number {
+ Some(n) => {
+ current_number = Some(n * 10 + i64::from(c - b'0'))
+ }
+ None => current_number = Some(i64::from(c - b'0')),
+ }
+ } else if let Some(n) = current_number.take() {
+ numbers.push((n, row, col));
+ }
+ }
+ if let Some(n) = current_number.take() {
+ numbers.push((n, row, schematic.cols()));
+ }
+ }
+
+ let mut gears: HashMap<_, HashSet<_>> = HashMap::new();
+ for (n, nrow, ncol) in numbers {
+ let len = n.ilog10() + 1;
+ for offset in 0..=n.ilog10() {
+ for (grow, gcol) in schematic.adjacent(
+ nrow,
+ Col(ncol.0 - usize::try_from(offset).unwrap() - 1),
+ true,
+ ) {
+ let c = schematic[grow][gcol];
+ if c == b'*' {
+ gears
+ .entry((grow, gcol))
+ .or_default()
+ .insert((n, nrow, ncol));
+ }
+ }
+ }
+ }
+
+ Ok(gears
+ .values()
+ .filter_map(|s| {
+ if s.len() == 2 {
+ Some(s.iter().map(|(n, _, _)| n).product::<i64>())
+ } else {
+ None
+ }
+ })
+ .sum())
+}
+
+#[test]
+fn test() {
+ assert_eq!(
+ part1(parse(parse::data(2023, 3).unwrap()).unwrap()).unwrap(),
+ 540212
+ );
+ assert_eq!(
+ part2(parse(parse::data(2023, 3).unwrap()).unwrap()).unwrap(),
+ 87605697
+ );
+}
diff --git a/src/bin/2023/main.rs b/src/bin/2023/main.rs
index cb9aa54..652bf26 100644
--- a/src/bin/2023/main.rs
+++ b/src/bin/2023/main.rs
@@ -13,6 +13,7 @@ use advent_of_code::prelude::*;
mod day1;
mod day2;
+mod day3;
// NEXT MOD
#[paw::main]
@@ -21,6 +22,7 @@ fn main(opt: Opt) -> Result<()> {
match opt.day {
1 => advent_of_code::day!(2023, opt.day, opt.puzzle, day1),
2 => advent_of_code::day!(2023, opt.day, opt.puzzle, day2),
+ 3 => advent_of_code::day!(2023, opt.day, opt.puzzle, day3),
// NEXT PART
_ => panic!("unknown day {}", opt.day),
}