making 2023 a generic aoc repo

This commit is contained in:
Dylan Thies
2023-12-04 19:40:31 -05:00
parent 09f1da1295
commit 51cf3fa8e7
28 changed files with 2 additions and 2 deletions

12
2023/day-3/Cargo.toml Normal file
View File

@@ -0,0 +1,12 @@
[package]
name = "day-3"
version.workspace = true
edition.workspace = true
authors.workspace = true
repository.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
itertools.workspace = true
log.workspace = true

4
2023/day-3/src/lib.rs Normal file
View File

@@ -0,0 +1,4 @@
pub mod part1;
pub use crate::part1::*;
pub mod part2;
pub use crate::part2::*;

12
2023/day-3/src/main.rs Normal file
View File

@@ -0,0 +1,12 @@
#![warn(clippy::all, clippy::pedantic)]
use day_3::part1;
use day_3::part2;
fn main() {
let input = include_str!("./input.txt");
let part1_result = part1(input);
println!("part 1: {part1_result}");
let part2_result = part2(input);
println!("part 2: {part2_result}");
}

129
2023/day-3/src/part1.rs Normal file
View File

@@ -0,0 +1,129 @@
#![warn(clippy::all, clippy::pedantic)]
use std::collections::BTreeMap;
#[derive(Debug)]
struct SerialNumber {
pub no: u64,
pub start: (usize, usize),
pub end: (usize, usize),
}
impl SerialNumber {
fn generate_adjacent(&self) -> Vec<(usize, usize)> {
let start_row = if self.start.0 == 0 {
0
} else {
self.start.0 - 1
};
let start_line = if self.start.1 == 0 {
0
} else {
self.start.1 - 1
};
(start_row..=(self.end.0 + 1))
.flat_map(|x| (start_line..=(self.end.1 + 1)).map(move |y| (x, y)))
.collect()
}
}
#[must_use]
pub fn part1(input: &str) -> String {
let (serials, symbols) = parse_input(input);
serials
.iter()
.filter(|x| {
x.generate_adjacent()
.iter()
.any(|t| symbols.get(t).is_some())
})
.map(|x| x.no)
.sum::<u64>()
.to_string()
}
fn parse_input(input: &str) -> (Vec<SerialNumber>, BTreeMap<(usize, usize), char>) {
let mut numbers = Vec::new();
let mut symbols = BTreeMap::new();
for (line_no, line) in input.lines().enumerate() {
let mut prev_char = None;
let mut cur_no = 0_u64;
let mut cur_no_row_start = 0_usize;
for (row_no, c) in line.chars().enumerate() {
if let Some(d) = c.to_digit(10) {
if prev_char.is_some() {
cur_no = cur_no * 10 + u64::from(d);
} else {
cur_no = u64::from(d);
cur_no_row_start = row_no;
}
prev_char = Some(c);
} else {
if prev_char.is_some() {
//handle saving number off
numbers.push(SerialNumber {
no: cur_no,
start: (cur_no_row_start, line_no),
end: (row_no - 1, line_no),
});
}
prev_char = None;
if c == '.' {
//move along space
continue;
}
//store symbol
let _ = symbols.insert((row_no, line_no), c);
}
}
//need to account for new line numbers
if prev_char.is_some() {
numbers.push(SerialNumber {
no: cur_no,
start: (cur_no_row_start, line_no),
end: (line.len() - 1, line_no),
});
}
}
(numbers, symbols)
}
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..";
const INPUT2: &str = "12.......*..
+.........34
.......-12..
..78........
..*....60...
78.........9
.5.....23..$
8...90*12...
............
2.2......12.
.*.........*
1.1..503+.56";
#[test]
fn part1_works() {
let result = part1(INPUT);
assert_eq!(result, "4361".to_string());
}
#[test]
fn part1_works_more() {
let result = part1(INPUT2);
assert_eq!(result, "925".to_string());
}
}

113
2023/day-3/src/part2.rs Normal file
View File

@@ -0,0 +1,113 @@
#![warn(clippy::all, clippy::pedantic)]
use std::collections::BTreeMap;
#[derive(Debug)]
struct SerialNumber {
pub no: u64,
pub start: (usize, usize),
pub end: (usize, usize),
}
impl SerialNumber {
fn is_adjacent(&self, pos: (usize, usize)) -> bool {
usize::abs_diff(self.start.1, pos.1) < 2
&& self.start.0 < 2 + pos.0
&& pos.0 < 2 + self.end.0
}
}
#[must_use]
pub fn part2(input: &str) -> String {
let (serials, symbols) = parse_input(input);
symbols
.iter()
.filter_map(|(key, value)| if *value == '*' { Some(*key) } else { None })
.filter_map(|pos| {
let serials = serials
.iter()
.filter_map(|serial| {
if serial.is_adjacent(pos) {
Some(serial.no)
} else {
None
}
})
.collect::<Vec<u64>>();
if serials.len() == 2 {
Some(serials[0] * serials[1])
} else {
None
}
})
.sum::<u64>()
.to_string()
//find all serials next to '*' and map with '*' location
}
fn parse_input(input: &str) -> (Vec<SerialNumber>, BTreeMap<(usize, usize), char>) {
let mut numbers = Vec::new();
let mut symbols = BTreeMap::new();
for (line_no, line) in input.lines().enumerate() {
let mut prev_char = None;
let mut cur_no = 0_u64;
let mut cur_no_row_start = 0_usize;
for (row_no, c) in line.chars().enumerate() {
if let Some(d) = c.to_digit(10) {
if prev_char.is_some() {
cur_no = cur_no * 10 + u64::from(d);
} else {
cur_no = u64::from(d);
cur_no_row_start = row_no;
}
prev_char = Some(c);
} else {
if prev_char.is_some() {
//handle saving number off
numbers.push(SerialNumber {
no: cur_no,
start: (cur_no_row_start, line_no),
end: (row_no - 1, line_no),
});
}
prev_char = None;
if c == '.' {
//move along space
continue;
}
//store symbol
let _ = symbols.insert((row_no, line_no), c);
}
}
//need to account for new line numbers
if prev_char.is_some() {
numbers.push(SerialNumber {
no: cur_no,
start: (cur_no_row_start, line_no),
end: (line.len() - 1, line_no),
});
}
}
(numbers, symbols)
}
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..";
#[test]
fn part2_works() {
let result = part2(INPUT);
assert_eq!(result, "467835".to_string());
}
}