Compare commits

...

2 commits

Author SHA1 Message Date
Joe Ardent
724572d5be day12 part1 2025-01-12 17:58:20 -08:00
Joe Ardent
80e57358e5 day12, part1: test passes, need to optimize 2025-01-12 15:58:00 -08:00
4 changed files with 192 additions and 3 deletions

4
Cargo.lock generated
View file

@ -64,6 +64,10 @@ version = "0.1.0"
name = "day11" name = "day11"
version = "0.1.0" version = "0.1.0"
[[package]]
name = "day12"
version = "0.1.0"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"

View file

@ -1,6 +1,6 @@
[workspace] [workspace]
resolver = "2" resolver = "3"
members = ["day01", "day02", "day03", "day04", "day05", "day06", "day07", "day08", "day09", "day10", "day11"] members = ["day01", "day02", "day03", "day04", "day05", "day06", "day07", "day08", "day09", "day10", "day11", "day12"]
[workspace.dependencies] [workspace.dependencies]
winnow = "0.6" winnow = "*"

6
day12/Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "day12"
version = "0.1.0"
edition = "2024"
[dependencies]

179
day12/src/main.rs Normal file
View file

@ -0,0 +1,179 @@
use std::collections::{HashSet, VecDeque};
fn main() {
let input = std::fs::read_to_string("input").unwrap();
let grid = Garden::new(&input);
println!("{}", pt1(&grid));
}
fn pt1(grid: &Garden) -> usize {
let mut visited = HashSet::new();
let mut cost = 0;
for row in grid.rows.iter() {
for plot in row.iter() {
let root = plot.loc;
if visited.contains(&root) {
continue;
}
let mut q = VecDeque::new();
q.push_back(root);
let mut region = HashSet::new();
let mut visiting = HashSet::new();
while let Some(current) = q.pop_front() {
visited.insert(current);
visiting.remove(&current);
let nexts = grid.neighbors(&current);
for next in nexts
.iter()
.map(|n| grid.get(n).unwrap())
.filter(|n| !region.contains(n))
{
if !visiting.contains(&next.loc) {
q.push_back(next.loc);
visiting.insert(next.loc);
}
}
region.insert(grid.get(&current).unwrap());
}
let a = region.len();
let mut p = 0;
for plot in region {
p += plot.p_val;
}
cost += a * p;
}
}
cost
}
#[derive(Debug, Clone)]
struct Garden {
rows: Vec<Vec<Plot>>,
}
impl Garden {
fn new(input: &str) -> Self {
let mut rows = Vec::new();
for (row, line) in input.lines().enumerate() {
let row = line
.chars()
.enumerate()
.map(|(col, c)| Plot {
loc: Loc { row, col },
p_val: 0,
plant: c,
})
.collect();
rows.push(row);
}
let mut g = Self { rows };
let rows = g.rows.len();
let cols = g.rows[0].len();
for row in 0..rows {
for col in 0..cols {
let mut p = 4;
for _ in g.neighbors(&Loc { row, col }) {
p -= 1;
}
g.rows[row][col].p_val = p;
}
}
g
}
fn get(&self, loc: &Loc) -> Option<&Plot> {
self.rows.get(loc.row).and_then(|row| row.get(loc.col))
}
fn next(&self, loc: &Loc) -> Vec<&Plot> {
let Loc { row, col } = *loc;
let mut out = Vec::new();
// north
{
let row = row.wrapping_sub(1);
if let Some(plot) = self.rows.get(row).and_then(|r| r.get(col)) {
out.push(plot)
}
}
// south
{
let row = row + 1;
if let Some(plot) = self.rows.get(row).and_then(|r| r.get(col)) {
out.push(plot);
}
}
// east
{
let col = col + 1;
if let Some(plot) = self.rows.get(row).and_then(|r| r.get(col)) {
out.push(plot);
}
}
// west
{
let col = col.wrapping_sub(1);
if let Some(plot) = self.rows.get(row).and_then(|r| r.get(col)) {
out.push(plot);
}
}
out
}
// returns list of neighbor nodes in a dag where the edges are all one step in
// distance
fn neighbors(&self, loc: &Loc) -> Vec<Loc> {
let plot = self.rows[loc.row][loc.col];
self.next(loc)
.iter()
.filter_map(|t| {
if t.plant == plot.plant {
Some(t.loc)
} else {
None
}
})
.collect()
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct Loc {
row: usize,
col: usize,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct Plot {
loc: Loc,
p_val: usize,
plant: char,
}
#[cfg(test)]
mod test {
use super::*;
static INPUT: &str = "RRRRIICCFF
RRRRIICCCF
VVRRRCCFFF
VVRCCCJFFF
VVVVCJJCFE
VVIVCCJJEE
VVIIICJJEE
MIIIIIJJEE
MIIISIJEEE
MMMISSJEEE";
#[test]
fn p1() {
let g = Garden::new(INPUT);
assert_eq!(1930, pt1(&g));
}
}