add: day12
This commit is contained in:
+1
-1
@@ -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!();
|
||||
|
||||
|
||||
+2
-2
@@ -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!();
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
AAAA
|
||||
BBCD
|
||||
BBCC
|
||||
EEEC
|
||||
@@ -0,0 +1,5 @@
|
||||
OOOOO
|
||||
OXOXO
|
||||
OOOOO
|
||||
OXOXO
|
||||
OOOOO
|
||||
@@ -0,0 +1,5 @@
|
||||
EEEEE
|
||||
EXXXX
|
||||
EEEEE
|
||||
EXXXX
|
||||
EEEEE
|
||||
+165
-5
@@ -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<String>) -> SResult<(usize, usize)> {
|
||||
Ok((0, 0))
|
||||
let width = lines.len();
|
||||
let mut grid: Vec<Vec<char>> = Vec::with_capacity(lines.len());
|
||||
for line in lines {
|
||||
grid.push(line.trim().chars().collect());
|
||||
}
|
||||
|
||||
let mut visited: HashSet<Pair> = 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<char>], loc: Pair, global_visit: &mut HashSet<Pair>) -> HashSet<Pair> {
|
||||
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<Pair>) -> 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<Pair>) -> usize {
|
||||
let mut count = 0;
|
||||
|
||||
// Organize things by x, and y
|
||||
let mut by_x: HashMap<usize, Vec<Pair>> = HashMap::default();
|
||||
let mut by_y: HashMap<usize, Vec<Pair>> = 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<String> = input!("d11p1.txt");
|
||||
let strings: Vec<String> = 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<String> = input!("d12i1.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (140, 80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sample_input3() {
|
||||
let strings: Vec<String> = input!("d12i2.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (772, 436));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sample_input4() {
|
||||
let strings: Vec<String> = input!("d12i3.txt");
|
||||
let got = solve(strings).unwrap();
|
||||
assert_eq!(got, (692, 236));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
RRRRIICCFF
|
||||
RRRRIICCCF
|
||||
VVRRRCCFFF
|
||||
VVRCCCJFFF
|
||||
VVVVCJJCFE
|
||||
VVIVCCJJEE
|
||||
VVIIICJJEE
|
||||
MIIIIIJJEE
|
||||
MIIISIJEEE
|
||||
MMMISSJEEE
|
||||
+1
-1
@@ -173,7 +173,7 @@ fn take_one(s: &str) -> PResult<char> {
|
||||
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();
|
||||
|
||||
+1
-1
@@ -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!();
|
||||
|
||||
|
||||
+1
-1
@@ -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!();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user