Compare commits
	
		
			4 Commits
		
	
	
		
			11b29a4d57
			...
			de535303d4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| de535303d4 | |||
| 50b6d045e7 | |||
| d2defae8a2 | |||
| cd8900d936 | 
| @@ -12,3 +12,6 @@ itertools = "0.13.0" | |||||||
| rayon = "1.10.0" | rayon = "1.10.0" | ||||||
| regex = "1.11.1" | regex = "1.11.1" | ||||||
| thread_local = "1.1.8" | thread_local = "1.1.8" | ||||||
|  |  | ||||||
|  | [profile.release] | ||||||
|  | lto = true | ||||||
							
								
								
									
										12
									
								
								src/day10.rs
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/day10.rs
									
									
									
									
									
								
							| @@ -29,12 +29,12 @@ impl TrailMap { | |||||||
|             .collect_vec() |             .collect_vec() | ||||||
|     } |     } | ||||||
|     fn count_reachable_from(&self, pos: &(i64, i64), needle: u8, visited: &mut Grid<bool>) -> u64 { |     fn count_reachable_from(&self, pos: &(i64, i64), needle: u8, visited: &mut Grid<bool>) -> u64 { | ||||||
|         if visited.get(pos.0, pos.1) == Some(true) { |         if visited.get(pos) == Some(true) { | ||||||
|             return 0; |             return 0; | ||||||
|         } else { |         } else { | ||||||
|             visited.set(pos.0, pos.1, true); |             visited.set(pos, true); | ||||||
|         } |         } | ||||||
|         let our_val = self.map.get(pos.0, pos.1).unwrap(); |         let our_val = self.map.get(pos).unwrap(); | ||||||
|         if our_val == needle { |         if our_val == needle { | ||||||
|             return 1; |             return 1; | ||||||
|         } |         } | ||||||
| @@ -42,7 +42,7 @@ impl TrailMap { | |||||||
|         [(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down |         [(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down | ||||||
|             .iter() |             .iter() | ||||||
|             .map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position |             .map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position | ||||||
|             .map(|(x, y)| ((x, y), self.map.get(x, y))) // get value at that position |             .map(|target_pos| (target_pos, self.map.get(&target_pos))) // get value at that position | ||||||
|             .filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1 |             .filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1 | ||||||
|             .map(|(pos, _)| pos) // discard the value |             .map(|(pos, _)| pos) // discard the value | ||||||
|             .map(|pos| self.count_reachable_from(&pos, needle, visited)) |             .map(|pos| self.count_reachable_from(&pos, needle, visited)) | ||||||
| @@ -50,14 +50,14 @@ impl TrailMap { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn count_paths_to(&self, pos: &(i64, i64), needle: u8) -> u64 { |     fn count_paths_to(&self, pos: &(i64, i64), needle: u8) -> u64 { | ||||||
|         let our_val = self.map.get(pos.0, pos.1).unwrap(); |         let our_val = self.map.get(pos).unwrap(); | ||||||
|         if our_val == needle { |         if our_val == needle { | ||||||
|             return 1; |             return 1; | ||||||
|         } |         } | ||||||
|         [(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down |         [(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down | ||||||
|             .iter() |             .iter() | ||||||
|             .map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position |             .map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position | ||||||
|             .map(|(x, y)| ((x, y), self.map.get(x, y))) // get value at that position |             .map(|target_pos| (target_pos, self.map.get(&target_pos))) // get value at that position | ||||||
|             .filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1 |             .filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1 | ||||||
|             .map(|(pos, _)| pos) // discard the value |             .map(|(pos, _)| pos) // discard the value | ||||||
|             .map(|mov| self.count_paths_to(&mov, needle)) |             .map(|mov| self.count_paths_to(&mov, needle)) | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								src/day11.rs
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								src/day11.rs
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| use aoc_runner_derive::{aoc, aoc_generator}; | use aoc_runner_derive::aoc; | ||||||
| use itertools::Itertools; | use itertools::Itertools; | ||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
| use std::iter::repeat; | use std::iter::repeat; | ||||||
| @@ -26,7 +26,6 @@ impl From<&str> for Stones { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[aoc_generator(day11)] |  | ||||||
| fn parse(input: &str) -> Stones { | fn parse(input: &str) -> Stones { | ||||||
|     Stones::from(input) |     Stones::from(input) | ||||||
| } | } | ||||||
| @@ -47,8 +46,8 @@ impl Stone { | |||||||
| } | } | ||||||
|  |  | ||||||
| fn count_blinks(stone: &Stone, blink: usize, cache: &mut Vec<CacheType>) -> IntType { | fn count_blinks(stone: &Stone, blink: usize, cache: &mut Vec<CacheType>) -> IntType { | ||||||
|     if cache[blink].contains_key(&stone) { |     if cache[blink].contains_key(stone) { | ||||||
|         return cache[blink][&stone].clone(); |         return cache[blink][stone]; | ||||||
|     } |     } | ||||||
|     let stones = stone.blink_once(); |     let stones = stone.blink_once(); | ||||||
|     let result = if blink == 0 { |     let result = if blink == 0 { | ||||||
| @@ -63,10 +62,10 @@ fn count_blinks(stone: &Stone, blink: usize, cache: &mut Vec<CacheType>) -> IntT | |||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|     cache[blink].insert(stone.clone(), result); |     cache[blink].insert(stone.clone(), result); | ||||||
|     cache[blink][&stone].clone() |     cache[blink][stone] | ||||||
| } | } | ||||||
|  |  | ||||||
| fn blink_stones(stones: &Stones, blinks: usize) -> IntType { | fn blink_stones(stones: Stones, blinks: usize) -> IntType { | ||||||
|     let mut cache = Vec::from_iter(repeat(CacheType::new()).take(blinks)); |     let mut cache = Vec::from_iter(repeat(CacheType::new()).take(blinks)); | ||||||
|     stones |     stones | ||||||
|         .0 |         .0 | ||||||
| @@ -76,12 +75,14 @@ fn blink_stones(stones: &Stones, blinks: usize) -> IntType { | |||||||
| } | } | ||||||
|  |  | ||||||
| #[aoc(day11, part1)] | #[aoc(day11, part1)] | ||||||
| fn part1(stones: &Stones) -> IntType { | pub fn part1(input: &str) -> IntType { | ||||||
|  |     let stones = parse(input); | ||||||
|     blink_stones(stones, 25) |     blink_stones(stones, 25) | ||||||
| } | } | ||||||
|  |  | ||||||
| #[aoc(day11, part2)] | #[aoc(day11, part2)] | ||||||
| fn part2(stones: &Stones) -> IntType { | pub fn part2(input: &str) -> IntType { | ||||||
|  |     let stones = parse(input); | ||||||
|     blink_stones(stones, 75) |     blink_stones(stones, 75) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -92,11 +93,11 @@ mod tests { | |||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn part1_example() { |     fn part1_example() { | ||||||
|         assert_eq!(part1(&parse(EXAMPLE)), 55312); |         assert_eq!(part1(EXAMPLE), 55312); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn part2_example() { |     fn part2_example() { | ||||||
|         assert_eq!(part2(&parse(EXAMPLE)), 65601038650482); |         assert_eq!(part2(EXAMPLE), 65601038650482); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										61
									
								
								src/day6.rs
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								src/day6.rs
									
									
									
									
									
								
							| @@ -1,5 +1,7 @@ | |||||||
| use aoc_runner_derive::{aoc, aoc_generator}; | use aoc_runner_derive::{aoc, aoc_generator}; | ||||||
| use bitflags::bitflags; | use bitflags::bitflags; | ||||||
|  | use rayon::iter::ParallelIterator; | ||||||
|  | use rayon::slice::ParallelSlice; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use std::io::{BufRead, Lines}; | use std::io::{BufRead, Lines}; | ||||||
| use std::ops::BitAnd; | use std::ops::BitAnd; | ||||||
| @@ -14,10 +16,10 @@ pub fn get_input(input: &[u8]) -> Map { | |||||||
| #[repr(u8)] | #[repr(u8)] | ||||||
| #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] | #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] | ||||||
| enum FacingDirection { | enum FacingDirection { | ||||||
|     Up = b'^', |     Up = 1, | ||||||
|     Down = b'v', |     Down = 2, | ||||||
|     Left = b'<', |     Left = 4, | ||||||
|     Right = b'>', |     Right = 8, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl FacingDirection { | impl FacingDirection { | ||||||
| @@ -45,6 +47,7 @@ enum StepOutcome { | |||||||
|     Continue, |     Continue, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Eq, PartialEq)] | ||||||
| enum RunOutcome { | enum RunOutcome { | ||||||
|     LeftMap, |     LeftMap, | ||||||
|     LoopFound, |     LoopFound, | ||||||
| @@ -98,7 +101,7 @@ impl<T: BufRead> From<Lines<T>> for Map { | |||||||
|         let grid = Grid::from(input); |         let grid = Grid::from(input); | ||||||
|         let mut visited_from: Grid<DirectionSet> = Grid::new(grid.width() as i64); |         let mut visited_from: Grid<DirectionSet> = Grid::new(grid.width() as i64); | ||||||
|         visited_from.data.resize(grid.data.len(), DirectionSet::empty()); |         visited_from.data.resize(grid.data.len(), DirectionSet::empty()); | ||||||
|         let guard_pos = grid.find(b'^').expect("Guard not found"); |         let guard_pos = grid.find(&b'^').expect("Guard not found"); | ||||||
|         let guard_facing = FacingDirection::Up; |         let guard_facing = FacingDirection::Up; | ||||||
|         Self { |         Self { | ||||||
|             grid, |             grid, | ||||||
| @@ -112,31 +115,24 @@ impl<T: BufRead> From<Lines<T>> for Map { | |||||||
|  |  | ||||||
| impl Map { | impl Map { | ||||||
|     fn look(&self, dir: &FacingDirection) -> Option<u8> { |     fn look(&self, dir: &FacingDirection) -> Option<u8> { | ||||||
|         match dir { |         self.grid.get(&dir.pos_ofs(self.guard_pos)) | ||||||
|             FacingDirection::Up => self.grid.get(self.guard_pos.0, self.guard_pos.1 - 1), |  | ||||||
|             FacingDirection::Down => self.grid.get(self.guard_pos.0, self.guard_pos.1 + 1), |  | ||||||
|             FacingDirection::Left => self.grid.get(self.guard_pos.0 - 1, self.guard_pos.1), |  | ||||||
|             FacingDirection::Right => self.grid.get(self.guard_pos.0 + 1, self.guard_pos.1), |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     /// Move one step in the facing direction, return if we are still inside the bounds |     /// Move one step in the facing direction, return if we are still inside the bounds | ||||||
|     fn step_guard<const RECORD_PATH: bool>(&mut self) -> StepOutcome { |     fn step_guard<const RECORD_PATH: bool>(&mut self) -> StepOutcome { | ||||||
|         let new_pos = self.guard_facing.pos_ofs(self.guard_pos); |         let new_pos = self.guard_facing.pos_ofs(self.guard_pos); | ||||||
|         if self |         if self | ||||||
|             .visited_from |             .visited_from | ||||||
|             .get(new_pos.0, new_pos.1) |             .get(&new_pos) | ||||||
|             .is_some_and(|dirs| dirs.contains(self.guard_facing.into())) |             .is_some_and(|dirs| dirs.contains(self.guard_facing.into())) | ||||||
|         { |         { | ||||||
|             return StepOutcome::LoopFound; |             StepOutcome::LoopFound | ||||||
|         } |         } else if self.grid.set(&new_pos, b'X').is_some() { | ||||||
|         if self.grid.set(new_pos.0, new_pos.1, b'X') { |  | ||||||
|             if RECORD_PATH { |             if RECORD_PATH { | ||||||
|                 self.path.push((new_pos, self.guard_facing)); |                 self.path.push((new_pos, self.guard_facing)); | ||||||
|             } |             } | ||||||
|             self.visited_from.set( |             self.visited_from.set( | ||||||
|                 new_pos.0, |                 &new_pos, | ||||||
|                 new_pos.1, |                 self.visited_from.get(&new_pos).unwrap() | self.guard_facing.into(), | ||||||
|                 self.visited_from.get(new_pos.0, new_pos.1).unwrap() | self.guard_facing.into(), |  | ||||||
|             ); |             ); | ||||||
|             self.guard_pos = new_pos; |             self.guard_pos = new_pos; | ||||||
|             StepOutcome::Continue |             StepOutcome::Continue | ||||||
| @@ -168,7 +164,7 @@ pub fn part1(map: &Map) -> u64 { | |||||||
|     let mut map = map.clone(); |     let mut map = map.clone(); | ||||||
|     map.run_guard::<false>(); |     map.run_guard::<false>(); | ||||||
|  |  | ||||||
|     (map.grid.count(b'X') + map.grid.count(b'-') + map.grid.count(b'|') + map.grid.count(b'^')) as u64 |     map.grid.count(&b'X') as u64 + 1 // 'X' path positions + 1 starting position | ||||||
| } | } | ||||||
|  |  | ||||||
| // PROBLEM 2 solution | // PROBLEM 2 solution | ||||||
| @@ -178,28 +174,19 @@ pub fn part2(input_map: &Map) -> u64 { | |||||||
|     let mut path_map = input_map.clone(); |     let mut path_map = input_map.clone(); | ||||||
|     path_map.run_guard::<true>(); |     path_map.run_guard::<true>(); | ||||||
|  |  | ||||||
|     let mut tested_position: grid::Grid<bool> = grid::Grid::new(path_map.grid.width() as i64); |     path_map | ||||||
|     tested_position.data.resize(path_map.grid.data.len(), false); |         .path | ||||||
|  |         .par_windows(2) | ||||||
|     let mut loop_count = 0u64; |         .filter(|prev_cur| { | ||||||
|     let mut last_posdir = (input_map.guard_pos, input_map.guard_facing); |             let last_posdir = prev_cur[0]; | ||||||
|  |  | ||||||
|     for ((x, y), dir) in path_map.path.iter() { |  | ||||||
|         if !tested_position.get(*x, *y).unwrap() { |  | ||||||
|             tested_position.set(*x, *y, true); |  | ||||||
|             let mut test_map = input_map.clone(); |             let mut test_map = input_map.clone(); | ||||||
|             test_map.grid.set(*x, *y, b'#'); |             test_map.grid.set(&prev_cur[1].0, b'#').unwrap(); | ||||||
|             test_map.guard_pos = last_posdir.0; |             test_map.guard_pos = last_posdir.0; | ||||||
|             test_map.guard_facing = last_posdir.1; |             test_map.guard_facing = last_posdir.1; | ||||||
|  |  | ||||||
|             if let RunOutcome::LoopFound = test_map.run_guard::<false>() { |             test_map.run_guard::<false>() == RunOutcome::LoopFound | ||||||
|                 loop_count += 1 |         }) | ||||||
|             } |         .count() as u64 | ||||||
|             last_posdir = ((*x, *y), *dir); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     loop_count |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
|   | |||||||
| @@ -43,7 +43,7 @@ impl AntennaMap { | |||||||
|                 let offset = (a.0 - b.0, a.1 - b.1); |                 let offset = (a.0 - b.0, a.1 - b.1); | ||||||
|                 for i in (start..).map_while(|i| if Some(i - start) != reps { Some(i as i64) } else { None }) { |                 for i in (start..).map_while(|i| if Some(i - start) != reps { Some(i as i64) } else { None }) { | ||||||
|                     let node_pos = (a.0 + i * offset.0, a.1 + i * offset.1); |                     let node_pos = (a.0 + i * offset.0, a.1 + i * offset.1); | ||||||
|                     if !antinodes.set(node_pos.0, node_pos.1, true) { |                     if antinodes.set(&node_pos, true).is_none() { | ||||||
|                         // left the grid |                         // left the grid | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
| @@ -58,14 +58,14 @@ impl AntennaMap { | |||||||
| #[aoc(day8, part1)] | #[aoc(day8, part1)] | ||||||
| pub fn part1(map: &AntennaMap) -> u64 { | pub fn part1(map: &AntennaMap) -> u64 { | ||||||
|     let antinodes = map.find_antinodes(1, Some(1)); |     let antinodes = map.find_antinodes(1, Some(1)); | ||||||
|     antinodes.count(true) as u64 |     antinodes.count(&true) as u64 | ||||||
| } | } | ||||||
|  |  | ||||||
| // PROBLEM 2 solution | // PROBLEM 2 solution | ||||||
| #[aoc(day8, part2)] | #[aoc(day8, part2)] | ||||||
| pub fn part2(map: &AntennaMap) -> u64 { | pub fn part2(map: &AntennaMap) -> u64 { | ||||||
|     let antinodes = map.find_antinodes(0, None); |     let antinodes = map.find_antinodes(0, None); | ||||||
|     antinodes.count(true) as u64 |     antinodes.count(&true) as u64 | ||||||
| } | } | ||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -1,15 +1,15 @@ | |||||||
| mod day11; |  | ||||||
| use aoc_runner_derive::aoc_lib; | use aoc_runner_derive::aoc_lib; | ||||||
|  |  | ||||||
| mod day1; | pub mod day1; | ||||||
| mod day2; | pub mod day2; | ||||||
| mod day3; | pub mod day3; | ||||||
| mod day4; | pub mod day4; | ||||||
| mod day5; | pub mod day5; | ||||||
| mod day6; | pub mod day6; | ||||||
| mod day7; | pub mod day7; | ||||||
| mod day8; | pub mod day8; | ||||||
| mod day9; | pub mod day9; | ||||||
| mod day10; | pub mod day10; | ||||||
|  | pub mod day11; | ||||||
|  |  | ||||||
| aoc_lib! { year = 2024 } | aoc_lib! { year = 2024 } | ||||||
|   | |||||||
| @@ -4,6 +4,42 @@ use std::{ | |||||||
|     iter::repeat, |     iter::repeat, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #[derive(Clone)] | ||||||
|  | pub struct Coord2d { | ||||||
|  |     pub x: i64, | ||||||
|  |     pub y: i64, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub trait AsCoord2d { | ||||||
|  |     fn to_coord(self) -> Coord2d; | ||||||
|  |     fn x(&self) -> i64; | ||||||
|  |     fn y(&self) -> i64; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl AsCoord2d for Coord2d { | ||||||
|  |     fn to_coord(self) -> Coord2d { | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  |     fn x(&self) -> i64 { | ||||||
|  |         self.x | ||||||
|  |     } | ||||||
|  |     fn y(&self) -> i64 { | ||||||
|  |         self.y | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl AsCoord2d for (i64, i64) { | ||||||
|  |     fn to_coord(self) -> Coord2d { | ||||||
|  |         Coord2d { x: self.0, y: self.1 } | ||||||
|  |     } | ||||||
|  |     fn x(&self) -> i64 { | ||||||
|  |         self.0 | ||||||
|  |     } | ||||||
|  |     fn y(&self) -> i64 { | ||||||
|  |         self.1 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| pub struct Grid<T> { | pub struct Grid<T> { | ||||||
|     pub data: Vec<T>, |     pub data: Vec<T>, | ||||||
| @@ -29,8 +65,8 @@ impl<T: Copy + Eq + PartialEq + Display + Debug> Grid<T> { | |||||||
|     pub fn height(&self) -> usize { |     pub fn height(&self) -> usize { | ||||||
|         return self.data.len() / self.width(); |         return self.data.len() / self.width(); | ||||||
|     } |     } | ||||||
|     fn pos(&self, x: i64, y: i64) -> i64 { |     fn pos<C: AsCoord2d>(&self, c: &C) -> i64 { | ||||||
|         y * self.width + x |         c.y() * self.width + c.x() | ||||||
|     } |     } | ||||||
|     pub fn coord(&self, pos: i64) -> Option<(i64, i64)> { |     pub fn coord(&self, pos: i64) -> Option<(i64, i64)> { | ||||||
|         if pos < 0 || pos >= self.data.len() as i64 { |         if pos < 0 || pos >= self.data.len() as i64 { | ||||||
| @@ -39,57 +75,58 @@ impl<T: Copy + Eq + PartialEq + Display + Debug> Grid<T> { | |||||||
|             Some((pos % self.width, pos / self.width)) |             Some((pos % self.width, pos / self.width)) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     fn valid_pos(&self, x: i64, y: i64) -> Option<usize> { |     fn valid_pos<C: AsCoord2d>(&self, c: &C) -> Option<usize> { | ||||||
|         if x < 0 || x >= self.width { |         if c.x() < 0 || c.x() >= self.width { | ||||||
|             return None; |             return None; | ||||||
|         } |         } | ||||||
|         if y < 0 || y >= self.data.len() as i64 / self.width { |         if c.y() < 0 || c.y() >= self.data.len() as i64 / self.width { | ||||||
|             return None; |             return None; | ||||||
|         } |         } | ||||||
|         let pos = self.pos(x, y); |         let pos = self.pos(c); | ||||||
|         if pos < 0 || pos as usize >= self.data.len() { |         if pos < 0 || pos as usize >= self.data.len() { | ||||||
|             return None; |             return None; | ||||||
|         } |         } | ||||||
|         self.pos(x, y).try_into().ok() |         self.pos(c).try_into().ok() | ||||||
|     } |     } | ||||||
|     pub fn get(&self, x: i64, y: i64) -> Option<T> { |     pub fn get<C: AsCoord2d>(&self, c: &C) -> Option<T> { | ||||||
|         match self.valid_pos(x, y) { |         match self.valid_pos(c) { | ||||||
|             Some(pos) => Some(self.data[pos]), |             Some(pos) => Some(self.data[pos]), | ||||||
|             None => None, |             None => None, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     pub fn set(&mut self, x: i64, y: i64, val: T) -> bool { |     pub fn set<C: AsCoord2d>(&mut self, c: &C, val: T) -> Option<T> { | ||||||
|         match self.valid_pos(x, y) { |         match self.valid_pos(c) { | ||||||
|             Some(pos) => { |             Some(pos) => { | ||||||
|  |                 let res = Some(self.data[pos]); | ||||||
|                 self.data[pos] = val; |                 self.data[pos] = val; | ||||||
|                 true |                 res | ||||||
|             } |             } | ||||||
|             None => false, |             None => None, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     pub fn row(&self, y: i64) -> Option<&[T]> { |     pub fn row(&self, y: i64) -> Option<&[T]> { | ||||||
|         if y < self.height() as i64 { |         if y < self.height() as i64 { | ||||||
|             Some(&self.data[self.pos(0, y) as usize..self.pos(self.width, y) as usize]) |             Some(&self.data[self.pos(&(0, y)) as usize..self.pos(&(self.width, y)) as usize]) | ||||||
|         } else { |         } else { | ||||||
|             None |             None | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn find(&self, haystack: T) -> Option<(i64, i64)> { |     pub fn find(&self, haystack: &T) -> Option<(i64, i64)> { | ||||||
|         self.coord( |         self.coord( | ||||||
|             self.data |             self.data | ||||||
|                 .iter() |                 .iter() | ||||||
|                 .enumerate() |                 .enumerate() | ||||||
|                 .find_map(|(pos, val)| if *val == haystack { Some(pos as i64) } else { None }) |                 .find_map(|(pos, val)| if val == haystack { Some(pos as i64) } else { None }) | ||||||
|                 .unwrap_or(-1), |                 .unwrap_or(-1), | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|     pub fn count(&self, haystack: T) -> usize { |     pub fn count(&self, haystack: &T) -> usize { | ||||||
|         self.data.iter().filter(|item| **item == haystack).count() |         self.data.iter().filter(|item| *item == haystack).count() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn forward_slice(&self, x: i64, y: i64, len: i64) -> Option<&[T]> { |     pub fn forward_slice<C: AsCoord2d>(&self, start: &C, len: i64) -> Option<&[T]> { | ||||||
|         let pos = (self.valid_pos(x, y), self.valid_pos(x + len - 1, y)); |         let pos = (self.valid_pos(start), self.valid_pos(&(start.x() + len - 1, start.y()))); | ||||||
|         match pos { |         match pos { | ||||||
|             (Some(pos1), Some(pos2)) => Some(&self.data[pos1..pos2 + 1]), |             (Some(pos1), Some(pos2)) => Some(&self.data[pos1..pos2 + 1]), | ||||||
|             _ => None, |             _ => None, | ||||||
| @@ -151,7 +188,7 @@ impl Display for Grid<u8> { | |||||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||||||
|         for y in 0..self.height() { |         for y in 0..self.height() { | ||||||
|             for x in 0..self.width() { |             for x in 0..self.width() { | ||||||
|                 f.write_fmt(format_args!("{}",self.get(x as i64, y as i64).unwrap() as char))?; |                 f.write_fmt(format_args!("{}", self.get(&(x as i64, y as i64)).unwrap() as char))?; | ||||||
|             } |             } | ||||||
|             f.write_char('\n')?; |             f.write_char('\n')?; | ||||||
|         } |         } | ||||||
| @@ -181,21 +218,21 @@ FBCG"; | |||||||
|     #[test] |     #[test] | ||||||
|     fn indexing() { |     fn indexing() { | ||||||
|         let grid = unchecked_load(); |         let grid = unchecked_load(); | ||||||
|         assert_eq!(grid.get(0, 0), Some(b'A')); |         assert_eq!(grid.get(&(0, 0)), Some(b'A')); | ||||||
|         assert_eq!(grid.get(3, 3), Some(b'G')); |         assert_eq!(grid.get(&(3, 3)), Some(b'G')); | ||||||
|         assert_eq!(grid.get(-1, 0), None); |         assert_eq!(grid.get(&(-1, 0)), None); | ||||||
|         assert_eq!(grid.get(0, -1), None); |         assert_eq!(grid.get(&(0, -1)), None); | ||||||
|         assert_eq!(grid.get(5, 0), None); |         assert_eq!(grid.get(&(5, 0)), None); | ||||||
|         assert_eq!(grid.get(0, 5), None); |         assert_eq!(grid.get(&(0, 5)), None); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn forward_slice() { |     fn forward_slice() { | ||||||
|         let grid = unchecked_load(); |         let grid = unchecked_load(); | ||||||
|         assert_eq!(grid.forward_slice(0, 0, 2), Some(b"AB".as_slice())); |         assert_eq!(grid.forward_slice(&(0, 0), 2), Some(b"AB".as_slice())); | ||||||
|         assert_eq!(grid.forward_slice(2, 0, 2), Some(b"CD".as_slice())); |         assert_eq!(grid.forward_slice(&(2, 0), 2), Some(b"CD".as_slice())); | ||||||
|         assert_eq!(grid.forward_slice(2, 0, 3), None); |         assert_eq!(grid.forward_slice(&(2, 0), 3), None); | ||||||
|         assert_eq!(grid.forward_slice(0, 2, 4), Some(b"IJKL".as_slice())); |         assert_eq!(grid.forward_slice(&(0, 2), 4), Some(b"IJKL".as_slice())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user