diff --git a/src/bin/d10p1.rs b/src/bin/d10p1.rs index 2bd224d..b4af7e6 100644 --- a/src/bin/d10p1.rs +++ b/src/bin/d10p1.rs @@ -1,6 +1,6 @@ use std::collections::{HashMap, HashSet, VecDeque}; -use advent_of_code_2024::{add_pair, make_main, mul_pair, next, nexti64, Pair, SResult}; +use advent_of_code_2024::{make_main, next, Pair, SResult}; make_main!(); diff --git a/src/bin/d11p1.rs b/src/bin/d11p1.rs index 6d29e88..629c803 100644 --- a/src/bin/d11p1.rs +++ b/src/bin/d11p1.rs @@ -1,6 +1,6 @@ -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::HashMap; -use advent_of_code_2024::{add_pair, make_main, mul_pair, next, nexti64, Pair, SResult}; +use advent_of_code_2024::{make_main, SResult}; make_main!(); diff --git a/src/bin/d12i1.txt b/src/bin/d12i1.txt new file mode 100644 index 0000000..cc5f968 --- /dev/null +++ b/src/bin/d12i1.txt @@ -0,0 +1,4 @@ +AAAA +BBCD +BBCC +EEEC \ No newline at end of file diff --git a/src/bin/d12i2.txt b/src/bin/d12i2.txt new file mode 100644 index 0000000..cc213c5 --- /dev/null +++ b/src/bin/d12i2.txt @@ -0,0 +1,5 @@ +OOOOO +OXOXO +OOOOO +OXOXO +OOOOO \ No newline at end of file diff --git a/src/bin/d12i3.txt b/src/bin/d12i3.txt new file mode 100644 index 0000000..26ada03 --- /dev/null +++ b/src/bin/d12i3.txt @@ -0,0 +1,5 @@ +EEEEE +EXXXX +EEEEE +EXXXX +EEEEE \ No newline at end of file diff --git a/src/bin/d12p1.rs b/src/bin/d12p1.rs index a684504..f827f11 100644 --- a/src/bin/d12p1.rs +++ b/src/bin/d12p1.rs @@ -1,13 +1,152 @@ -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::{HashMap, HashSet}; -use advent_of_code_2024::{add_pair, make_main, mul_pair, next, nexti64, Pair, SResult}; +use advent_of_code_2024::{make_main, next, Pair, SResult}; make_main!(); fn solve(lines: Vec) -> SResult<(usize, usize)> { - Ok((0, 0)) + let width = lines.len(); + let mut grid: Vec> = Vec::with_capacity(lines.len()); + for line in lines { + grid.push(line.trim().chars().collect()); + } + + let mut visited: HashSet = HashSet::new(); + let mut size = 0; + let mut size2 = 0; + for (i, row) in grid.iter().enumerate() { + for (j, _) in row.iter().enumerate() { + if visited.contains(&(i, j)) { + continue; + } + let section = fill(&grid, (i, j), &mut visited); + size += perim(width, §ion) * section.len(); + size2 += sides(width, §ion) * section.len(); + } + } + + // Find the regions + Ok((size, size2)) } +fn fill(grid: &[Vec], loc: Pair, global_visit: &mut HashSet) -> HashSet { + let mut stack = vec![loc]; + let mut visited = HashSet::new(); + visited.insert(loc); + global_visit.insert(loc); + let v = grid[loc.0][loc.1]; + + while let Some(loc) = stack.pop() { + for vel in [(0, 1), (0, -1), (-1, 0), (1, 0)] { + if let Some(loc2) = next(loc, vel, grid.len()) { + if grid[loc2.0][loc2.1] == v && !visited.contains(&loc2) { + global_visit.insert(loc2); + visited.insert(loc2); + stack.push(loc2); + } + } + } + } + + visited +} + +fn perim(width: usize, section: &HashSet) -> usize { + let mut perim = 0; + for loc in section.iter() { + if loc.0 == 0 || loc.0 + 1 == width { + perim += 1; + } + if loc.1 == 0 || loc.1 + 1 == width { + perim += 1; + } + for vel in [(0, 1), (0, -1), (-1, 0), (1, 0)] { + if let Some(loc2) = next(*loc, vel, width) { + if section.contains(&loc2) { + continue; + } + perim += 1; + } + } + } + perim +} + +fn sides(width: usize, section: &HashSet) -> usize { + let mut count = 0; + + // Organize things by x, and y + let mut by_x: HashMap> = HashMap::default(); + let mut by_y: HashMap> = HashMap::default(); + for pos in section.iter() { + by_x.entry(pos.0).or_insert_with(|| Vec::new()).push(*pos); + by_y.entry(pos.1).or_insert_with(|| Vec::new()).push(*pos); + } + + for (_, v) in by_x.iter_mut() { + v.sort_by(|a, b| a.1.cmp(&b.1)); + } + for (_, v) in by_y.iter_mut() { + v.sort_by(|a, b| a.0.cmp(&b.0)); + } + + for (x, v) in by_x { + // Check if we need fence on left/right + for vel in [(1, 0), (-1, 0)] { + let mut in_fence = false; + for pos in &v { + let mut need_fence = true; + // We don't need a fence if the next cell over is in the region + if let Some(x) = next(*pos, vel, width) { + if section.contains(&x) { + need_fence = false; + } + } + if in_fence != need_fence { + if need_fence { + count += 1; + } + in_fence = need_fence; + } + // If the next cell is not adjaent to us, we are not in fence + // when the next iteration starts + in_fence = in_fence && match next(*pos, (0, 1), width) { + Some(x) => section.contains(&x), + None => false, + }; + } + } + } + + for (y, v) in by_y { + for vel in [(0, 1), (0, -1)] { + let mut in_fence = false; + for pos in &v { + let mut need_fence = true; + // We don't need a fence if the next cell over is in the region + if let Some(x) = next(*pos, vel, width) { + if section.contains(&x) { + need_fence = false; + } + } + if in_fence != need_fence { + if need_fence { + count += 1; + } + in_fence = need_fence; + } + // If the next cell is not adjaent to us, we are not in fence + // when the next iteration starts + in_fence = in_fence && match next(*pos, (1, 0), width) { + // We are still in the fance + Some(x) => section.contains(&x), + None => false, + }; + } + } + } + count +} #[cfg(test)] mod tests { @@ -16,8 +155,29 @@ mod tests { use super::*; #[test] fn sample_input() { - let strings: Vec = input!("d11p1.txt"); + let strings: Vec = input!("d12p1.txt"); let got = solve(strings).unwrap(); - assert_eq!(got, (0, 0)); + assert_eq!(got, (1930, 1206)); + } + + #[test] + fn sample_input2() { + let strings: Vec = input!("d12i1.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (140, 80)); + } + + #[test] + fn sample_input3() { + let strings: Vec = input!("d12i2.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (772, 436)); + } + + #[test] + fn sample_input4() { + let strings: Vec = input!("d12i3.txt"); + let got = solve(strings).unwrap(); + assert_eq!(got, (692, 236)); } } diff --git a/src/bin/d12p1.txt b/src/bin/d12p1.txt new file mode 100644 index 0000000..0b328f1 --- /dev/null +++ b/src/bin/d12p1.txt @@ -0,0 +1,10 @@ +RRRRIICCFF +RRRRIICCCF +VVRRRCCFFF +VVRCCCJFFF +VVVVCJJCFE +VVIVCCJJEE +VVIIICJJEE +MIIIIIJJEE +MIIISIJEEE +MMMISSJEEE \ No newline at end of file diff --git a/src/bin/d7p1.rs b/src/bin/d7p1.rs index 18436ab..4309c30 100644 --- a/src/bin/d7p1.rs +++ b/src/bin/d7p1.rs @@ -173,7 +173,7 @@ fn take_one(s: &str) -> PResult { Ok((chars.as_str(), c)) } -fn take_while<'a, F: Fn(char) -> bool>(mut s: &'a str, f: F) -> PResult<&'a str> { +fn take_while<'a, F: Fn(char) -> bool>(s: &'a str, f: F) -> PResult<&'a str> { let og = s; let mut mid = 0; let mut chars = s.chars(); diff --git a/src/bin/d8p1.rs b/src/bin/d8p1.rs index c802985..8d4812c 100644 --- a/src/bin/d8p1.rs +++ b/src/bin/d8p1.rs @@ -1,6 +1,6 @@ use std::collections::{HashMap, HashSet}; -use advent_of_code_2024::{add_pair, make_main, mul_pair, next, nexti64, Pair, SResult}; +use advent_of_code_2024::{add_pair, make_main, mul_pair, nexti64, Pair, SResult}; make_main!(); diff --git a/src/bin/d9p1.rs b/src/bin/d9p1.rs index cccf416..965fe47 100644 --- a/src/bin/d9p1.rs +++ b/src/bin/d9p1.rs @@ -1,6 +1,6 @@ use std::collections::{HashMap, HashSet}; -use advent_of_code_2024::{add_pair, make_main, mul_pair, next, nexti64, Pair, SResult}; +use advent_of_code_2024::{make_main, SResult}; make_main!();