diff --git a/2024/Cargo.lock b/2024/Cargo.lock index 93301ed..3515154 100644 --- a/2024/Cargo.lock +++ b/2024/Cargo.lock @@ -179,6 +179,16 @@ dependencies = [ "nom", ] +[[package]] +name = "day08" +version = "0.1.0" +dependencies = [ + "divan", + "helper", + "nom", + "smallvec", +] + [[package]] name = "divan" version = "0.1.16" @@ -306,6 +316,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "strsim" version = "0.11.1" diff --git a/2024/day08/Cargo.toml b/2024/day08/Cargo.toml new file mode 100644 index 0000000..551b23f --- /dev/null +++ b/2024/day08/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "day08" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nom.workspace = true +helper.workspace = true +divan.workspace = true +smallvec = "1.13.2" + +[[bench]] +name = "benches" +harness = false diff --git a/2024/day08/benches/benches.rs b/2024/day08/benches/benches.rs new file mode 100644 index 0000000..dfd4798 --- /dev/null +++ b/2024/day08/benches/benches.rs @@ -0,0 +1,3 @@ +fn main() { + day08::bench(); +} diff --git a/2024/day08/input.txt b/2024/day08/input.txt new file mode 100644 index 0000000..4d86744 --- /dev/null +++ b/2024/day08/input.txt @@ -0,0 +1,50 @@ +...............................6.B..........P..... +n..............M.................................. +....n.....sM7.............................6.....p. +......................Mr......................P... +.......n.......................................p.E +.......................6...................p...... +r..............................C........B....P.... +.....................d........6......B4....P...... +.........................7....................4... +.n......................R..............4.......... +.....N........S.................K.C..........4.... +...........N..r.....................B....K........ +.................................................. +......N.......x.............7.......K.....2....E.. +...................r..H........R.................. +.....................s....p........C...........2.. +....3.......................M..................... +........k....................H....5............... +.....x....N................d.5..y................J +m.....................d7...................J...... +.......exk........................................ +.......x.............5.......R.................... +..........eY...................................... +...S.3..............................O.E...J....... +.......8...H....k...............J................. +......S.e.........C.H.....................X.....y. +................j..........y.........2............ +...........e.........k............................ +......YS...3..............5..........K...XR....... +...m..............j.s..........c.................. +.........................j........................ +...............j.................................. +.....m................................2........... +.........Y......................................b. +.................................................. +.......................h...........b.............. +............m......D..............d............... +........o......D.................................. +...................................O.............. +.................................................. +......8........................................... +........D.Y..o...................1................ +.....................................b..9......... +........................h..0...................... +.....o......................h..0........b1........ +.........8.............X.......................... +..........o..........c..........1...........O..... +....8....................y0...c................... +..............D.......c..................9..0..... +............................1..........O..9....... diff --git a/2024/day08/input_small.txt b/2024/day08/input_small.txt new file mode 100644 index 0000000..78a1e91 --- /dev/null +++ b/2024/day08/input_small.txt @@ -0,0 +1,12 @@ +............ +........0... +.....0...... +.......0.... +....0....... +......A..... +............ +............ +........A... +.........A.. +............ +............ diff --git a/2024/day08/src/lib.rs b/2024/day08/src/lib.rs new file mode 100644 index 0000000..6064ed0 --- /dev/null +++ b/2024/day08/src/lib.rs @@ -0,0 +1,330 @@ +use helper::{Day, Variants}; + +pub fn main() { + helper::main::(include_str!("../input.txt")); +} + +struct Day08; + +helper::define_variants! { + day => crate::Day08; + part1 { + basic => crate::part1; + asciicheck => crate::part1_asciicheck; + parsing => crate::part1_parsing; + vec_opts => crate::part1_vec_opts; + arrayvec => crate::part1_arrayvec; + } + part2 { + basic => crate::part2; + } +} + +impl Day for Day08 { + fn part1() -> Variants { + part1_variants!(construct_variants) + } + + fn part2() -> Variants { + part2_variants!(construct_variants) + } +} + +fn part1(input: &str) -> u64 { + let mut all_antennas = vec![vec![]; 128]; + + let mut height = 0; + let mut width = 0; + + for (row, line) in input.lines().enumerate() { + for (col, cell) in line.bytes().enumerate() { + if cell.is_ascii_alphanumeric() { + all_antennas[cell as usize].push((col, row)); + } + } + width = line.len(); + height += 1; + } + + let mut is_antinode = vec![false; width * height]; + + for antennas in all_antennas { + for &a in &antennas { + for &b in &antennas { + if a == b { + continue; + } + + let diff = (a.0 as i64 - b.0 as i64, a.1 as i64 - b.1 as i64); + let antinode = (a.0 as i64 + diff.0, a.1 as i64 + diff.1); + + if !(0..(width as i64)).contains(&antinode.0) { + continue; + } + if !(0..(height as i64)).contains(&antinode.1) { + continue; + } + + is_antinode[(antinode.0 as usize * width) + antinode.1 as usize] = true; + } + } + } + + is_antinode + .iter() + .filter(|is_antinode| **is_antinode) + .count() as u64 +} + +fn part1_asciicheck(input: &str) -> u64 { + let mut all_antennas = vec![vec![]; 128]; + + let mut height = 0; + let mut width = 0; + + for (row, line) in input.lines().enumerate() { + for (col, cell) in line.bytes().enumerate() { + if cell != b'.' { + all_antennas[cell as usize].push((col, row)); + } + } + width = line.len(); + height += 1; + } + + let mut is_antinode = vec![false; width * height]; + + for antennas in all_antennas { + for &a in &antennas { + for &b in &antennas { + if a == b { + continue; + } + + let diff = (a.0 as i64 - b.0 as i64, a.1 as i64 - b.1 as i64); + let antinode = (a.0 as i64 + diff.0, a.1 as i64 + diff.1); + + if !(0..(width as i64)).contains(&antinode.0) { + continue; + } + if !(0..(height as i64)).contains(&antinode.1) { + continue; + } + + is_antinode[(antinode.0 as usize * width) + antinode.1 as usize] = true; + } + } + } + + is_antinode + .iter() + .filter(|is_antinode| **is_antinode) + .count() as u64 +} + +fn part1_parsing(input: &str) -> u64 { + let mut all_antennas = vec![vec![]; 128]; + + let mut width = 0; + + let mut row = 0; + let mut col = 0; + for cell in input.bytes() { + if cell == b'\n' { + row += 1; + width = col; + col = 0; + } else if cell != b'.' { + all_antennas[cell as usize].push((col, row)); + col += 1; + } else { + col += 1; + } + } + + let height = row; + + let mut is_antinode = vec![false; width * height]; + + for antennas in all_antennas { + for &a in &antennas { + for &b in &antennas { + if a == b { + continue; + } + + let diff = (a.0 as i64 - b.0 as i64, a.1 as i64 - b.1 as i64); + let antinode = (a.0 as i64 + diff.0, a.1 as i64 + diff.1); + + if !(0..(width as i64)).contains(&antinode.0) { + continue; + } + if !(0..(height as i64)).contains(&antinode.1) { + continue; + } + + is_antinode[(antinode.0 as usize * width) + antinode.1 as usize] = true; + } + } + } + + is_antinode + .iter() + .filter(|is_antinode| **is_antinode) + .count() as u64 +} + +fn part1_vec_opts(input: &str) -> u64 { + let mut all_antennas = [const { vec![] }; 256]; + + let mut width = 0; + + let mut row = 0; + let mut col = 0; + for cell in input.bytes() { + if cell == b'\n' { + row += 1; + width = col; + col = 0; + } else if cell != b'.' { + all_antennas[cell as usize].push((col, row)); + col += 1; + } else { + col += 1; + } + } + + let height = row; + + let mut is_antinode = vec![false; width * height]; + let all_antennas = &all_antennas[b'0' as usize..b'z' as usize]; + + for antennas in all_antennas { + for &a in antennas { + for &b in antennas { + if a == b { + continue; + } + + let diff = (a.0 as i64 - b.0 as i64, a.1 as i64 - b.1 as i64); + let antinode = (a.0 as i64 + diff.0, a.1 as i64 + diff.1); + + if !(0..(width as i64)).contains(&antinode.0) { + continue; + } + if !(0..(height as i64)).contains(&antinode.1) { + continue; + } + + unsafe { + *is_antinode + .get_unchecked_mut((antinode.0 as usize * width) + antinode.1 as usize) = + true; + } + } + } + } + + is_antinode + .iter() + .filter(|is_antinode| **is_antinode) + .count() as u64 +} + +fn part1_arrayvec(input: &str) -> u64 { + type Coods = (usize, usize); + struct Arrayvec { + elems: [Coods; 8], + len: usize, + } + impl Arrayvec { + fn push(&mut self, elem: Coods) { + self.elems[self.len] = elem; + self.len += 1; + } + } + impl<'a> IntoIterator for &'a Arrayvec { + type IntoIter = std::slice::Iter<'a,Coods>; + type Item = &'a Coods; + fn into_iter(self) -> Self::IntoIter { + unsafe { self.elems.get_unchecked(0..self.len).iter() } + } + } + + let mut all_antennas = [const { + Arrayvec { + elems: [(0, 0); 8], + len: 0, + } + }; 256]; + + let mut width = 0; + + let mut row = 0; + let mut col = 0; + for cell in input.bytes() { + if cell == b'\n' { + row += 1; + width = col; + col = 0; + } else if cell != b'.' { + all_antennas[cell as usize].push((col, row)); + col += 1; + } else { + col += 1; + } + } + + let height = row; + + let mut is_antinode = vec![false; width * height]; + let all_antennas = &all_antennas[b'0' as usize..b'z' as usize]; + + for antennas in all_antennas { + for &a in antennas { + for &b in antennas { + if a == b { + continue; + } + + let diff = (a.0 as i64 - b.0 as i64, a.1 as i64 - b.1 as i64); + let antinode = (a.0 as i64 + diff.0, a.1 as i64 + diff.1); + + if !(0..(width as i64)).contains(&antinode.0) { + continue; + } + if !(0..(height as i64)).contains(&antinode.1) { + continue; + } + + unsafe { + *is_antinode + .get_unchecked_mut((antinode.0 as usize * width) + antinode.1 as usize) = + true; + } + } + } + } + + is_antinode + .iter() + .filter(|is_antinode| **is_antinode) + .count() as u64 +} + +fn part2(_input: &str) -> u64 { + 0 +} + +helper::tests! { + day08 Day08; + part1 { + small => 14; + default => 269; + } + part2 { + small => 34; + default => 0; + } +} +helper::benchmarks! {} diff --git a/2024/day08/src/main.rs b/2024/day08/src/main.rs new file mode 100644 index 0000000..4c8bcea --- /dev/null +++ b/2024/day08/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + day08::main(); +} diff --git a/helper/src/cmd.rs b/helper/src/cmd.rs index f3b7f64..ff097ac 100644 --- a/helper/src/cmd.rs +++ b/helper/src/cmd.rs @@ -40,6 +40,11 @@ pub fn main(default_input: &str) -> ! { } fn create_variant_subcommands(mut part: Command, variants: &[Variant]) -> Command { + let iter_arg = Arg::new("iter") + .long("iter") + .value_parser(value_parser!(usize)) + .default_value("1"); + if variants.len() > 1 { part = part.subcommand_required(true); @@ -49,13 +54,13 @@ fn create_variant_subcommands(mut part: Command, variants: &[Variant]) -> Comman Command::new(v.name) .about(format!("Run the {} variant", v.name)) .arg(Arg::new("input").short('i').long("input")) - .arg(Arg::new("iter").long("iter").value_parser(value_parser!(usize))) + .arg(iter_arg.clone()) }) .for_each(|cmd| part = part.clone().subcommand(cmd)); } else { part = part .arg(Arg::new("input").short('i').long("input")) - .arg(Arg::new("iter").long("iter").value_parser(value_parser!(usize))); + .arg(iter_arg); } part @@ -66,14 +71,14 @@ fn dispatch_root_subcommand( variants: &[Variant], matches: &ArgMatches, ) -> ! { - let iter = matches.get_one::("iter").unwrap_or(&1); - if variants.len() > 1 { - let subcommand = matches.subcommand().unwrap(); - let variant = variants.iter().find(|v| v.name == subcommand.0).unwrap(); - let input = get_input(subcommand.1, default_input); + let (subcommand, matches) = matches.subcommand().unwrap(); + let iter = matches.get_one::("iter").unwrap(); + let variant = variants.iter().find(|v| v.name == subcommand).unwrap(); + let input = get_input(matches, default_input); execute::(variant, &input, *iter); } else { + let iter = matches.get_one::("iter").unwrap(); let input = get_input(matches, default_input); execute::(&variants[0], &input, *iter); }