diff --git a/2023/16/src/main.rs b/2023/16/src/main.rs index b5d19c0..6b2599d 100644 --- a/2023/16/src/main.rs +++ b/2023/16/src/main.rs @@ -1,7 +1,8 @@ -use std::{fs::File, io::{BufReader, BufRead, Write}, ops::Add, fmt::Debug}; +use std::{fs::File, io::{BufReader, BufRead, Write}, ops::Add, fmt::Debug, collections::HashSet, hash::{Hasher, BuildHasherDefault}}; fn main() { part1(); + part2(); } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -46,6 +47,42 @@ struct Beam { vector: Vector } +impl Beam { + fn to_u64(&self) -> u64 { + (self.point.x * 100 + self.point.y) * (1 + self.vector.x + 2 * (self.vector.y + 1)) + } +} + +#[derive(Debug, Default)] +struct BeamHasher { + nums: u64 +} + +impl Hasher for BeamHasher { + fn write(&mut self, bytes: &[u8]) { + // assign bytes directly to nums - this hasher will always get 4 u8s, just once + // self.nums = 0; + for i in 0..4 { + self.nums ^= (bytes[i] as u64) << (i * 8); + } + } + + fn finish(&self) -> u64 { + self.nums + } +} + +impl std::hash::Hash for Beam { + fn hash(&self, state: &mut H) { + state.write(&[ + self.point.x as u8, + self.point.y as u8, + self.vector.x as u8, + self.vector.y as u8 + ]); + } +} + impl Vector { fn map_by_mirror(&self, mirror: Type) -> Vector { match mirror { @@ -127,11 +164,11 @@ fn print_energized(energized: &Vec>) -> Result<(), std::io::Error> { Ok(()) } -fn append_if_not_in(vec: &mut Vec, item: T) { - if !vec.contains(&item) { - vec.push(item); - } -} +// fn append_if_not_in(vec: &mut Vec, item: T) { +// if !vec.contains(&item) { +// vec.push(item); +// } +// } fn set_range(vec: &mut Vec, range: std::ops::Range, item: T) { for i in range { vec[i] = item; @@ -159,14 +196,14 @@ fn mark(vec: Vector, point: Point, otherpos: usize, energized: &mut Vec Vec> { let file = File::open("input2").expect("File not found"); let reader = BufReader::new(file); let map : Vec> = reader.lines().map(|l| l.unwrap().chars().collect()).collect(); - let mut energized : Vec> = map.iter().map(|l| l.iter().map(|_| false).collect()).collect(); - - let max_point = Point { x: map[0].len(), y: map.len() }; + map +} +fn get_rows_and_cols(map: Vec>) -> (Vec>, Vec>) { let rows: Vec> = map.iter().enumerate().map(|(y, row)| { row .iter() @@ -202,10 +239,23 @@ fn part1() { }).collect() }).collect(); - let mut beams : Vec = vec![Beam { - point: Point { x: 0, y: 0 }, - vector: VEC_RIGHT - }]; + (rows, columns) +} + +fn setup() -> (Point, Vec>, Vec>) { + let map = get_map(); + // let energized : Vec> = map.iter().map(|l| l.iter().map(|_| false).collect()).collect(); + let max_point = Point { x: map[0].len(), y: map.len() }; + let (rows, columns) = get_rows_and_cols(map); + + (max_point, rows, columns) +} + +fn get_count(max_point: Point, rows: Vec>, columns: Vec>, beam: Beam) -> usize { + let mut energized : Vec> = vec![vec![false; max_point.x]; max_point.y]; + let mut beams_set = HashSet::>::default(); + let mut beams : Vec = vec![beam]; + beams_set.insert(beams[0]); let mut offset = 0; @@ -214,15 +264,16 @@ fn part1() { offset += 1; let vec = beam.vector; + let vec_is_vertical = vec.is_vertical(); let mut relevant = { - (if vec.is_vertical() { + (if vec_is_vertical { columns[beam.point.x].iter() } else { rows[beam.point.y].iter() }) .filter(|mp| { - let mpp = if vec.is_vertical() { mp.point.y } else { mp.point.x }; - let beamp = if vec.is_vertical() { beam.point.y } else { beam.point.x }; + let mpp = if vec_is_vertical { mp.point.y } else { mp.point.x }; + let beamp = if vec_is_vertical { beam.point.y } else { beam.point.x }; // ignore splits that are the same direction as the beam mp.mirror != vec.map_to_split() && (mpp >= beamp && vec.is_positive() || mpp <= beamp && vec.is_negative()) @@ -238,7 +289,7 @@ fn part1() { mark(vec, beam.point, if vec.is_positive() { max_point.x } else { 0 }, &mut energized); }, Some(mappoint) => { - mark(vec, beam.point, (if vec.is_vertical() { mappoint.point.y } else { mappoint.point.x } ) + (if vec.is_positive() { 1 } else { 0 }), &mut energized); + mark(vec, beam.point, (if vec_is_vertical { mappoint.point.y } else { mappoint.point.x } ) + (if vec.is_positive() { 1 } else { 0 }), &mut energized); let mut vecs = vec![]; if mappoint.mirror == Type::SplitHorizontal || mappoint.mirror == Type::SplitVertical { let (v1, v2) = vectors_from_split(mappoint.mirror); @@ -255,14 +306,62 @@ fn part1() { point: new_point, vector: v }; - append_if_not_in(&mut beams, beam); + // append_if_not_in(&mut beams, beam); + if beams_set.insert(beam) { + beams.push(beam); + } } } } } } - print_energized(&energized).unwrap(); + // print_energized(&energized).unwrap(); let count = energized.iter().map(|row| row.iter().filter(|&&b| b).count()).sum::(); - println!("Count: {}", count); + count +} + +fn part1() { + let (max_point, rows, columns) = setup(); + let count = get_count(max_point, rows, columns, Beam { + point: Point { x: 0, y: 0 }, + vector: VEC_RIGHT + }); + println!("Part 1 count: {}", count); +} + +fn part2() { + let (max_point, rows, columns) = setup(); + let mut count = 0; + for x in 0..max_point.x { + for y in 0..max_point.y { + if x != 0 && y != 0 && x != max_point.x - 1 && y != max_point.y - 1 { + continue; + } + let mut vecs = vec![]; + if x > 0 { + vecs.push(VEC_LEFT); + } + if x == 0 { + vecs.push(VEC_RIGHT); + } + if y > 0 { + vecs.push(VEC_UP); + } + if y == 0 { + vecs.push(VEC_DOWN); + } + for vector in vecs { + let count_here = get_count(max_point, rows.clone(), columns.clone(), Beam { + point: Point { x, y }, + vector + }); + if count_here > count { + count = count_here; + println!("New max: {} at {},{}", count, x, y); + } + } + } + } + println!("Max count: {}", count); } \ No newline at end of file