Skip to content

Commit

Permalink
add: day 14
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian Liu committed Dec 14, 2024
1 parent 63c8040 commit 4a2a3df
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 23 deletions.
12 changes: 12 additions & 0 deletions data/examples/14.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
p=0,4 v=3,-3
p=6,3 v=-1,-3
p=10,3 v=-1,2
p=2,0 v=2,-1
p=0,0 v=1,3
p=3,0 v=-2,-2
p=7,6 v=-1,-3
p=3,0 v=-1,-2
p=9,3 v=2,3
p=7,3 v=-1,2
p=2,4 v=2,-3
p=9,5 v=-3,-3
43 changes: 21 additions & 22 deletions src/bin/12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn part_one(input: &str) -> Option<u32> {
Some(get_fence_cost(
&mut grid,
&bounds,
compute_cost_and_update_grid,
compute_cost,
))
}

Expand All @@ -24,7 +24,7 @@ pub fn part_two(input: &str) -> Option<u32> {
Some(get_fence_cost(
&mut grid,
&bounds,
compute_cost_and_update_grid2,
compute_cost2,
))
}

Expand All @@ -35,12 +35,12 @@ fn convert_input_to_grid(input: &str) -> Vec<Vec<char>> {
fn get_fence_cost<F>(
grid: &mut Vec<Vec<char>>,
bounds: &(usize, usize),
compute_cost_and_update_grid: F,
compute_cost: F,
) -> u32
where
F: Fn(&mut Vec<Vec<char>>, &(usize, usize), HashSet<(usize, usize)>) -> u32,
F: Fn(&mut Vec<Vec<char>>, &(usize, usize), &HashSet<(usize, usize)>) -> u32,
{
let mut cost = 0;
let mut total_cost = 0;

for pos in (0..bounds.0).cartesian_product(0..bounds.1) {
if grid[pos.0][pos.1] == ' ' {
Expand All @@ -50,10 +50,11 @@ where
let mut visited: HashSet<(usize, usize)> = HashSet::new();
dfs(&pos, grid, bounds, &mut visited);

cost += compute_cost_and_update_grid(grid, bounds, visited);
total_cost += compute_cost(grid, bounds, &visited);
mark_visited_on_grid(grid, visited);
}

cost
total_cost
}

fn dfs(
Expand All @@ -62,7 +63,7 @@ fn dfs(
bounds: &(usize, usize),
visited: &mut HashSet<(usize, usize)>,
) {
if visited.contains(&pos) {
if visited.contains(pos) {
return;
}
visited.insert(*pos);
Expand All @@ -77,14 +78,20 @@ fn dfs(
}
}

fn compute_cost_and_update_grid(
fn mark_visited_on_grid(grid: &mut [Vec<char>], visited: HashSet<(usize, usize)>) {
for pos in &visited {
grid[pos.0][pos.1] = ' ';
}
}

fn compute_cost(
grid: &mut Vec<Vec<char>>,
bounds: &(usize, usize),
visited: HashSet<(usize, usize)>,
visited: &HashSet<(usize, usize)>,
) -> u32 {
let mut perimeter = 0;

for pos in &visited {
for pos in visited {
for delta in DIRECTIONS {
if let Some(next_pos) = is_valid_pos(pos, bounds, &delta) {
if grid[next_pos.0][next_pos.1] != grid[pos.0][pos.1] {
Expand All @@ -96,20 +103,16 @@ fn compute_cost_and_update_grid(
}
}

for pos in &visited {
grid[pos.0][pos.1] = ' ';
}

visited.len() as u32 * perimeter
}

fn compute_cost_and_update_grid2(
fn compute_cost2(
grid: &mut Vec<Vec<char>>,
bounds: &(usize, usize),
visited: HashSet<(usize, usize)>,
visited: &HashSet<(usize, usize)>,
) -> u32 {
let mut borders: HashMap<(isize, isize), Vec<(usize, usize)>> = HashMap::new();
for pos in &visited {
for pos in visited {
for delta in DIRECTIONS {
if let Some(next_pos) = is_valid_pos(pos, bounds, &delta) {
if grid[next_pos.0][next_pos.1] != grid[pos.0][pos.1] {
Expand Down Expand Up @@ -146,10 +149,6 @@ fn compute_cost_and_update_grid2(
}
}

for pos in &visited {
grid[pos.0][pos.1] = ' ';
}

sides * visited.len() as u32
}

Expand Down
1 change: 0 additions & 1 deletion src/bin/13.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,5 @@ mod tests {
#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, None);
}
}
161 changes: 161 additions & 0 deletions src/bin/14.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
use std::collections::HashMap;

use regex::Regex;

advent_of_code::solution!(14);

#[derive(Debug)]
struct Robot {
i: usize,
j: usize,
di: isize,
dj: isize,
}

struct Grid {
m: usize,
n: usize,
robots: Vec<Robot>,
mid_m: usize,
mid_n: usize,
}

impl Grid {
fn new(m: usize, n: usize, robots: Vec<Robot>) -> Self {
Grid {
m,
n,
robots,
mid_m: m / 2,
mid_n: n / 2,
}
}

fn move_robots(&mut self) {
for robot in &mut self.robots {
robot.i = ((robot.i as isize + robot.di).rem_euclid(self.m as isize)) as usize;
robot.j = ((robot.j as isize + robot.dj).rem_euclid(self.n as isize)) as usize;
}
}

fn find_safety_factor(&self) -> u32 {
let mut quadrant: HashMap<(bool, bool), u32> = HashMap::new();

for robot in &self.robots {
if robot.i == self.mid_m || robot.j == self.mid_n {
continue;
}
*quadrant
.entry((robot.i > self.mid_m, robot.j > self.mid_n))
.or_default() += 1;
}

quadrant.values().product()
}

fn has_a_tree(&self) -> bool {
let mut rows: HashMap<usize, Vec<usize>> = HashMap::new();
let mut cols: HashMap<usize, Vec<usize>> = HashMap::new();

for robot in &self.robots {
rows.entry(robot.i).or_default().push(robot.j);
cols.entry(robot.j).or_default().push(robot.i);
}

let mut crowded_rows = 0;
for row in rows.values() {
if row.len() >= 30 {
crowded_rows += 1;
}
}
let mut crowded_cols = 0;
for col in cols.values() {
if col.len() >= 30 {
crowded_cols += 1;
}
}

crowded_rows >= 2 && crowded_cols >= 2 // has a frame
}

fn draw_grid(&self) {
let mut canvas = vec![vec!['.'; self.n]; self.m];
for robot in &self.robots {
canvas[robot.i][robot.j] = '󱚣';
}
for row in canvas {
println!("{}", row.iter().collect::<String>());
}
}

#[allow(dead_code)]
fn dbg_robots(&self) {
for robot in &self.robots {
dbg!(robot);
}
}
}

pub fn part_one(input: &str) -> Option<u32> {
let robots = parse_input(input);
let mut grid = Grid::new(103, 101, robots);

for _ in 0..100 {
grid.move_robots();
}

Some(grid.find_safety_factor())
}

pub fn part_two(input: &str) -> Option<u32> {
let robots = parse_input(input);
let mut grid = Grid::new(103, 101, robots);

for i in 1..=10000 {
grid.move_robots();
if grid.has_a_tree() {
grid.draw_grid();
return Some(i as u32);
}
}

None
}

fn parse_input(input: &str) -> Vec<Robot> {
let line_re = Regex::new(r"p\=(.*),(.*)\sv\=(.*),(.*)").unwrap();
let mut parsed_input = vec![];

input.lines().for_each(|line| {
let cap = line_re.captures(line).unwrap();
parsed_input.push(Robot {
i: cap[2].parse().unwrap(),
j: cap[1].parse().unwrap(),
di: cap[4].parse().unwrap(),
dj: cap[3].parse().unwrap(),
})
});

parsed_input
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_part_one() {
let robots = parse_input(&advent_of_code::template::read_file("examples", DAY));
let mut grid = Grid::new(7, 11, robots);
for _ in 0..100 {
grid.move_robots();
grid.draw_grid();
}
assert_eq!(grid.find_safety_factor(), 12);
}

#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
}
}

0 comments on commit 4a2a3df

Please sign in to comment.