diff --git a/day14/Cargo.toml b/day14/Cargo.toml new file mode 100644 index 0000000..7a571c1 --- /dev/null +++ b/day14/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "day14" +version = "0.1.0" +edition = "2021" + +[dependencies] +regex = "1.11.1" diff --git a/day14/src/main.rs b/day14/src/main.rs new file mode 100644 index 0000000..15c51b0 --- /dev/null +++ b/day14/src/main.rs @@ -0,0 +1,116 @@ +use std::collections::HashSet; +use regex::Regex; +use std::env; + +use std::fs; + +use crate::Dir::{North, South, East, West }; + +type Coord = (i128, i128); +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +enum Dir { North, South, East, West } + +fn step(start: &Coord, d: Dir, steps: i128) -> Coord { + match d { + North => (start.0, start.1 - steps), + South => (start.0, start.1 + steps), + East => (start.0 + steps, start.1), + West => (start.0 - steps, start.1), + } +} + +fn walk(start: &Coord, diff: &Coord) -> Coord { + (start.0 + diff.0, start.1 + diff.1) +} + +#[derive(Debug, Copy, Clone)] +struct Robot { start: Coord, velocity: Coord } + +fn main() { + println!("Hello, AoC day 13!"); + + let args: Vec = env::args().collect(); + if args.len() != 2 { + println!("wrong number of arguments!"); + std::process::exit(1); + } + + let file_path = &args[1]; + + let find_record = Regex::new(r"p=([0-9]+),([0-9]+) v=(-?[0-9]+),(-?[0-9]+)").unwrap(); + + let binding = fs::read_to_string(file_path) + .expect("should be able to read the file"); + let robots = binding.lines() + .filter_map(|l| find_record.captures(l) ) + .map(|caps| Robot { + start: (caps[1].parse().unwrap(), caps[2].parse().unwrap()), + velocity: (caps[3].parse().unwrap(), caps[4].parse().unwrap()) + }) + .collect::>(); + + let corner = (101, 103); + + let mut new_robots = robots.clone(); + for _ in 0..100 { iterate(&mut new_robots, corner); } + println!("the safety factor after 100 seconsd is {}", safety_factor(&mut new_robots, corner)); + + let seconds = 17774; + + let mut new_robots = robots.clone(); + iterate_n(&mut new_robots, corner, seconds); + print_scene(&new_robots, corner); + +} + +fn iterate(robots: &mut Vec, corner: Coord) -> usize { + let mut positions: HashSet = HashSet::new(); + for r in robots { + r.start.0 = (r.start.0 + r.velocity.0).rem_euclid(corner.0); + r.start.1 = (r.start.1 + r.velocity.1).rem_euclid(corner.1); + positions.insert(r.start); + } + return positions.len(); +} + +fn iterate_n(robots: &mut Vec, corner: Coord, seconds: i128) -> usize { + let mut positions: HashSet = HashSet::new(); + for r in robots { + r.start.0 = (r.start.0 + r.velocity.0*seconds).rem_euclid(corner.0); + r.start.1 = (r.start.1 + r.velocity.1*seconds).rem_euclid(corner.1); + positions.insert(r.start); + } + return positions.len(); +} + +fn print_scene(robots: &Vec, corner: Coord) { + let mut positions: HashSet = HashSet::new(); + for Robot {start, velocity: _} in robots.iter() { + positions.insert(*start); + } + for x in 0..corner.0 { + for y in 0..corner.1 { + print!("{}", if positions.contains(&(x,y)) { "#" } else { "." }); + } + print!("\n"); + } +} + +fn safety_factor(robots: &mut Vec, corner: Coord) -> i128 { + let mut q: [i128; 4] = [0,0,0,0]; + + let halfs = ((corner.0 - 1) / 2, (corner.1 - 1) / 2); + for Robot { start, velocity: _ } in robots { + if start.0 < halfs.0 && start.1 < halfs.1 { + q[0] += 1; + } else if start.0 > halfs.0 && start.1 < halfs.1 { + q[1] += 1; + } else if start.0 < halfs.0 && start.1 > halfs.1 { + q[2] += 1; + } else if start.0 > halfs.0 && start.1 > halfs.1 { + q[3] += 1; + } + } + + return q[0]*q[1]*q[2]*q[3]; +} \ No newline at end of file diff --git a/day15/Cargo.toml b/day15/Cargo.toml new file mode 100644 index 0000000..96a5696 --- /dev/null +++ b/day15/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "day15" +version = "0.1.0" +edition = "2021" + +[dependencies] +itertools = "0.13.0" diff --git a/day15/src/main.rs b/day15/src/main.rs new file mode 100644 index 0000000..65bc941 --- /dev/null +++ b/day15/src/main.rs @@ -0,0 +1,228 @@ +use std::collections::HashMap; +use std::collections::HashSet; + +use std::env; +use std::fs; + +use itertools::Itertools; + +use crate::Dir::{North, South, East, West }; + +type Coord = (i32, i32); +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +enum Dir { North, South, East, West } + +fn step(start: &Coord, d: Dir, steps: i32) -> Coord { + match d { + North => (start.0, start.1 - steps), + South => (start.0, start.1 + steps), + East => (start.0 + steps, start.1), + West => (start.0 - steps, start.1), + } +} + +fn main() { + println!("Hello, AoC day 13!"); + + let args: Vec = env::args().collect(); + if args.len() != 2 { + println!("wrong number of arguments!"); + std::process::exit(1); + } + + let file_path = &args[1]; + + let binding = fs::read_to_string(file_path) + .expect("should be able to read the file"); + let (map_string, instructions_string) = binding + .split_once("\n\n") + .expect("should have a map and an instructions section"); + + let mut map = HashMap::new(); + + let mut robot = (0,0); + let mut y = 0; + for line in map_string.lines() { + let mut x = 0; + for c in line.chars() { + if c == '@' { + robot = (x,y); + map.insert((x,y), '.'); + } else { + map.insert((x,y), c); + } + x += 1; + } + y += 1; + } + + let binding = instructions_string + .lines() + .join(""); + let instructions = binding + .chars() + .map(|c| match c { '^'=>North, '>'=>East, 'v'=>South, '<'=>West, _=>North }); + + for direction in instructions { + let next = step(&robot, direction, 1); + let neighbor = map.get(&next); + if neighbor == Some(&'.') { + robot = next; + } else if neighbor == Some(&'#') { + continue; + } else if neighbor == Some(&'O') { + let mut steps = 1; + let mut stack_top = map.get(&step(&robot, direction, steps)); + while stack_top == Some(&'O') { + steps = steps + 1; + stack_top = map.get(&step(&robot, direction, steps)); + } + if stack_top == Some(&'.') { + map.insert(step(&robot, direction, steps), 'O'); + map.insert(next, '.'); + robot = next; + } + } + } + + println!("the gps score after all the instructions is {}", sum_of_box_gps(&map)); + + let mut map = HashMap::new(); + + let mut robot = (0,0); + let mut y = 0; + for line in map_string.lines() { + let mut x = 0; + for c in line.chars() { + match c { + '@' => { + robot = (2*x,y); + map.insert((2*x,y), '.'); + map.insert((2*x+1,y), '.'); + }, + '.' => { + map.insert((2*x, y), '.'); + map.insert((2*x+1, y), '.'); + }, + 'O' => { + map.insert((2*x, y), '['); + map.insert((2*x+1, y), ']'); + }, + '#' => { + map.insert((2*x, y), '#'); + map.insert((2*x+1, y), '#'); + }, + _ => { + map.insert((2*x, y), '.'); + map.insert((2*x+1, y), '.'); + } + } + x += 1; + } + y += 1; + } + + let binding = instructions_string + .lines() + .join(""); + let instructions = binding + .chars() + .map(|c| match c { '^'=>North, '>'=>East, 'v'=>South, '<'=>West, _=>North }); + + for direction in instructions { + let next = step(&robot, direction, 1); + let neighbor = map.get(&next); + if neighbor == Some(&'.') { + robot = next; + } else if neighbor == Some(&'#') { + continue; + } else if neighbor == Some(&'[') || neighbor == Some(&']') { + let mut boxes_to_move: HashSet = HashSet::new(); + let mut unexamined_boxes: HashSet = HashSet::new(); + + unexamined_boxes.insert(next); + + while !unexamined_boxes.is_empty() { + let mut candidate_boxes: HashSet = HashSet::new(); + for spot in unexamined_boxes.drain() { + match map.get(&spot) { + Some('[') => { + let other_half = step(&spot, East, 1); + if !boxes_to_move.contains(&other_half) { + candidate_boxes.insert(other_half); + } + candidate_boxes.insert(step(&spot, direction, 1)); + boxes_to_move.insert(spot); + }, + Some(']') => { + let other_half = step(&spot, West, 1); + if !boxes_to_move.contains(&other_half) { + candidate_boxes.insert(other_half); + } + candidate_boxes.insert(step(&spot, direction, 1)); + boxes_to_move.insert(spot); + }, + Some('#') => { + boxes_to_move.drain(); + candidate_boxes.drain(); + break; + }, + Some('.') => { + continue; + }, + _ => { + println!("encountered something weird in the map"); + } + + } + } + unexamined_boxes = candidate_boxes; + } + + if !boxes_to_move.is_empty() { + robot = next; + let mut fulls: HashMap = HashMap::new(); + for b in &boxes_to_move { + fulls.insert(step(&b, direction, 1), *map.get(&b).unwrap()); + } + + for x in boxes_to_move { + map.insert(x, '.'); + } + for (x, c) in fulls { + map.insert(x, c); + } + } + } + } + + print_map(&map); + + println!("the gps score after all the instructions in wide mode is {}", sum_of_box_gps(&map)); +} + +fn sum_of_box_gps(grid: &HashMap) -> i32 { + let mut sum = 0; + + for ((x, y), stuff) in grid { + if *stuff == 'O' { sum += x + 100*y; } + if *stuff == '[' { sum += x + 100*y; } + } + + return sum; +} + +fn print_map(grid: &HashMap) { + let (mut x_max, mut y_max): (i32, i32) = (0,0); + for ((x, y), _) in grid { + x_max = x_max.max(*x); + y_max = y_max.max(*y) + } + + for y in 0..y_max { + for x in 0..x_max { + print!("{}", grid.get(&(x,y)).unwrap()) + } + println!(); + } +} \ No newline at end of file