Skip to content

Commit

Permalink
add day16
Browse files Browse the repository at this point in the history
  • Loading branch information
mirsella committed Dec 16, 2023
1 parent e85fe21 commit 88b0220
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 1 deletion.
2 changes: 1 addition & 1 deletion 2023/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ members = [
"day13",
"day14",
"day15",
# "day16",
"day16",
# "day17",
# "day18",
# "day19",
Expand Down
19 changes: 19 additions & 0 deletions 2023/day16/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
input.txt
flamegraph.svg
perf.data*
### Rust
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

12 changes: 12 additions & 0 deletions 2023/day16/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "day16"
authors = ["mirsella <[email protected]>"]
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

grid = { git = "https://github.com/becheran/grid" }
itertools = "0.12.0"
28 changes: 28 additions & 0 deletions 2023/day16/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use std::fs::File;
use std::io::{self, Read};
use std::path::PathBuf;
use std::{env, fs};

fn replace_in_file(file_path: &PathBuf, old: &str, new: &str) -> io::Result<()> {
let mut contents = String::new();
File::open(file_path)?.read_to_string(&mut contents)?;
let new_contents = contents.replace(old, new);
if contents != new_contents {
println!("Updating {}", file_path.display());
fs::write(file_path, new_contents)?;
}
Ok(())
}

fn main() -> io::Result<()> {
let pkg_name = env::var("CARGO_PKG_NAME").unwrap();
replace_in_file(
&"../Cargo.toml".into(),
&format!("# \"{pkg_name}\""),
&format!("\"{pkg_name}\""),
)?;

replace_in_file(&"./Cargo.toml".into(), "\n[workspace]", "")?;

Ok(())
}
160 changes: 160 additions & 0 deletions 2023/day16/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
use grid::Grid;
use itertools::Itertools;
use std::{collections::BTreeSet, sync::Arc};

#[derive(Debug, Ord, PartialEq, PartialOrd, Eq, Copy, Clone)]
enum Direction {
Up,
Down,
Left,
Right,
}
/// x, y
impl From<Direction> for (isize, isize) {
fn from(val: Direction) -> Self {
match val {
Direction::Up => (0, -1),
Direction::Down => (0, 1),
Direction::Left => (-1, 0),
Direction::Right => (1, 0),
}
}
}

fn _print_energized_grid(grid: &Grid<char>, energized: &BTreeSet<(isize, isize, Direction)>) {
let mut grid = grid.clone();
for (x, y, _) in energized {
*grid.get_mut(*y as usize, *x as usize).unwrap() = '#';
}
for row in grid.iter_rows() {
println!("{}", row.collect::<String>());
}
println!();
}

/// x, y current pos, direction the ray was going
fn fill_ray(
grid: &Grid<char>,
history: &mut BTreeSet<(isize, isize, Direction)>,
x: isize,
y: isize,
direction: Direction,
) {
let c = match grid.get(y as usize, x as usize) {
Some(c) => c,
None => return,
};
let (dx, dy) = direction.into();
if !history.insert((x, y, direction)) {
return;
}
match c {
'|' if matches!(direction, Direction::Left | Direction::Right) => {
fill_ray(grid, history, x, y - 1, Direction::Up);
fill_ray(grid, history, x, y + 1, Direction::Down);
}
'-' if matches!(direction, Direction::Up | Direction::Down) => {
fill_ray(grid, history, x - 1, y, Direction::Left);
fill_ray(grid, history, x + 1, y, Direction::Right);
}
'/' => match direction {
Direction::Up => fill_ray(grid, history, x + 1, y, Direction::Right),
Direction::Down => fill_ray(grid, history, x - 1, y, Direction::Left),
Direction::Left => fill_ray(grid, history, x, y + 1, Direction::Down),
Direction::Right => fill_ray(grid, history, x, y - 1, Direction::Up),
},
'\\' => match direction {
Direction::Down => fill_ray(grid, history, x + 1, y, Direction::Right),
Direction::Up => fill_ray(grid, history, x - 1, y, Direction::Left),
Direction::Right => fill_ray(grid, history, x, y + 1, Direction::Down),
Direction::Left => fill_ray(grid, history, x, y - 1, Direction::Up),
},
_ => fill_ray(grid, history, x + dx, y + dy, direction),
}
}

fn part1(input: &str) -> usize {
let grid = Grid::from_vec(
input.chars().filter(|&c| c != '\n').collect(),
input.find('\n').unwrap(),
);
let mut energized_tiles = BTreeSet::new();
fill_ray(&grid, &mut energized_tiles, 0, 0, Direction::Right);
// print_energized_grid(&grid, &energized_tiles);
energized_tiles
.into_iter()
.unique_by(|&(x, y, _)| (x, y))
.count()
}
fn part2(input: &str) -> usize {
let grid = Grid::from_vec(
input.chars().filter(|&c| c != '\n').collect(),
input.find('\n').unwrap(),
);
let grid = Arc::new(grid);
let starts = [
(0..grid.cols() - 1, 0..1, Direction::Down),
(
0..grid.cols() - 1,
(grid.cols() - 1)..grid.cols(),
Direction::Up,
),
(0..1, 0..grid.rows() - 1, Direction::Right),
(
(grid.cols() - 1)..grid.cols(),
0..grid.rows() - 1,
Direction::Left,
),
];
let mut counts = Vec::with_capacity(grid.rows() * 2 + grid.cols() * 2);
for (x_range, y_range, direction) in starts.iter() {
for x in x_range.clone() {
for y in y_range.clone() {
let grid = grid.clone();
let direction = *direction;
counts.push(std::thread::spawn(move || {
let mut energized_tiles = BTreeSet::new();
fill_ray(
&grid,
&mut energized_tiles,
x as isize,
y as isize,
direction,
);
energized_tiles
.iter()
.unique_by(|&(x, y, _)| (x, y))
.count()
}))
}
}
}
counts.into_iter().map(|h| h.join().unwrap()).max().unwrap()
}
fn main() {
let input = include_str!("../input.txt");
println!("Part 1: {}", part1(input));
println!("Part 2: {}", part2(input));
}

#[cfg(test)]
mod tests {
const INPUT: &str = r".|...\....
|.-.\.....
.....|-...
........|.
..........
.........\
..../.\\..
.-.-/..|..
.|....-|.\
..//.|....";
#[test]
fn part1() {
assert_eq!(super::part1(INPUT), 46);
}
#[test]
fn part2() {
assert_eq!(super::part2(INPUT), 51);
}
}

0 comments on commit 88b0220

Please sign in to comment.