Advent of Code solutions
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Most of initial utils done

Ben C ffd2a3fd 79ff0503

+2444 -114
+1 -1
Cargo.toml
··· 21 21 22 22 [[bin]] 23 23 name = "advent" 24 - path = "src/main.rs" 24 + path = "src/main.rs"
+14 -5
core/src/bootstrap.rs
··· 4 4 5 5 use crate::MAX_DAY; 6 6 7 - 8 7 const DAY_TEMPLATE: &str = " 9 8 use core::{Day, day_stuff, ex_for_day}; 10 9 ··· 119 118 std::fs::write(cargo_path, contents).unwrap(); 120 119 } 121 120 122 - fn replace_year_list(new_year: &str ) { 121 + fn replace_year_list(new_year: &str) { 123 122 let main = include_str!("../../src/main.rs"); 124 123 125 124 let global_runner_pattern = Regex::new(r"global_runner!\(([\d,]+)\)").unwrap(); ··· 128 127 129 128 let full = matches.get(0).unwrap().as_str(); 130 129 131 - let mut years = matches.get(1).unwrap().as_str().split(",").map(|s| s.parse::<usize>().unwrap()).collect::<Vec<_>>(); 130 + let mut years = matches 131 + .get(1) 132 + .unwrap() 133 + .as_str() 134 + .split(",") 135 + .map(|s| s.parse::<usize>().unwrap()) 136 + .collect::<Vec<_>>(); 132 137 133 138 years.push(new_year.parse::<usize>().unwrap()); 134 139 135 140 years.sort(); 136 141 137 - let new_years = years.iter().map(|y| y.to_string()).collect::<Vec<_>>().join(","); 142 + let new_years = years 143 + .iter() 144 + .map(|y| y.to_string()) 145 + .collect::<Vec<_>>() 146 + .join(","); 138 147 139 148 let new_main = main.replace(full, &format!("global_runner!({})", new_years)); 140 149 ··· 163 172 164 173 replace_cargo_dependencies(year); 165 174 replace_year_list(year); 166 - } 175 + }
+28 -10
core/src/day.rs
··· 3 3 #[macro_export] 4 4 macro_rules! ex_for_day { 5 5 ($day:literal, $part:literal) => { 6 - include_str!(concat!("examples/day_", stringify!($day), "/", stringify!($part), ".txt")) 6 + include_str!(concat!( 7 + "examples/day_", 8 + stringify!($day), 9 + "/", 10 + stringify!($part), 11 + ".txt" 12 + )) 7 13 }; 8 14 } 9 15 ··· 11 17 macro_rules! day_stuff { 12 18 ($day:literal, $e_1:literal, $e_2:literal) => { 13 19 day_stuff!($day, $e_1, $e_2, String); 14 - 20 + 15 21 fn parse_input(input: &str) -> Self::Input { 16 22 input.to_string() 17 23 } ··· 19 25 20 26 ($day:literal, $e_1:literal, $e_2:literal, $i: ty) => { 21 27 type Input = $i; 22 - 28 + 23 29 const DAY: usize = $day; 24 30 const EXAMPLE_INPUT_1: &'static str = ex_for_day!($day, 1); 25 31 const EXAMPLE_INPUT_2: &'static str = ex_for_day!($day, 2); 26 32 const EXPECTED_1: &'static str = $e_1; 27 - const EXPECTED_2: &'static str = $e_2; 33 + const EXPECTED_2: &'static str = $e_2; 28 34 } 29 35 } 30 36 ··· 40 46 /// Then, any runner can use `run_part` to run a part of the day with a given input or the example input. 41 47 /// 42 48 pub trait Day { 43 - 44 49 type Input; 45 50 46 51 const DAY: usize = 0; ··· 68 73 2 => Self::part_2(input), 69 74 _ => panic!("Invalid part number"), 70 75 }; 71 - println!("Day {} Part {}: {} ({}ms)", Self::DAY, part, solution.as_ref().unwrap_or(&"Not implemented".to_string()), instant.elapsed().as_millis()); 76 + println!( 77 + "Day {} Part {}: {} ({}ms)", 78 + Self::DAY, 79 + part, 80 + solution.as_ref().unwrap_or(&"Not implemented".to_string()), 81 + instant.elapsed().as_millis() 82 + ); 72 83 solution 73 84 } 74 85 75 86 fn run_all_parts(extra_indent: &str) { 76 - println!("{extra_indent}Day {day}:", extra_indent = extra_indent, day = Self::DAY); 87 + println!( 88 + "{extra_indent}Day {day}:", 89 + extra_indent = extra_indent, 90 + day = Self::DAY 91 + ); 77 92 for part in 1..=2 { 78 93 let part_time = Instant::now(); 79 94 let solution = match part { ··· 81 96 2 => Self::part_2(Self::parse_input(Self::EXAMPLE_INPUT_2)), 82 97 _ => panic!("Invalid part number"), 83 98 }; 84 - println!("{extra_indent} Part {}: {} ({}ms)", part, solution.as_ref().unwrap_or(&"Not implemented".to_string()), part_time.elapsed().as_millis()); 99 + println!( 100 + "{extra_indent} Part {}: {} ({}ms)", 101 + part, 102 + solution.as_ref().unwrap_or(&"Not implemented".to_string()), 103 + part_time.elapsed().as_millis() 104 + ); 85 105 } 86 106 } 87 107 ··· 119 139 struct TestDay; 120 140 121 141 impl Day for TestDay { 122 - 123 142 type Input = String; 124 143 125 144 const EXAMPLE_INPUT_1: &'static str = "Hello, world!"; ··· 144 163 struct TestDay2; 145 164 146 165 impl Day for TestDay2 { 147 - 148 166 type Input = Vec<String>; 149 167 150 168 const EXAMPLE_INPUT_1: &'static str = "A\nB\nC";
+4 -4
core/src/lib.rs
··· 1 + mod bootstrap; 1 2 mod day; 2 - mod year; 3 3 mod parser; 4 - mod bootstrap; 4 + mod year; 5 5 6 6 pub const MAX_DAY: usize = 25; 7 7 8 + pub use bootstrap::make_year; 8 9 pub use day::Day; 10 + pub use parser::{get_dp_and_input, get_ydp_and_input, Selection, DP, YDP}; 9 11 pub use year::Year; 10 - pub use parser::{Selection, YDP, DP, get_dp_and_input, get_ydp_and_input}; 11 - pub use bootstrap::make_year;
+10 -20
core/src/parser.rs
··· 1 - use std::io::{stdin, Read}; 2 1 use std::env::args; 2 + use std::io::{stdin, Read}; 3 3 #[derive(Clone, Debug)] 4 4 pub enum Selection { 5 5 All, ··· 7 7 } 8 8 9 9 impl Selection { 10 - 11 10 fn parse(input: &str) -> Self { 12 11 if input == "*" { 13 12 Self::All ··· 16 15 Self::Single(input) 17 16 } 18 17 } 19 - 20 18 } 21 19 22 20 #[derive(Clone, Debug)] ··· 31 29 }; 32 30 33 31 impl DP { 34 - 35 32 fn parse(input: &str) -> Self { 36 33 let mut split = input.split(':'); 37 34 38 35 let day = split.next().map(Selection::parse).unwrap_or(Selection::All); 39 36 let part = split.next().map(Selection::parse).unwrap_or(Selection::All); 40 37 41 - Self { 42 - day, 43 - part, 44 - } 38 + Self { day, part } 45 39 } 46 - 47 40 } 48 41 49 42 #[derive(Clone, Debug)] ··· 54 47 } 55 48 56 49 impl YDP { 57 - 58 50 fn parse(input: &str) -> Self { 59 51 let mut split = input.split(':'); 60 52 ··· 62 54 let day = split.next().map(Selection::parse).unwrap_or(Selection::All); 63 55 let part = split.next().map(Selection::parse).unwrap_or(Selection::All); 64 56 65 - Self { 66 - year, 67 - day, 68 - part, 69 - } 57 + Self { year, day, part } 70 58 } 71 59 72 60 pub fn to_dp(&self) -> DP { ··· 75 63 part: self.part.clone(), 76 64 } 77 65 } 78 - 79 66 } 80 67 81 68 pub fn get_dp_and_input() -> (DP, Option<String>) { ··· 86 73 let input = args.next().map(|s| s.trim().to_string()).map(|i| { 87 74 if i == "-" { 88 75 let mut input = String::new(); 89 - stdin().read_to_string(&mut input).expect("Failed to read input"); 76 + stdin() 77 + .read_to_string(&mut input) 78 + .expect("Failed to read input"); 90 79 input.trim().to_string() 91 80 } else { 92 81 i ··· 97 86 } 98 87 99 88 pub fn get_ydp_and_input(args: Vec<String>) -> (YDP, Option<String>) { 100 - 101 89 let mut args = args.into_iter(); 102 90 103 91 let ydp = args.next().map(|s| YDP::parse(&s.trim())).unwrap_or(YDP { ··· 109 97 let input = args.next().map(|s| s.trim().to_string()).map(|i| { 110 98 if i == "-" { 111 99 let mut input = String::new(); 112 - stdin().read_to_string(&mut input).expect("Failed to read input"); 100 + stdin() 101 + .read_to_string(&mut input) 102 + .expect("Failed to read input"); 113 103 input.trim().to_string() 114 104 } else { 115 105 i ··· 117 107 }); 118 108 119 109 (ydp, input) 120 - } 110 + }
+8 -10
core/src/year.rs
··· 1 - use crate::parser::{DP, Selection}; 1 + use crate::parser::{Selection, DP}; 2 2 3 3 use super::MAX_DAY; 4 4 ··· 20 20 match dp.day { 21 21 Selection::All => { 22 22 Self::solve_all_days(); 23 - }, 24 - Selection::Single(day) => { 25 - match dp.part { 26 - Selection::All => { 27 - Self::solve_day_both_parts(day, ""); 28 - }, 29 - Selection::Single(part) => { 30 - Self::solve_day(day, part, input); 31 - }, 23 + } 24 + Selection::Single(day) => match dp.part { 25 + Selection::All => { 26 + Self::solve_day_both_parts(day, ""); 27 + } 28 + Selection::Single(part) => { 29 + Self::solve_day(day, part, input); 32 30 } 33 31 }, 34 32 }
+86 -25
macros/src/lib.rs
··· 5 5 use proc_macro::TokenStream; 6 6 7 7 fn make_day_mods() -> String { 8 - (1..=MAX_DAY).map(|day| format!("mod day_{day};", day = day)).collect::<Vec<_>>().join("\n") 8 + (1..=MAX_DAY) 9 + .map(|day| format!("mod day_{day};", day = day)) 10 + .collect::<Vec<_>>() 11 + .join("\n") 9 12 } 10 13 11 14 fn make_use_days() -> String { 12 - (1..=MAX_DAY).map(|day| format!("use day_{day}::Day{day};", day = day)).collect::<Vec<_>>().join("\n") 15 + (1..=MAX_DAY) 16 + .map(|day| format!("use day_{day}::Day{day};", day = day)) 17 + .collect::<Vec<_>>() 18 + .join("\n") 13 19 } 14 20 15 21 fn make_day_match(inner: &str) -> String { 16 - (1..=MAX_DAY).map(|day| format!("{day} => {},", inner.replace("{day}", &day.to_string()))).collect::<Vec<_>>().join("\n") 22 + (1..=MAX_DAY) 23 + .map(|day| format!("{day} => {},", inner.replace("{day}", &day.to_string()))) 24 + .collect::<Vec<_>>() 25 + .join("\n") 17 26 } 18 27 19 28 fn make_day_tests() -> String { 20 - (1..=MAX_DAY).map(|day| format!(" 29 + (1..=MAX_DAY) 30 + .map(|day| { 31 + format!( 32 + " 21 33 #[test] 22 34 fn test_day_{day}_part_1() {{ 23 35 Day{day}::assert_part_1(); ··· 26 38 #[test] 27 39 fn test_day_{day}_part_2() {{ 28 40 Day{day}::assert_part_2(); 29 - }}")).collect::<Vec<_>>().join("\n") 41 + }}" 42 + ) 43 + }) 44 + .collect::<Vec<_>>() 45 + .join("\n") 30 46 } 31 47 32 48 fn get_solve_day() -> String { 33 49 let inner = make_day_match("Day{day}::run_part(part, input)"); 34 - format!(" 50 + format!( 51 + " 35 52 fn solve_day(day: usize, part: usize, input: Option<&str>) -> Option<String> {{ 36 53 match day {{ 37 54 {inner} 38 55 _ => None, 39 56 }} 40 - }}", inner = inner) 57 + }}", 58 + inner = inner 59 + ) 41 60 } 42 61 43 62 fn get_solve_day_both_parts() -> String { 44 63 let inner = make_day_match("Day{day}::run_all_parts(extra_indent)"); 45 - format!(" 64 + format!( 65 + " 46 66 fn solve_day_both_parts(day: usize, extra_indent: &str) {{ 47 67 match day {{ 48 68 {inner} 49 69 _ => (), 50 70 }} 51 - }}", inner = inner) 71 + }}", 72 + inner = inner 73 + ) 52 74 } 53 75 54 76 fn make_year_struct(year: &str) -> String { 55 - format!(" 77 + format!( 78 + " 56 79 pub struct Year{year}; 57 80 58 81 impl Year for Year{year} {{ ··· 61 84 {solve_day} 62 85 63 86 {solve_day_both_parts} 64 - }}", solve_day = get_solve_day(), solve_day_both_parts = get_solve_day_both_parts()) 87 + }}", 88 + solve_day = get_solve_day(), 89 + solve_day_both_parts = get_solve_day_both_parts() 90 + ) 65 91 } 66 92 67 93 fn make_tests() -> String { 68 - format!(" 94 + format!( 95 + " 69 96 #[cfg(test)] 70 97 mod tests {{ 71 98 use super::*; 72 99 use core::{{Day, Year}}; 73 100 74 101 {day_tests} 75 - }}", day_tests = make_day_tests()) 102 + }}", 103 + day_tests = make_day_tests() 104 + ) 76 105 } 77 106 78 107 #[proc_macro] ··· 86 115 87 116 let tests = make_tests(); 88 117 89 - format!(" 118 + format!( 119 + " 90 120 {mods} 91 121 92 122 use core::{{Year, Day}}; ··· 95 125 {year_struct} 96 126 97 127 {tests} 98 - ").parse::<TokenStream>().unwrap() 128 + " 129 + ) 130 + .parse::<TokenStream>() 131 + .unwrap() 99 132 } 100 133 101 134 #[proc_macro] 102 135 pub fn year_runner(item: TokenStream) -> TokenStream { 103 136 let year = item.to_string(); 104 137 105 - format!(" 138 + format!( 139 + " 106 140 use core::{{Year, get_dp_and_input}}; 107 141 108 142 use y_{year}::Year{year}; ··· 110 144 fn main() {{ 111 145 let (dp, input) = get_dp_and_input(); 112 146 Year{year}::run_dp(input.as_deref(), dp); 113 - }}").parse::<TokenStream>().unwrap() 147 + }}" 148 + ) 149 + .parse::<TokenStream>() 150 + .unwrap() 114 151 } 115 152 116 153 fn make_year_match(years: &Vec<&str>, inner: &str) -> String { 117 - years.iter().map(|year| format!("{year} => {},", inner.replace("{year}", &year.to_string()))).collect::<Vec<_>>().join("\n") 154 + years 155 + .iter() 156 + .map(|year| format!("{year} => {},", inner.replace("{year}", &year.to_string()))) 157 + .collect::<Vec<_>>() 158 + .join("\n") 118 159 } 119 160 120 161 fn make_year_uses(years: &Vec<&str>) -> String { 121 - years.iter().map(|year| format!("use y_{year}::Year{year};", year = year)).collect::<Vec<_>>().join("\n") 162 + years 163 + .iter() 164 + .map(|year| format!("use y_{year}::Year{year};", year = year)) 165 + .collect::<Vec<_>>() 166 + .join("\n") 122 167 } 123 168 124 169 fn make_run_all_years(years: &Vec<&str>) -> String { 125 - years.iter().map(|year| format!("Year{year}::run_dp(input.as_deref(), dp.clone());", year = year)).collect::<Vec<_>>().join("\n") 170 + years 171 + .iter() 172 + .map(|year| { 173 + format!( 174 + "Year{year}::run_dp(input.as_deref(), dp.clone());", 175 + year = year 176 + ) 177 + }) 178 + .collect::<Vec<_>>() 179 + .join("\n") 126 180 } 127 181 128 182 fn make_run_year(years: &Vec<&str>) -> String { 129 183 let inner = make_year_match(years, "Year{year}::run_dp(input.as_deref(), dp)"); 130 - format!(" 184 + format!( 185 + " 131 186 fn run_year(year: usize, dp: DP, input: Option<&str>) {{ 132 187 match year {{ 133 188 {inner} ··· 135 190 println!(\"Unknown year: {{year}}\"); 136 191 }} 137 192 }} 138 - }}", inner = inner) 193 + }}", 194 + inner = inner 195 + ) 139 196 } 140 197 141 198 #[proc_macro] ··· 147 204 let run_all_years = make_run_all_years(&years); 148 205 let run_year = make_run_year(&years); 149 206 150 - format!(" 207 + format!( 208 + " 151 209 {year_uses} 152 210 153 211 {run_year} 154 212 155 213 fn run_all_years(dp: &DP, input: Option<String>) {{ 156 214 {run_all_years} 157 - }}").parse::<TokenStream>().unwrap() 158 - } 215 + }}" 216 + ) 217 + .parse::<TokenStream>() 218 + .unwrap() 219 + }
+15 -17
src/main.rs
··· 1 - use core::{get_ydp_and_input, make_year, Year, Selection, YDP, DP}; 1 + use core::{get_ydp_and_input, make_year, Selection, Year, DP, YDP}; 2 2 use macros::global_runner; 3 3 4 4 global_runner!(2023); ··· 9 9 match ydp.year { 10 10 Selection::All => { 11 11 run_all_years(&dp, input); 12 - }, 12 + } 13 13 Selection::Single(year) => { 14 14 run_year(year, dp, input.as_deref()); 15 - }, 15 + } 16 16 } 17 17 } 18 18 ··· 22 22 let command = args.get(0); 23 23 24 24 match command { 25 - Some(command) => { 26 - match command.as_str() { 27 - "new" => { 28 - let year = args.get(1).expect("No year provided"); 29 - make_year(year); 30 - }, 31 - "solve" | "run" => { 32 - let (ydp, input) = get_ydp_and_input(args[1..].to_vec()); 33 - run_ydp(ydp, input); 34 - } 35 - _ => { 36 - println!("Unknown command: {}", command); 37 - println!("Available commands: new, solve"); 38 - } 25 + Some(command) => match command.as_str() { 26 + "new" => { 27 + let year = args.get(1).expect("No year provided"); 28 + make_year(year); 29 + } 30 + "solve" | "run" => { 31 + let (ydp, input) = get_ydp_and_input(args[1..].to_vec()); 32 + run_ydp(ydp, input); 33 + } 34 + _ => { 35 + println!("Unknown command: {}", command); 36 + println!("Available commands: new, solve"); 39 37 } 40 38 }, 41 39 None => {
-4
utils/Cargo.toml
··· 2 2 name = "utils" 3 3 version = "0.1.0" 4 4 edition = "2021" 5 - 6 - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 - 8 - [dependencies]
+30
utils/src/day_utils.rs
··· 1 + #[macro_export] 2 + macro_rules! yippee { 3 + () => { 4 + fn part_2(_: Self::Input) -> Option<String> { 5 + Some("🥳".to_string()) 6 + } 7 + }; 8 + } 9 + 10 + #[macro_export] 11 + macro_rules! grid_day { 12 + ($day:literal, $e_1:literal, $e_2:literal, $t:ty) => { 13 + day_stuff!($day, $e_1, $e_2, utils::grid::Grid<$t>); 14 + 15 + fn parse_input(input: &str) -> Self::Input { 16 + Self::Input::parse(input) 17 + } 18 + }; 19 + } 20 + 21 + #[macro_export] 22 + macro_rules! lines_day { 23 + ($day:literal, $e_1:literal, $e_2:literal, $t:ty) => { 24 + day_stuff!($day, $e_1, $e_2, Vec<$t>); 25 + 26 + fn parse_input(input: &str) -> Self::Input { 27 + input.lines().map(|l| l.parse().unwrap()).collect() 28 + } 29 + }; 30 + }
+146
utils/src/dir.rs
··· 1 + /// Module containing utilities related to direction and movement. 2 + use crate::pos::Position; 3 + 4 + /// Trait used to define an object that can be used to move around a grid. 5 + /// 6 + /// This is meant for complex scenarios where you want to move around a grid in a non-standard way. 7 + /// By implementing this trait you can use various methods from the [Position] struct to move around. 8 + /// 9 + /// # Implementing 10 + /// 11 + /// Implementing this trait requires you to define a `get_kernel` method that returns a `Position`. 12 + /// This position is used to move around the grid by applying it to the current position. 13 + /// 14 + /// # Examples 15 + /// 16 + /// ``` 17 + /// use utils::prelude::*; 18 + /// 19 + /// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] 20 + /// struct RightBy(usize); 21 + /// 22 + /// impl Movement for RightBy { 23 + /// fn get_kernel(&self) -> Position { 24 + /// Position::new(self.0 as isize, 0) 25 + /// } 26 + /// } 27 + /// 28 + /// let pos = Position::new(0, 0); 29 + /// assert_eq!(pos.move_dir(RightBy(1)), Position::new(1, 0)); 30 + /// ``` 31 + /// 32 + /// # See also 33 + /// 34 + /// - [Direction] is a simple implementation of this trait. 35 + /// - [Position] is the main user of this trait. 36 + /// 37 + pub trait Movement: std::fmt::Debug + Copy + Clone + PartialEq + std::hash::Hash { 38 + fn get_kernel(&self) -> Position; 39 + } 40 + 41 + /// The four cardinal directions. 42 + /// Useful for iterating over all four directions. 43 + pub const CARDINALS: [Direction; 4] = [ 44 + Direction::North, 45 + Direction::South, 46 + Direction::East, 47 + Direction::West, 48 + ]; 49 + 50 + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] 51 + /// The four cardinal directions. 52 + /// This is a simple implementation of the [Movement] trait. 53 + /// 54 + /// # Examples 55 + /// 56 + /// ``` 57 + /// use utils::prelude::*; 58 + /// 59 + /// let pos = Position::new(0, 0); 60 + /// assert_eq!(pos.move_dir(Direction::North), Position::new(0, -1)); 61 + /// assert_eq!(pos.move_dir(Direction::South), Position::new(0, 1)); 62 + /// assert_eq!(pos.move_dir(Direction::East), Position::new(1, 0)); 63 + /// assert_eq!(pos.move_dir(Direction::West), Position::new(-1, 0)); 64 + /// ``` 65 + /// 66 + pub enum Direction { 67 + North, 68 + South, 69 + East, 70 + West, 71 + } 72 + 73 + impl Direction { 74 + /// Returns the direction that is opposite to the current one. 75 + /// 76 + /// # Examples 77 + /// 78 + /// ``` 79 + /// use utils::prelude::*; 80 + /// 81 + /// assert_eq!(Direction::North.opposite(), Direction::South); 82 + /// assert_eq!(Direction::South.opposite(), Direction::North); 83 + /// assert_eq!(Direction::East.opposite(), Direction::West); 84 + /// assert_eq!(Direction::West.opposite(), Direction::East); 85 + /// ``` 86 + /// 87 + pub fn opposite(&self) -> Self { 88 + match self { 89 + Self::North => Self::South, 90 + Self::South => Self::North, 91 + Self::East => Self::West, 92 + Self::West => Self::East, 93 + } 94 + } 95 + 96 + /// Returns the direction that is 90 degrees to the current one. 97 + /// 98 + /// # Examples 99 + /// 100 + /// ``` 101 + /// use utils::prelude::*; 102 + /// 103 + /// assert_eq!(Direction::North.ninety_deg(true), Direction::East); 104 + /// assert_eq!(Direction::North.ninety_deg(false), Direction::West); 105 + /// 106 + /// assert_eq!(Direction::South.ninety_deg(true), Direction::West); 107 + /// assert_eq!(Direction::South.ninety_deg(false), Direction::East); 108 + /// ``` 109 + /// 110 + pub fn ninety_deg(&self, clockwise: bool) -> Self { 111 + match (self, clockwise) { 112 + (Self::North, true) => Self::East, 113 + (Self::North, false) => Self::West, 114 + (Self::South, true) => Self::West, 115 + (Self::South, false) => Self::East, 116 + (Self::East, true) => Self::South, 117 + (Self::East, false) => Self::North, 118 + (Self::West, true) => Self::North, 119 + (Self::West, false) => Self::South, 120 + } 121 + } 122 + } 123 + 124 + impl From<Position> for Direction { 125 + fn from(pos: Position) -> Self { 126 + let pos = pos.normalize(); 127 + match (pos.x, pos.y) { 128 + (0, -1) => Self::North, 129 + (0, 1) => Self::South, 130 + (1, 0) => Self::East, 131 + (-1, 0) => Self::West, 132 + _ => panic!("Invalid position"), 133 + } 134 + } 135 + } 136 + 137 + impl Movement for Direction { 138 + fn get_kernel(&self) -> Position { 139 + match self { 140 + Direction::North => Position::new(0, -1), 141 + Direction::South => Position::new(0, 1), 142 + Direction::East => Position::new(1, 0), 143 + Direction::West => Position::new(-1, 0), 144 + } 145 + } 146 + }
+24
utils/src/geom.rs
··· 1 + use crate::pos::Position; 2 + 3 + /// Get the area of a polygon given its vertices. 4 + /// 5 + /// This is the shoelace formula. 6 + /// 7 + pub fn area(verts: &[Position]) -> isize { 8 + verts 9 + .windows(2) 10 + .map(|w| ((w[0].x) * (w[1].y)) - ((w[0].y) * (w[1].x))) 11 + .sum::<isize>() 12 + / 2 13 + } 14 + 15 + /// Get the perimeter of a polygon given its vertices. 16 + /// 17 + /// This is the sum of the distances between each vertex. 18 + /// 19 + pub fn perimeter(verts: &[Position]) -> isize { 20 + verts 21 + .windows(2) 22 + .map(|w| (w[0].x - w[1].x).abs() + (w[0].y - w[1].y).abs()) 23 + .sum::<isize>() 24 + }
+938
utils/src/grid.rs
··· 1 + use crate::{ 2 + dir::{Direction, Movement, CARDINALS}, 3 + pos::Position, 4 + }; 5 + 6 + /// A 2D integer grid of values. 7 + /// 8 + /// This grid is represented by a vector of vectors. 9 + /// 10 + /// # Examples 11 + /// 12 + /// ``` 13 + /// use utils::prelude::*; 14 + /// 15 + /// let data = vec![ 16 + /// vec![1, 2, 3], 17 + /// vec![4, 5, 6], 18 + /// vec![7, 8, 9], 19 + /// ]; 20 + /// 21 + /// let grid = Grid::new(data); 22 + /// 23 + /// assert_eq!(grid.get(Position::new(0, 0)), Some(&1)); 24 + /// assert_eq!(grid.get(Position::new(1, 1)), Some(&5)); 25 + /// assert_eq!(grid.get(Position::new(2, 2)), Some(&9)); 26 + /// ``` 27 + /// 28 + pub struct Grid<T> { 29 + data: Vec<Vec<T>>, 30 + } 31 + 32 + impl<T> Grid<T> { 33 + /// Create a new grid from a vector of vectors. 34 + pub fn new(data: Vec<Vec<T>>) -> Self { 35 + Self { data } 36 + } 37 + 38 + /// Parse a grid from a string, this will convert each character into `T` via `From<char>`. 39 + /// 40 + /// Use the `tiles!` macro to easily create an enum that implements `From<char>`. 41 + /// 42 + /// # Examples 43 + /// 44 + /// ``` 45 + /// use utils::prelude::*; 46 + /// 47 + /// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 48 + /// enum Tile { 49 + /// Floor, 50 + /// Wall, 51 + /// } 52 + /// 53 + /// impl From<char> for Tile { 54 + /// fn from(c: char) -> Self { 55 + /// match c { 56 + /// '.' => Self::Floor, 57 + /// '#' => Self::Wall, 58 + /// _ => panic!("Invalid tile {c}"), 59 + /// } 60 + /// } 61 + /// } 62 + /// 63 + /// let input = ".#.\n#.#\n.#."; 64 + /// let grid = Grid::<Tile>::parse(input); 65 + /// 66 + /// assert_eq!(grid.get(Position::new(0, 0)), Some(&Tile::Floor)); 67 + /// assert_eq!(grid.get(Position::new(1, 0)), Some(&Tile::Wall)); 68 + /// assert_eq!(grid.get(Position::new(2, 0)), Some(&Tile::Floor)); 69 + /// assert_eq!(grid.get(Position::new(1, 1)), Some(&Tile::Floor)); 70 + /// ``` 71 + /// 72 + /// Using `tiles!`... 73 + /// 74 + /// ``` 75 + /// use utils::prelude::*; 76 + /// use utils::tiles; 77 + /// 78 + /// tiles!(Tile, [ 79 + /// '.' => Floor, 80 + /// '#' => Wall, 81 + /// ]); 82 + /// 83 + /// let input = ".#.\n#.#\n.#."; 84 + /// let grid = Grid::<Tile>::parse(input); 85 + /// 86 + /// assert_eq!(grid.get(Position::new(0, 0)), Some(&Tile::Floor)); 87 + /// assert_eq!(grid.get(Position::new(1, 0)), Some(&Tile::Wall)); 88 + /// assert_eq!(grid.get(Position::new(2, 0)), Some(&Tile::Floor)); 89 + /// assert_eq!(grid.get(Position::new(1, 1)), Some(&Tile::Floor)); 90 + /// ``` 91 + /// 92 + pub fn parse(input: &str) -> Self 93 + where 94 + T: From<char>, 95 + { 96 + let data = input 97 + .lines() 98 + .map(|line| line.chars().map(|c| c.into()).collect()) 99 + .collect(); 100 + Self::new(data) 101 + } 102 + 103 + /// Return the width of the grid. 104 + pub fn width(&self) -> usize { 105 + self.data[0].len() 106 + } 107 + 108 + /// Return the height of the grid. 109 + pub fn height(&self) -> usize { 110 + self.data.len() 111 + } 112 + 113 + /// Get the size of the grid. 114 + pub fn size(&self) -> (usize, usize) { 115 + (self.width(), self.height()) 116 + } 117 + 118 + /// Get the bounds of the grid. 119 + /// 120 + /// (This is the same as `self.size()` with -1 added to each component) 121 + pub fn bounds(&self) -> (usize, usize) { 122 + (self.width() - 1, self.height() - 1) 123 + } 124 + 125 + /// Get a value from the grid at the given position. 126 + /// 127 + /// # Examples 128 + /// 129 + /// ``` 130 + /// use utils::prelude::*; 131 + /// 132 + /// let data = vec![ 133 + /// vec![1, 2, 3], 134 + /// vec![4, 5, 6], 135 + /// vec![7, 8, 9], 136 + /// ]; 137 + /// 138 + /// let grid = Grid::new(data); 139 + /// assert_eq!(grid.get(Position::new(0, 0)), Some(&1)); 140 + /// assert_eq!(grid.get(Position::new(1, 1)), Some(&5)); 141 + /// assert_eq!(grid.get(Position::new(2, 2)), Some(&9)); 142 + /// assert_eq!(grid.get(Position::new(3, 3)), None); 143 + /// ``` 144 + /// 145 + pub fn get(&self, pos: Position) -> Option<&T> { 146 + self.data 147 + .get(pos.y as usize) 148 + .and_then(|row| row.get(pos.x as usize)) 149 + } 150 + 151 + /// Get a value from the grid at the given position, 152 + /// panicking if the position is out of bounds. 153 + /// 154 + /// # Examples 155 + /// 156 + /// ``` 157 + /// use utils::prelude::*; 158 + /// 159 + /// let data = vec![ 160 + /// vec![1, 2, 3], 161 + /// vec![4, 5, 6], 162 + /// vec![7, 8, 9], 163 + /// ]; 164 + /// 165 + /// let grid = Grid::new(data); 166 + /// 167 + /// assert_eq!(grid.unsafe_get(Position::new(0, 0)), &1); 168 + /// assert_eq!(grid.unsafe_get(Position::new(1, 1)), &5); 169 + /// ``` 170 + /// 171 + pub fn unsafe_get(&self, pos: Position) -> &T { 172 + &self.data[pos.y as usize][pos.x as usize] 173 + } 174 + 175 + /// Get the value at the given position, wrapping around the grid if necessary. 176 + /// 177 + /// # Examples 178 + /// 179 + /// ``` 180 + /// use utils::prelude::*; 181 + /// 182 + /// let data = vec![ 183 + /// vec![1, 2, 3], 184 + /// vec![4, 5, 6], 185 + /// vec![7, 8, 9], 186 + /// ]; 187 + /// 188 + /// let grid = Grid::new(data); 189 + /// assert_eq!(grid.get_wrapped(Position::new(0, 0)), &1); 190 + /// assert_eq!(grid.get_wrapped(Position::new(1, 1)), &5); 191 + /// assert_eq!(grid.get_wrapped(Position::new(2, 2)), &9); 192 + /// assert_eq!(grid.get_wrapped(Position::new(3, 3)), &1); 193 + /// assert_eq!(grid.get_wrapped(Position::new(-1, -1)), &9); 194 + /// ``` 195 + /// 196 + pub fn get_wrapped(&self, pos: Position) -> &T { 197 + let wrapped_pos = pos.bind(self.size()); 198 + &self.data[wrapped_pos.1][wrapped_pos.0] 199 + } 200 + 201 + /// Iterate over a row of the grid. 202 + /// 203 + /// # Examples 204 + /// 205 + /// ``` 206 + /// use utils::prelude::*; 207 + /// 208 + /// let data = vec![ 209 + /// vec![1, 2, 3], 210 + /// vec![4, 5, 6], 211 + /// vec![7, 8, 9], 212 + /// ]; 213 + /// 214 + /// let grid = Grid::new(data); 215 + /// 216 + /// assert_eq!(grid.iter_row(0).unwrap().collect::<Vec<_>>(), vec![&1, &2, &3]); 217 + /// assert_eq!(grid.iter_row(1).unwrap().sum::<usize>(), 4+5+6); 218 + /// assert!(grid.iter_row(8).is_none()); 219 + /// ``` 220 + /// 221 + pub fn iter_row(&self, row: usize) -> Option<impl Iterator<Item = &T>> { 222 + self.data.get(row).map(|row| row.iter()) 223 + } 224 + 225 + /// Iterate over a column of the grid. 226 + /// 227 + /// # Examples 228 + /// 229 + /// ``` 230 + /// use utils::prelude::*; 231 + /// 232 + /// 233 + /// let data = vec![ 234 + /// vec![1, 2, 3], 235 + /// vec![4, 5, 6], 236 + /// vec![7, 8, 9], 237 + /// ]; 238 + /// 239 + /// let grid = Grid::new(data); 240 + /// 241 + /// assert_eq!(grid.iter_col(0).unwrap().collect::<Vec<_>>(), vec![&1, &4, &7]); 242 + /// assert_eq!(grid.iter_col(1).unwrap().sum::<usize>(), 2+5+8); 243 + /// assert!(grid.iter_col(8).is_none()); 244 + /// ``` 245 + /// 246 + pub fn iter_col(&self, col: usize) -> Option<impl Iterator<Item = &T>> { 247 + if col > self.width() { 248 + return None; 249 + } 250 + Some(self.data.iter().filter_map(move |row| row.get(col))) 251 + } 252 + 253 + /// Get a row of the grid. 254 + /// 255 + /// This is the same as `self.iter_row(row).map(|iter| iter.collect())`. 256 + pub fn get_row(&self, y: usize) -> Option<Vec<&T>> { 257 + self.iter_row(y).map(|iter| iter.collect()) 258 + } 259 + 260 + /// Get a column of the grid. 261 + /// 262 + /// This is the same as `self.iter_col(col).map(|iter| iter.collect())`. 263 + pub fn get_col(&self, x: usize) -> Option<Vec<&T>> { 264 + self.iter_col(x).map(|iter| iter.collect()) 265 + } 266 + 267 + /// Iterate over all rows of the grid. 268 + /// 269 + /// # Examples 270 + /// 271 + /// ``` 272 + /// use utils::prelude::*; 273 + /// 274 + /// 275 + /// let data = vec![ 276 + /// vec![1, 2, 3], 277 + /// vec![4, 5, 6], 278 + /// vec![7, 8, 9], 279 + /// ]; 280 + /// 281 + /// let grid = Grid::new(data); 282 + /// 283 + /// assert_eq!(grid.iter_rows().enumerate().filter_map(|(y, row)| row.collect::<Vec<_>>().get(y).copied()).sum::<usize>(), 1+5+9); 284 + /// ``` 285 + /// 286 + pub fn iter_rows(&self) -> impl Iterator<Item = impl Iterator<Item = &T>> { 287 + self.data.iter().map(|row| row.iter()) 288 + } 289 + 290 + /// Iterate over all columns of the grid. 291 + /// 292 + /// # Examples 293 + /// 294 + /// ``` 295 + /// use utils::prelude::*; 296 + /// 297 + /// 298 + /// let data = vec![ 299 + /// vec![1, 2, 3], 300 + /// vec![4, 5, 6], 301 + /// vec![7, 8, 9], 302 + /// ]; 303 + /// 304 + /// let grid = Grid::new(data); 305 + /// 306 + /// assert_eq!(grid.iter_cols().enumerate().filter_map(|(x, col)| col.collect::<Vec<_>>().get(x).copied()).sum::<usize>(), 1+5+9); 307 + /// ``` 308 + /// 309 + pub fn iter_cols(&self) -> impl Iterator<Item = impl Iterator<Item = &T>> { 310 + (0..self.width()).map(move |col| self.iter_col(col).unwrap()) 311 + } 312 + 313 + /// Iterate over all elements of the grid. 314 + /// 315 + /// This also yields the position of each element for easy access. 316 + /// 317 + /// # Examples 318 + /// 319 + /// ``` 320 + /// use utils::prelude::*; 321 + /// 322 + /// let data = vec![ 323 + /// vec![1, 2, 3], 324 + /// vec![4, 5, 6], 325 + /// vec![7, 8, 9], 326 + /// ]; 327 + /// 328 + /// let grid = Grid::new(data); 329 + /// 330 + /// assert_eq!(grid.iter().map(|(_, v)| v).sum::<usize>(), 1+2+3+4+5+6+7+8+9); 331 + /// ``` 332 + /// 333 + pub fn iter(&self) -> impl Iterator<Item = (Position, &T)> { 334 + self.data.iter().enumerate().flat_map(|(y, row)| { 335 + row.iter() 336 + .enumerate() 337 + .map(move |(x, col)| (Position::new(x as isize, y as isize), col)) 338 + }) 339 + } 340 + 341 + /// Get all positions relative to the given position in the grid based off the given kernels. 342 + /// 343 + /// This will automatically filter out any positions that are out of bounds. 344 + /// 345 + /// # Examples 346 + /// 347 + /// ``` 348 + /// use utils::prelude::*; 349 + /// 350 + /// let data = vec![ 351 + /// vec![1, 2, 3], 352 + /// vec![4, 5, 6], 353 + /// vec![7, 8, 9], 354 + /// ]; 355 + /// 356 + /// let grid = Grid::new(data); 357 + /// 358 + /// let pos = Position::new(1, 1); 359 + /// let kernels = &[ 360 + /// Direction::North, 361 + /// Direction::East, 362 + /// ]; 363 + /// 364 + /// let mut relatives = grid.relatives(pos, kernels); 365 + /// 366 + /// assert_eq!(relatives.next(), Some((Direction::North, Position::new(1, 0), &2))); 367 + /// assert_eq!(relatives.next(), Some((Direction::East, Position::new(2, 1), &6))); 368 + /// ``` 369 + /// 370 + /// ``` 371 + /// use utils::prelude::*; 372 + /// 373 + /// let data = vec![ 374 + /// vec![1, 2, 3], 375 + /// vec![4, 5, 6], 376 + /// vec![7, 8, 9], 377 + /// ]; 378 + /// 379 + /// let grid = Grid::new(data); 380 + /// 381 + /// let pos = Position::new(1, 0); 382 + /// let kernels = &[ 383 + /// Direction::North, // This will be filtered out, as (1, -1) is out of bounds 384 + /// Direction::East, 385 + /// ]; 386 + /// 387 + /// let mut relatives = grid.relatives(pos, kernels); 388 + /// 389 + /// assert_eq!(relatives.next(), Some((Direction::East, Position::new(2, 0), &3))); 390 + /// ``` 391 + /// 392 + pub fn relatives<'a, M: Movement>( 393 + &'a self, 394 + pos: Position, 395 + kernels: &'a [M], 396 + ) -> impl Iterator<Item = (M, Position, &T)> + 'a { 397 + pos.relatives(kernels) 398 + .filter_map(move |(pos, dir)| self.get(pos).map(|v| (dir, pos, v))) 399 + } 400 + 401 + /// Get all positions relative to the given position in the grid based off the given kernels. 402 + /// 403 + /// Wraps around the grid if necessary. 404 + /// 405 + pub fn relatives_wrapped<'a, M: Movement>( 406 + &'a self, 407 + pos: Position, 408 + kernels: &'a [M], 409 + ) -> impl Iterator<Item = (M, Position, &T)> + 'a { 410 + pos.relatives(kernels) 411 + .map(move |(pos, dir)| (dir, pos, self.get_wrapped(pos))) 412 + } 413 + 414 + /// Get all positions relative to the given position in the grid based off the given kernels, 415 + /// applying the kernel multiple times. 416 + /// 417 + /// This will automatically filter out any positions that are out of bounds. 418 + /// 419 + pub fn relatives_expand_by<'a, M: Movement>( 420 + &'a self, 421 + pos: Position, 422 + kernels: &'a [M], 423 + expand: usize, 424 + ) -> impl Iterator<Item = ((M, usize), Position, &T)> + 'a { 425 + pos.relatives_expand_by(kernels, expand) 426 + .filter_map(move |(dir, pos)| self.get(pos).map(|v| (dir, pos, v))) 427 + } 428 + 429 + /// Get all positions relative to the given position in the grid based off the given kernels, 430 + /// applying the kernel multiple times. 431 + /// 432 + /// Wraps around the grid if necessary. 433 + /// 434 + pub fn relatives_expand_by_wrapped<'a, M: Movement>( 435 + &'a self, 436 + pos: Position, 437 + kernels: &'a [M], 438 + expand: usize, 439 + ) -> impl Iterator<Item = ((M, usize), Position, &T)> + 'a { 440 + pos.relatives_expand_by(kernels, expand) 441 + .map(move |(dir, pos)| (dir, pos, self.get_wrapped(pos))) 442 + } 443 + 444 + /// Like [Grid::relatives] but with `kernels` set to the four cardinal directions. 445 + pub fn adjacent<'a>( 446 + &'a self, 447 + pos: Position, 448 + ) -> impl Iterator<Item = (Direction, Position, &T)> + 'a { 449 + self.relatives(pos, &CARDINALS) 450 + } 451 + 452 + /// Like [Grid::relatives_wrapped] but with `kernels` set to the four cardinal directions. 453 + pub fn adjacent_wrapped<'a>( 454 + &'a self, 455 + pos: Position, 456 + ) -> impl Iterator<Item = (Direction, Position, &T)> + 'a { 457 + self.relatives_wrapped(pos, &CARDINALS) 458 + } 459 + 460 + /// Like [Grid::relatives_expand_by] but with `kernels` set to the four cardinal directions. 461 + pub fn adjacent_expand_by<'a>( 462 + &'a self, 463 + pos: Position, 464 + expand: usize, 465 + ) -> impl Iterator<Item = ((Direction, usize), Position, &T)> + 'a { 466 + self.relatives_expand_by(pos, &CARDINALS, expand) 467 + } 468 + 469 + /// Like [Grid::relatives_expand_by_wrapped] but with `kernels` set to the four cardinal directions. 470 + pub fn adjacent_expand_by_wrapped<'a>( 471 + &'a self, 472 + pos: Position, 473 + expand: usize, 474 + ) -> impl Iterator<Item = ((Direction, usize), Position, &T)> + 'a { 475 + self.relatives_expand_by_wrapped(pos, &CARDINALS, expand) 476 + } 477 + } 478 + 479 + impl<T: std::fmt::Debug> std::fmt::Debug for Grid<T> { 480 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 481 + let mut debug = f.debug_struct("Grid"); 482 + for (y, row) in self.data.iter().enumerate() { 483 + debug.field(&format!("row_{}", y), row); 484 + } 485 + debug.finish() 486 + } 487 + } 488 + 489 + /// Utilities for making tiles of a grid. 490 + pub mod tiles { 491 + use crate::{dir::Movement, pos::Position}; 492 + 493 + use super::Grid; 494 + 495 + #[macro_export] 496 + /// Create an enum that implements `From<char>`. 497 + /// 498 + /// There are three versions of this macro: 499 + /// 500 + /// ## 1. Simple 501 + /// 502 + /// Create a simple enum that implements `From<char>`, with the specific characters mapping to specific variants. 503 + /// Also will make the implementation panic if an invalid character is given. 504 + /// 505 + /// ``` 506 + /// use utils::prelude::*; 507 + /// use utils::tiles; 508 + /// 509 + /// tiles!(Tile, [ 510 + /// '.' => Floor, 511 + /// '#' => Wall, 512 + /// ]); 513 + /// 514 + /// assert_eq!(Tile::from('.'), Tile::Floor); 515 + /// assert_eq!(Tile::from('#'), Tile::Wall); 516 + /// ``` 517 + /// 518 + /// ## 2. With Extra Variants 519 + /// 520 + /// Create an enum that implements `From<char>`, with the specific characters mapping to specific variants. 521 + /// Also allows for extra variants to be added, which won't be mapped to any characters. 522 + /// 523 + /// ``` 524 + /// use utils::prelude::*; 525 + /// use utils::tiles; 526 + /// 527 + /// tiles!(Tile, [ 528 + /// '.' => Floor, 529 + /// '#' => Wall, 530 + /// ], [ 531 + /// Empty, 532 + /// ]); 533 + /// 534 + /// assert_eq!(Tile::from('.'), Tile::Floor); 535 + /// assert_eq!(Tile::from('#'), Tile::Wall); 536 + /// let empty = Tile::Empty; 537 + /// ``` 538 + /// 539 + /// The extra variants can also have fields. 540 + /// 541 + /// ``` 542 + /// use utils::prelude::*; 543 + /// use utils::tiles; 544 + /// 545 + /// tiles!(Tile, [ 546 + /// '.' => Floor, 547 + /// '#' => Wall, 548 + /// ], [ 549 + /// Door(bool), 550 + /// ]); 551 + /// 552 + /// assert_eq!(Tile::from('.'), Tile::Floor); 553 + /// assert_eq!(Tile::from('#'), Tile::Wall); 554 + /// let door = Tile::Door(true); 555 + /// ``` 556 + /// 557 + /// ## 3. With Extra Variants and Extra Logic for Invalid Characters 558 + /// 559 + /// Create an enum that implements `From<char>`, with the specific characters mapping to specific variants. 560 + /// Also allows for extra variants to be added, which won't be mapped to any characters. 561 + /// Also allows for extra logic to be added for invalid characters. 562 + /// 563 + /// ``` 564 + /// use utils::prelude::*; 565 + /// use utils::tiles; 566 + /// 567 + /// tiles!(Tile, [ 568 + /// '.' => Floor, 569 + /// '#' => Wall, 570 + /// ], [ 571 + /// Slope(Direction) 572 + /// ], |c| { 573 + /// match c { 574 + /// '>' => Tile::Slope(Direction::East), 575 + /// '<' => Tile::Slope(Direction::West), 576 + /// _ => panic!("Invalid tile {c}"), 577 + /// } 578 + /// }); 579 + /// 580 + /// assert_eq!(Tile::from('.'), Tile::Floor); 581 + /// assert_eq!(Tile::from('#'), Tile::Wall); 582 + /// assert_eq!(Tile::from('>'), Tile::Slope(Direction::East)); 583 + /// ``` 584 + /// 585 + macro_rules! tiles { 586 + ($name:ident, [$($char:pat => $v_name:ident$(,)?)*]) => { 587 + tiles!($name, [$($char => $v_name,)*], [], |c| { panic!("Invalid tile {c}") }); 588 + }; 589 + 590 + ($name:ident, [$($char:pat => $v_name:ident$(,)?)*], [$($e_name:ident$(($($i_name:ty$(,)?)*))?$(,)?)*]) => { 591 + tiles!($name, [$($char => $v_name,)*], [$($e_name$(($($i_name,)*))?,)*], |c| { panic!("Invalid tile {c}") }); 592 + }; 593 + 594 + ($name:ident, [$($char:pat => $v_name:ident$(,)?)*], [$($e_name:ident$(($($i_name:ty$(,)?)*))?$(,)?)*], $default:expr) => { 595 + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 596 + pub enum $name { 597 + $($v_name,)* 598 + $($e_name$(($($i_name,)*))?,)* 599 + } 600 + 601 + impl From<char> for $name { 602 + fn from(c: char) -> Self { 603 + match c { 604 + $($char => Self::$v_name,)* 605 + _ => ($default)(c), 606 + } 607 + } 608 + } 609 + }; 610 + } 611 + 612 + /// Simple tile that holds a number value. 613 + pub struct NumberTile { 614 + pub value: isize, 615 + } 616 + 617 + impl From<char> for NumberTile { 618 + fn from(c: char) -> Self { 619 + Self { 620 + value: c.to_digit(10).unwrap() as isize, 621 + } 622 + } 623 + } 624 + 625 + /// A tile that represents some kind of movement to another position in the grid. 626 + pub trait DirectedTile<T: Movement>: Copy + Clone { 627 + /// Get the next direction from the previous direction and position. 628 + fn next_dir(&self, previous_dir: T, pos: Position) -> Option<T>; 629 + 630 + /// Get the next position and position from the previous direction and position. 631 + fn next_pos(&self, previous_dir: T, pos: Position) -> Option<(T, Position)> { 632 + self.next_dir(previous_dir, pos) 633 + .map(|d| (d, pos.move_dir(d))) 634 + } 635 + } 636 + 637 + /// A tile that can be used in a flood fill. 638 + pub trait FillableTile: Copy + Clone { 639 + /// Check if the tile can be filled. 640 + fn get_next_tiles(&self, pos: Position, grid: &Grid<Self>) -> Vec<Position>; 641 + } 642 + } 643 + 644 + /// Utilities for traversing a grid. 645 + pub mod cursors { 646 + 647 + use std::{ 648 + collections::{HashSet, VecDeque}, 649 + hash::Hasher, 650 + }; 651 + 652 + use super::{ 653 + tiles::{DirectedTile, FillableTile}, 654 + *, 655 + }; 656 + 657 + #[derive(Clone, Copy)] 658 + /// A cursor for traversing a grid. 659 + /// 660 + /// This cursor holds a position and a direction which represents the current position in the grid. 661 + /// 662 + /// # Examples 663 + /// 664 + /// ``` 665 + /// use utils::prelude::*; 666 + /// 667 + /// let data = vec![ 668 + /// vec![1, 2, 3], 669 + /// vec![4, 5, 6], 670 + /// vec![7, 8, 9], 671 + /// ]; 672 + /// 673 + /// let grid = Grid::new(data); 674 + /// 675 + /// let mut cursor = GridCursor::zero(&grid); 676 + /// 677 + /// assert_eq!(cursor.get(), Some(&1)); 678 + /// cursor.move_forward(); 679 + /// assert_eq!(cursor.get(), Some(&2)); 680 + /// cursor.turn(true); 681 + /// cursor.move_forward(); 682 + /// assert_eq!(cursor.get(), Some(&5)); 683 + /// ``` 684 + /// 685 + pub struct GridCursor<'a, T, D: Movement> { 686 + grid: &'a Grid<T>, 687 + pos: Position, 688 + dir: D, 689 + } 690 + 691 + impl<'a, T> GridCursor<'a, T, Direction> { 692 + /// Create a new cursor at position (0, 0) facing east. 693 + pub fn zero(grid: &'a Grid<T>) -> Self { 694 + Self { 695 + grid, 696 + pos: Position::new(0, 0), 697 + dir: Direction::East, 698 + } 699 + } 700 + 701 + /// Turn the cursor 90 degrees clockwise or counter-clockwise. 702 + pub fn turn(&mut self, clockwise: bool) { 703 + self.dir = self.dir.ninety_deg(clockwise); 704 + } 705 + 706 + /// Turn the cursor 180 degrees. 707 + pub fn turn_around(&mut self) { 708 + self.dir = self.dir.opposite(); 709 + } 710 + } 711 + 712 + impl<'a, T, D: Movement> PartialEq for GridCursor<'a, T, D> { 713 + fn eq(&self, other: &Self) -> bool { 714 + self.pos == other.pos && self.dir == other.dir 715 + } 716 + } 717 + 718 + impl<'a, T, D: Movement> std::hash::Hash for GridCursor<'a, T, D> { 719 + fn hash<H: Hasher>(&self, state: &mut H) { 720 + self.pos.hash(state); 721 + self.dir.hash(state); 722 + } 723 + } 724 + 725 + impl<'a, T, D: Movement> GridCursor<'a, T, D> { 726 + /// Create a new cursor at the given position and direction. 727 + pub fn new(grid: &'a Grid<T>, pos: Position, dir: D) -> Self { 728 + Self { grid, pos, dir } 729 + } 730 + 731 + /// Move the cursor forward one step in the direction it is facing. 732 + pub fn move_forward(&mut self) { 733 + self.pos = self.pos.move_dir(self.dir); 734 + } 735 + 736 + /// Get the value at the current position of the cursor. 737 + pub fn get(&self) -> Option<&T> { 738 + self.grid.get(self.pos) 739 + } 740 + 741 + /// Move the cursor forward one step in the direction it is facing and get the value at the new position. 742 + pub fn next(&mut self) -> Option<&T> { 743 + self.move_forward(); 744 + self.get() 745 + } 746 + } 747 + 748 + impl<'a, T: std::fmt::Debug, D: Movement> std::fmt::Debug for GridCursor<'a, T, D> { 749 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 750 + f.debug_struct("GridCursor") 751 + .field("pos", &self.pos) 752 + .field("dir", &self.dir) 753 + .field("value", &self.get()) 754 + .finish() 755 + } 756 + } 757 + 758 + /// A cursor for traversing a grid with a direction. 759 + /// 760 + /// This cursor will follow the direction of the tile it is currently on. 761 + /// 762 + /// # Examples 763 + /// 764 + /// ``` 765 + /// use utils::prelude::*; 766 + /// use utils::tiles; 767 + /// 768 + /// tiles!(Tile, [ 769 + /// '>' => Right, 770 + /// '<' => Left, 771 + /// '^' => Up, 772 + /// 'v' => Down, 773 + /// ]); 774 + /// 775 + /// impl DirectedTile<Direction> for Tile { 776 + /// fn next_dir(&self, previous_dir: Direction, pos: Position) -> Option<Direction> { 777 + /// match self { 778 + /// Tile::Right => Some(Direction::East), 779 + /// Tile::Left => Some(Direction::West), 780 + /// Tile::Up => Some(Direction::North), 781 + /// Tile::Down => Some(Direction::South), 782 + /// _ => None, 783 + /// } 784 + /// } 785 + /// } 786 + /// 787 + /// let data = vec![ 788 + /// vec![Tile::Right, Tile::Right, Tile::Down], 789 + /// vec![Tile::Up, Tile::Left, Tile::Down], 790 + /// vec![Tile::Up, Tile::Left, Tile::Left], 791 + /// ]; 792 + /// 793 + /// let grid = Grid::new(data); 794 + /// 795 + /// let mut cursor = DirectedCursor::new(&grid, Position::new(0, 0), Direction::East); 796 + /// 797 + /// let path = cursor.map(|(p, _, _)| p).take(8).collect::<Vec<_>>(); 798 + /// 799 + /// assert_eq!(path, vec![ 800 + /// Position::new(1, 0), 801 + /// Position::new(2, 0), 802 + /// Position::new(2, 1), 803 + /// Position::new(2, 2), 804 + /// Position::new(1, 2), 805 + /// Position::new(0, 2), 806 + /// Position::new(0, 1), 807 + /// Position::new(0, 0), 808 + /// ]); 809 + /// ``` 810 + /// 811 + pub struct DirectedCursor<'a, T: DirectedTile<D>, D: Movement>(GridCursor<'a, T, D>); 812 + 813 + impl<'a, T: DirectedTile<D>, D: Movement> DirectedCursor<'a, T, D> { 814 + /// Create a new cursor at the given position and direction. 815 + /// Note this starting position will *not* be included in the iterator. 816 + pub fn new(grid: &'a Grid<T>, pos: Position, dir: D) -> Self { 817 + let initial_cursor = GridCursor::new(grid, pos, dir); 818 + Self(initial_cursor) 819 + } 820 + } 821 + 822 + impl<'a, T: DirectedTile<D>, D: Movement> Iterator for DirectedCursor<'a, T, D> { 823 + type Item = (Position, D, T); 824 + 825 + fn next(&mut self) -> Option<Self::Item> { 826 + let current_val = self.0.get().cloned(); 827 + current_val.and_then(|tile| { 828 + tile.next_pos(self.0.dir, self.0.pos).map(|(dir, pos)| { 829 + self.0.dir = dir; 830 + self.0.pos = pos; 831 + (self.0.pos, self.0.dir, tile) 832 + }) 833 + }) 834 + } 835 + } 836 + 837 + /// A cursor that flood fills a grid. 838 + /// 839 + /// This cursor will flood fill the grid from the given position, 840 + /// using [FillableTile::get_next_tiles] to determine which tiles to fill. 841 + /// 842 + /// Setting `wrapped` to true will make the cursor wrap around the grid if necessary. 843 + /// Note this can lead to infinite loops if you don't have something to stop the iterator. 844 + /// 845 + /// # Examples 846 + /// 847 + /// ``` 848 + /// use utils::prelude::*; 849 + /// use utils::tiles; 850 + /// 851 + /// tiles!(Tile, [ 852 + /// '.' => Floor, 853 + /// '#' => Wall, 854 + /// ]); 855 + /// 856 + /// impl FillableTile for Tile { 857 + /// fn get_next_tiles(&self, pos: Position, grid: &Grid<Self>) -> Vec<Position> { 858 + /// match self { 859 + /// Tile::Floor => grid.adjacent(pos).filter(|(_, _, t)| t == &&Tile::Floor).map(|(_, p, _)| p).collect(), 860 + /// _ => vec![], 861 + /// } 862 + /// } 863 + /// } 864 + /// 865 + /// let data = vec![ 866 + /// vec![Tile::Floor, Tile::Floor, Tile::Floor], 867 + /// vec![Tile::Floor, Tile::Wall, Tile::Floor], 868 + /// vec![Tile::Floor, Tile::Floor, Tile::Wall], 869 + /// ]; 870 + /// 871 + /// let grid = Grid::new(data); 872 + /// 873 + /// let mut cursor = FloodFillCursor::new(&grid, Position::new(0, 0), true); 874 + /// 875 + /// let path = cursor.collect::<Vec<_>>(); 876 + /// 877 + /// assert_eq!(path, vec![ 878 + /// Position::new(0, 0), 879 + /// Position::new(0, 1), 880 + /// Position::new(1, 0), 881 + /// Position::new(0, 2), 882 + /// Position::new(2, 0), 883 + /// Position::new(1, 2), 884 + /// Position::new(2, 1), 885 + /// ]); 886 + /// ``` 887 + /// 888 + pub struct FloodFillCursor<'a, T: FillableTile> { 889 + grid: &'a Grid<T>, 890 + visited: HashSet<Position>, 891 + queue: VecDeque<Position>, 892 + wrapped: bool, 893 + } 894 + 895 + impl<'a, T: FillableTile> FloodFillCursor<'a, T> { 896 + /// Create a new cursor at the given position. 897 + pub fn new(grid: &'a Grid<T>, pos: Position, wrapped: bool) -> Self { 898 + let mut visited = HashSet::new(); 899 + visited.insert(pos); 900 + let mut queue = VecDeque::new(); 901 + queue.push_back(pos); 902 + Self { 903 + grid, 904 + visited, 905 + queue, 906 + wrapped, 907 + } 908 + } 909 + } 910 + 911 + impl<'a, T: FillableTile> std::fmt::Debug for FloodFillCursor<'a, T> { 912 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 913 + f.debug_struct("FloodFillCursor") 914 + .field("visited", &self.visited) 915 + .field("queue", &self.queue) 916 + .finish() 917 + } 918 + } 919 + 920 + impl<'a, T: FillableTile> Iterator for FloodFillCursor<'a, T> { 921 + type Item = Position; 922 + 923 + fn next(&mut self) -> Option<Self::Item> { 924 + let pos = self.queue.pop_front()?; 925 + let tile = if self.wrapped { 926 + self.grid.get_wrapped(pos) 927 + } else { 928 + self.grid.get(pos)? 929 + }; 930 + for next_pos in tile.get_next_tiles(pos, self.grid) { 931 + if self.visited.insert(next_pos) { 932 + self.queue.push_back(next_pos); 933 + } 934 + } 935 + Some(pos) 936 + } 937 + } 938 + }
+17 -12
utils/src/lib.rs
··· 1 - pub fn add(left: usize, right: usize) -> usize { 2 - left + right 3 - } 1 + pub mod day_utils; 2 + pub mod dir; 3 + pub mod geom; 4 + pub mod grid; 5 + pub mod line; 6 + pub mod pos; 7 + pub mod range; 4 8 5 - #[cfg(test)] 6 - mod tests { 7 - use super::*; 8 - 9 - #[test] 10 - fn it_works() { 11 - let result = add(2, 2); 12 - assert_eq!(result, 4); 13 - } 9 + pub mod prelude { 10 + pub use crate::day_utils::*; 11 + pub use crate::dir::*; 12 + pub use crate::geom; 13 + pub use crate::grid::cursors::*; 14 + pub use crate::grid::tiles::*; 15 + pub use crate::grid::*; 16 + pub use crate::line::*; 17 + pub use crate::pos::*; 18 + pub use crate::range::*; 14 19 }
+171
utils/src/line.rs
··· 1 + use std::ops::Neg; 2 + 3 + use crate::{dir::Direction, pos::Position}; 4 + 5 + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 6 + /// A line between two points. 7 + /// 8 + /// This line is represented by two [Position]s. 9 + /// 10 + /// # Examples 11 + /// 12 + /// ``` 13 + /// use utils::prelude::*; 14 + /// 15 + /// let line = Line::new(Position::new(0, 0), Position::new(1, 1)); 16 + /// assert_eq!(line.get_slope(), 1.0); 17 + /// assert_eq!(line.get_intercept(), 0.0); 18 + /// ``` 19 + /// 20 + pub struct Line(Position, Position); 21 + 22 + impl Line { 23 + /// Create a new line between two points. 24 + /// 25 + /// # Examples 26 + /// 27 + /// ``` 28 + /// use utils::prelude::*; 29 + /// 30 + /// let line = Line::new(Position::new(0, 0), Position::new(1, 1)); 31 + /// assert_eq!(line.end().x, 1); 32 + /// ``` 33 + /// 34 + pub fn new(start: Position, end: Position) -> Self { 35 + Self(start, end) 36 + } 37 + 38 + /// Create a new line from a starting point and a direction. 39 + /// 40 + /// # Examples 41 + /// 42 + /// ``` 43 + /// use utils::prelude::*; 44 + /// 45 + /// let line = Line::from_dir(Position::new(0, 0), Direction::East); 46 + /// assert_eq!(line.end().x, 1); 47 + /// ``` 48 + /// 49 + pub fn from_dir(start: Position, dir: Direction) -> Self { 50 + Self(start, start.move_dir(dir)) 51 + } 52 + 53 + /// Get the linear slope of the line. 54 + /// 55 + /// # Examples 56 + /// 57 + /// ``` 58 + /// use utils::prelude::*; 59 + /// 60 + /// let line = Line::new(Position::new(0, 0), Position::new(1, 1)); 61 + /// assert_eq!(line.get_slope(), 1.0); 62 + /// 63 + /// let line = Line::new(Position::new(0, 0), Position::new(2, 1)); 64 + /// assert_eq!(line.get_slope(), 0.5); 65 + /// ``` 66 + /// 67 + pub fn get_slope(&self) -> f64 { 68 + let dx = self.1.x - self.0.x; 69 + let dy = self.1.y - self.0.y; 70 + dy as f64 / dx as f64 71 + } 72 + 73 + /// Get the y-intercept of the line. 74 + /// 75 + /// # Examples 76 + /// 77 + /// ``` 78 + /// use utils::prelude::*; 79 + /// 80 + /// let line = Line::new(Position::new(0, 0), Position::new(1, 1)); 81 + /// assert_eq!(line.get_intercept(), 0.0); 82 + /// 83 + /// let line = Line::new(Position::new(0, 5), Position::new(2, 1)); 84 + /// assert_eq!(line.get_intercept(), 5.0); 85 + /// ``` 86 + /// 87 + pub fn get_intercept(&self) -> f64 { 88 + let slope = self.get_slope(); 89 + self.0.y as f64 - slope * self.0.x as f64 90 + } 91 + 92 + /// Check that the given point is *after* the start position on the line. 93 + /// 94 + /// Note this doesn't check if the point is on the line, just that it is 95 + /// on the same side of the line as the end point. 96 + /// 97 + /// # Examples 98 + /// 99 + /// ``` 100 + /// use utils::prelude::*; 101 + /// 102 + /// let line = Line::new(Position::new(0, 0), Position::new(2, 2)); 103 + /// assert_eq!(line.check_after(&Position::new(1, 1)), true); 104 + /// 105 + /// let line = Line::new(Position::new(0, 0), Position::new(2, 2)); 106 + /// assert_eq!(line.check_after(&Position::new(-1, -1)), false); 107 + /// ``` 108 + /// 109 + pub fn check_after(&self, pos: &Position) -> bool { 110 + let relative = pos.sub(&self.0); 111 + let d = self.1.sub(&self.0); 112 + relative.normalize() == d.normalize() 113 + } 114 + 115 + /// Get the intersection point between this line and another. 116 + /// 117 + /// Pass `check_after` as `true` to ensure that the intersection point is 118 + /// after the start of both lines. 119 + /// 120 + /// # Examples 121 + /// 122 + /// ``` 123 + /// use utils::prelude::*; 124 + /// 125 + /// let line1 = Line::new(Position::new(2, -2), Position::new(-2, 2)); 126 + /// let line2 = Line::new(Position::new(2, 2), Position::new(-2, -2)); 127 + /// assert_eq!(line1.get_intersection(&line2, true), Some(Position::new(0, 0))); 128 + /// 129 + /// let line1 = Line::new(Position::new(5, 0), Position::new(6, 8)); 130 + /// let line2 = Line::new(Position::new(0, 1), Position::new(-4, -3)); 131 + /// assert_eq!(line1.get_intersection(&line2, true), None); 132 + /// ``` 133 + /// 134 + pub fn get_intersection(&self, other: &Self, check_after: bool) -> Option<Position> { 135 + let slope = self.get_slope(); 136 + let intercept = self.get_intercept(); 137 + let other_slope = other.get_slope(); 138 + let other_intercept = other.get_intercept(); 139 + 140 + if slope == other_slope { 141 + return None; 142 + } 143 + 144 + let x = (other_intercept - intercept) / (slope - other_slope); 145 + let y = slope * x + intercept; 146 + 147 + let point = Position::new(x as isize, y as isize); 148 + 149 + if !check_after || self.check_after(&point) && other.check_after(&point) { 150 + Some(point) 151 + } else { 152 + None 153 + } 154 + } 155 + 156 + pub fn start(&self) -> Position { 157 + self.0 158 + } 159 + 160 + pub fn end(&self) -> Position { 161 + self.1 162 + } 163 + } 164 + 165 + impl Neg for Line { 166 + type Output = Self; 167 + 168 + fn neg(self) -> Self::Output { 169 + Self(self.1, self.0) 170 + } 171 + }
+775
utils/src/pos.rs
··· 1 + /// Position utilities 2 + use std::{ 3 + fmt::{Debug, Display}, 4 + ops::{Add, Mul, Neg, Sub}, 5 + str::FromStr, 6 + }; 7 + 8 + use crate::dir::{Direction, Movement, CARDINALS}; 9 + 10 + type CompType = isize; 11 + type PositiveType = (usize, usize); 12 + 13 + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 14 + /// A position in 2D space on an integer grid 15 + /// This is meant to represent indices of a 2D array, so north is negative y 16 + /// 17 + /// This is also used to represent a vector in 2D space at times 18 + pub struct Position { 19 + pub x: CompType, 20 + pub y: CompType, 21 + } 22 + 23 + impl Position { 24 + /// Create a new position 25 + pub fn new(x: CompType, y: CompType) -> Self { 26 + Self { x, y } 27 + } 28 + 29 + /// Create a new position at 0, 0 30 + pub fn zero() -> Self { 31 + Self { x: 0, y: 0 } 32 + } 33 + 34 + /// Create the unit vector position 35 + pub fn one() -> Self { 36 + Self { x: 1, y: 1 } 37 + } 38 + 39 + /// Get the position flipped over the line y = x 40 + /// 41 + /// # Examples 42 + /// 43 + /// ``` 44 + /// use utils::prelude::*; 45 + /// 46 + /// let flipped = Position::new(1, 2).flip(); 47 + /// assert_eq!(flipped, Position::new(2, 1)); 48 + /// ``` 49 + /// 50 + pub fn flip(&self) -> Self { 51 + Self { 52 + x: self.y, 53 + y: self.x, 54 + } 55 + } 56 + 57 + /// Normalize a position to a unit vector 58 + /// 59 + /// # Examples 60 + /// 61 + /// ``` 62 + /// use utils::prelude::*; 63 + /// 64 + /// let normalized = Position::new(1, 1).normalize(); 65 + /// assert_eq!(normalized, Position::new(1, 1)); 66 + /// 67 + /// let normalized = Position::new(50, -45).normalize(); 68 + /// assert_eq!(normalized, Position::new(1, -1)); 69 + /// 70 + /// let normalized = Position::new(-30, 0).normalize(); 71 + /// assert_eq!(normalized, Position::new(-1, 0)); 72 + /// ``` 73 + /// 74 + pub fn normalize(&self) -> Self { 75 + Self { 76 + x: self.x.signum(), 77 + y: self.y.signum(), 78 + } 79 + } 80 + 81 + /// Get the magnitude of a position 82 + /// 83 + /// # Examples 84 + /// 85 + /// ``` 86 + /// use utils::prelude::*; 87 + /// 88 + /// let mag = Position::new(0, 1).magnitude(); 89 + /// assert_eq!(mag, 1.0); 90 + /// 91 + /// let mag = Position::new(3, 4).magnitude(); 92 + /// assert_eq!(mag, 5.0); 93 + /// ``` 94 + /// 95 + pub fn magnitude(&self) -> f64 { 96 + (((self.x * self.x) + (self.y * self.y)) as f64).sqrt() 97 + } 98 + 99 + /// Get the absolute value of a position 100 + /// 101 + /// # Examples 102 + /// 103 + /// ``` 104 + /// use utils::prelude::*; 105 + /// 106 + /// let abs = Position::new(-1, -1).abs(); 107 + /// assert_eq!(abs, Position::new(1, 1)); 108 + /// ``` 109 + /// 110 + pub fn abs(&self) -> Self { 111 + Self { 112 + x: self.x.abs(), 113 + y: self.y.abs(), 114 + } 115 + } 116 + 117 + /// Sum the components of a position 118 + /// 119 + /// # Examples 120 + /// 121 + /// ``` 122 + /// use utils::prelude::*; 123 + /// 124 + /// let sum = Position::new(1, 1).sum(); 125 + /// assert_eq!(sum, 2); 126 + /// ``` 127 + /// 128 + pub fn sum(&self) -> CompType { 129 + self.x + self.y 130 + } 131 + 132 + /// Get the difference between the components of a position 133 + /// 134 + /// # Examples 135 + /// 136 + /// ``` 137 + /// use utils::prelude::*; 138 + /// 139 + /// let diff = Position::new(1, 1).diff(); 140 + /// assert_eq!(diff, 0); 141 + /// ``` 142 + /// 143 + pub fn diff(&self) -> CompType { 144 + self.x - self.y 145 + } 146 + 147 + /// Get the direction of one position relative to another 148 + /// 149 + /// This is the direction that the second position is from the first 150 + /// 151 + /// Meaning 152 + /// 153 + /// ```txt 154 + /// ... 155 + /// A.B 156 + /// ... 157 + /// 158 + /// A.get_dir(B) == Direction::East 159 + /// and 160 + /// B.get_dir(A) == Direction::West 161 + /// ``` 162 + /// 163 + /// # Panics 164 + /// 165 + /// If the positions are the same or diagonal from each other 166 + /// 167 + /// # Examples 168 + /// 169 + /// ``` 170 + /// use utils::prelude::*; 171 + /// 172 + /// let dir = Position::new(1, 1).get_dir(&Position::new(5, 1)); 173 + /// assert_eq!(dir, Direction::East); 174 + /// 175 + /// let dir = Position::new(5, 1).get_dir(&Position::new(1, 1)); 176 + /// assert_eq!(dir, Direction::West); 177 + /// 178 + /// let dir = Position::new(1, 1).get_dir(&Position::new(1, 5)); 179 + /// assert_eq!(dir, Direction::South); 180 + /// ``` 181 + /// 182 + pub fn get_dir(&self, other: &Self) -> Direction { 183 + other.sub(self).normalize().into() 184 + } 185 + 186 + /// Add two positions together 187 + /// 188 + /// # Examples 189 + /// 190 + /// ``` 191 + /// use utils::prelude::*; 192 + /// 193 + /// let sum = Position::new(1, 1).add(&Position::new(5, 4)); 194 + /// assert_eq!(sum, Position::new(6, 5)); 195 + /// ``` 196 + /// 197 + pub fn add(&self, other: &Self) -> Self { 198 + Self { 199 + x: self.x + other.x, 200 + y: self.y + other.y, 201 + } 202 + } 203 + 204 + /// Get the difference between two positions 205 + /// 206 + /// # Examples 207 + /// 208 + /// ``` 209 + /// use utils::prelude::*; 210 + /// 211 + /// let diff = Position::new(1, 1).sub(&Position::new(5, 5)); 212 + /// assert_eq!(diff, Position::new(-4, -4)); 213 + /// ``` 214 + /// 215 + pub fn sub(&self, other: &Self) -> Self { 216 + Self { 217 + x: self.x - other.x, 218 + y: self.y - other.y, 219 + } 220 + } 221 + 222 + /// Multiply two positions together 223 + /// 224 + /// # Examples 225 + /// 226 + /// ``` 227 + /// use utils::prelude::*; 228 + /// 229 + /// let multiplied = Position::new(1, 1).multiply(&Position::new(5, 4)); 230 + /// assert_eq!(multiplied, Position::new(5, 4)); 231 + /// ``` 232 + /// 233 + pub fn multiply(&self, other: &Self) -> Self { 234 + Self { 235 + x: self.x * other.x, 236 + y: self.y * other.y, 237 + } 238 + } 239 + 240 + /// Get the dot product of two positions 241 + /// 242 + /// x1 * x2 + y1 * y2 243 + /// 244 + /// # Examples 245 + /// 246 + /// ``` 247 + /// use utils::prelude::*; 248 + /// 249 + /// let dot = Position::new(1, 1).dot(&Position::new(5, 4)); 250 + /// assert_eq!(dot, 9); 251 + /// ``` 252 + /// 253 + pub fn dot(&self, other: &Self) -> CompType { 254 + self.multiply(other).sum() 255 + } 256 + 257 + /// Get the angle between two positions 258 + /// 259 + /// # Examples 260 + /// 261 + /// ``` 262 + /// use utils::prelude::*; 263 + /// 264 + /// let angle = Position::new(0, 1).angle(&Position::new(1, 0)); 265 + /// 266 + /// assert_eq!(angle, std::f64::consts::FRAC_PI_2); 267 + /// ``` 268 + /// 269 + pub fn angle(&self, other: &Self) -> f64 { 270 + let dot = self.dot(other) as f64; 271 + let mag = self.magnitude() * other.magnitude(); 272 + (dot / mag).acos() 273 + } 274 + 275 + /// Get the cross product of two positions 276 + /// 277 + /// x1 * y2 - y1 * x2 278 + /// 279 + /// # Examples 280 + /// 281 + /// ``` 282 + /// use utils::prelude::*; 283 + /// 284 + /// let cross = Position::new(2, 3).cross(&Position::new(5, 4)); 285 + /// assert_eq!(cross, -7); 286 + /// ``` 287 + /// 288 + pub fn cross(&self, other: &Self) -> CompType { 289 + self.multiply(&other.flip()).diff() 290 + } 291 + 292 + /// Multiply a position by a scalar 293 + /// 294 + /// # Examples 295 + /// 296 + /// ``` 297 + /// use utils::prelude::*; 298 + /// 299 + /// let multiplied = Position::new(1, 1).multiply_comp(5); 300 + /// assert_eq!(multiplied, Position::new(5, 5)); 301 + /// ``` 302 + /// 303 + pub fn multiply_comp(&self, other: CompType) -> Self { 304 + Self { 305 + x: self.x * other, 306 + y: self.y * other, 307 + } 308 + } 309 + 310 + /// Get the manhattan distance between two positions 311 + /// 312 + /// # Examples 313 + /// 314 + /// ``` 315 + /// use utils::prelude::*; 316 + /// 317 + /// let distance = Position::new(1, 1).manhattan(&Position::new(5, 5)); 318 + /// assert_eq!(distance, 8); 319 + /// ``` 320 + /// 321 + pub fn manhattan(&self, other: &Self) -> CompType { 322 + self.sub(other).abs().sum() 323 + } 324 + 325 + /// Get the chebyshev distance between two positions 326 + /// 327 + /// # Examples 328 + /// 329 + /// ``` 330 + /// use utils::prelude::*; 331 + /// 332 + /// let distance = Position::new(1, 1).chebyshev(&Position::new(5, 5)); 333 + /// assert_eq!(distance, 4); 334 + /// ``` 335 + /// 336 + pub fn chebyshev(&self, other: &Self) -> CompType { 337 + let diff = self.sub(other).abs(); 338 + diff.x.max(diff.y) 339 + } 340 + 341 + /// Check if a component is within a range of 0..bound 342 + /// Note bound is exclusive 343 + fn check_comp(comp: CompType, bound: usize) -> bool { 344 + (0..(bound as isize)).contains(&comp) 345 + } 346 + 347 + /// Check if a position is within a range of (0..bound.0, 0..bound.1) 348 + /// Note bound is exclusive 349 + /// 350 + /// # Examples 351 + /// 352 + /// ``` 353 + /// use utils::prelude::*; 354 + /// 355 + /// let checked = Position::new(0, 0).check((10, 10)); 356 + /// assert!(checked); 357 + /// 358 + /// let checked = Position::new(50, 50).check((5, 5)); 359 + /// assert_eq!(checked, false); 360 + /// ``` 361 + /// 362 + pub fn check(&self, bounds: PositiveType) -> bool { 363 + Self::check_comp(self.x, bounds.0) && Self::check_comp(self.y, bounds.1) 364 + } 365 + 366 + /// Normalize a value to be within a range of 0..bound 367 + /// Note bound is exclusive 368 + /// 369 + /// # Examples 370 + /// 371 + /// ``` 372 + /// use utils::prelude::*; 373 + /// 374 + /// let normalized = Position::bind_comp(-1, 10); 375 + /// assert_eq!(normalized, 9); 376 + /// 377 + /// let normalized = Position::bind_comp(-10, 5); 378 + /// assert_eq!(normalized, 0); 379 + /// 380 + /// let normalized = Position::bind_comp(10, 5); 381 + /// assert_eq!(normalized, 0); 382 + /// 383 + /// let normalized = Position::bind_comp(3, 6); 384 + /// assert_eq!(normalized, 3); 385 + /// ``` 386 + /// 387 + pub fn bind_comp(comp: CompType, bound: usize) -> usize { 388 + let bound = bound as isize; 389 + if comp >= bound || comp.is_negative() { 390 + let ans = comp % bound; 391 + if ans.is_negative() { 392 + (ans + bound) as usize 393 + } else { 394 + ans as usize 395 + } 396 + } else { 397 + comp as usize 398 + } 399 + } 400 + 401 + /// Bind a position to be within ranges of (0..bound.0, 0..bound.1) 402 + /// Note bound is exclusive 403 + /// 404 + /// # Examples 405 + /// 406 + /// ``` 407 + /// use utils::prelude::*; 408 + /// 409 + /// let bound = Position::new(-1, -1).bind((11, 11)); 410 + /// assert_eq!(bound, (10, 10)); 411 + /// 412 + /// let bound = Position::new(-10, -10).bind((6, 6)); 413 + /// assert_eq!(bound, (2, 2)); 414 + /// 415 + /// let bound = Position::new(10, 10).bind((6, 6)); 416 + /// assert_eq!(bound, (4, 4)); 417 + /// ``` 418 + /// 419 + pub fn bind(&self, bounds: PositiveType) -> PositiveType { 420 + ( 421 + Self::bind_comp(self.x, bounds.0), 422 + Self::bind_comp(self.y, bounds.1), 423 + ) 424 + } 425 + 426 + /// Move a position by direction 427 + /// 428 + /// # Examples 429 + /// 430 + /// ``` 431 + /// use utils::prelude::*; 432 + /// 433 + /// let moved = Position::new(0, 0).move_dir(Direction::North); 434 + /// assert_eq!(moved, Position::new(0, -1)); 435 + /// 436 + /// let moved = Position::new(0, 0).move_dir(Direction::East); 437 + /// assert_eq!(moved, Position::new(1, 0)); 438 + /// ``` 439 + /// 440 + pub fn move_dir(&self, dir: impl Movement) -> Self { 441 + self.add(&dir.get_kernel()) 442 + } 443 + 444 + /// Move a position by direction a certain number of times 445 + /// 446 + /// # Examples 447 + /// 448 + /// ``` 449 + /// use utils::prelude::*; 450 + /// 451 + /// let moved = Position::new(0, 0).move_times(Direction::North, 5); 452 + /// assert_eq!(moved, Position::new(0, -5)); 453 + /// ``` 454 + /// 455 + pub fn move_times(&self, dir: impl Movement, times: usize) -> Self { 456 + self.add(&dir.get_kernel().multiply_comp(times as isize)) 457 + } 458 + 459 + /// Move a position by direction, 460 + /// checking if it is within a range of (0..bound.0, 0..bound.1) 461 + /// 462 + /// # Returns 463 + /// 464 + /// * `Some(Position)` if the new position is within the bounds 465 + /// * `None` if the new position is outside the bounds 466 + /// 467 + /// # Examples 468 + /// 469 + /// ``` 470 + /// use utils::prelude::*; 471 + /// 472 + /// let moved = Position::new(0, 0).move_dir_checked(Direction::East, (10, 10)); 473 + /// assert_eq!(moved.unwrap(), Position::new(1, 0)); 474 + /// 475 + /// let moved = Position::new(40, 40).move_dir_checked(Direction::East, (40, 40)); 476 + /// assert!(moved.is_none()); 477 + /// ``` 478 + /// 479 + pub fn move_dir_checked(&self, dir: impl Movement, bounds: PositiveType) -> Option<Self> { 480 + let new = self.move_dir(dir); 481 + if new.check(bounds) { 482 + Some(new) 483 + } else { 484 + None 485 + } 486 + } 487 + 488 + /// Move a position by direction a certain number of times, 489 + /// checking if it is within a range of (0..bound.0, 0..bound.1) 490 + /// 491 + /// # Returns 492 + /// 493 + /// * `Some(Position)` if the new position is within the bounds 494 + /// * `None` if the new position is outside the bounds 495 + /// 496 + pub fn move_times_checked( 497 + &self, 498 + dir: impl Movement, 499 + times: usize, 500 + bounds: PositiveType, 501 + ) -> Option<Self> { 502 + let new = self.move_times(dir, times); 503 + if new.check(bounds) { 504 + Some(new) 505 + } else { 506 + None 507 + } 508 + } 509 + 510 + /// Get all positions relative to this position by a list of directions 511 + /// 512 + /// # Examples 513 + /// 514 + /// ``` 515 + /// use utils::prelude::*; 516 + /// 517 + /// let relatives = Position::new(0, 0).relatives(&[Direction::North, Direction::East]).collect::<Vec<_>>(); 518 + /// assert_eq!(relatives, vec![(Position::new(0, -1), Direction::North), (Position::new(1, 0), Direction::East)]); 519 + /// ``` 520 + /// 521 + pub fn relatives<'a, T: Movement>( 522 + self, 523 + kernels: &'a [T], 524 + ) -> impl Iterator<Item = (Self, T)> + 'a { 525 + kernels.into_iter().map(move |k| (self.move_dir(*k), *k)) 526 + } 527 + 528 + /// Get all positions relative to this position by a list of directions, 529 + /// checking if they are within a range of (0..bound.0, 0..bound.1) 530 + /// 531 + /// # Examples 532 + /// 533 + /// ``` 534 + /// use utils::prelude::*; 535 + /// 536 + /// let relatives = Position::new(0, 0).relatives_checked(&[Direction::North, Direction::East], (10, 10)).collect::<Vec<_>>(); 537 + /// assert_eq!(relatives, vec![(Position::new(1, 0), Direction::East)]); 538 + /// ``` 539 + /// 540 + pub fn relatives_checked<'a, T: Movement>( 541 + self, 542 + kernels: &'a [T], 543 + bounds: PositiveType, 544 + ) -> impl Iterator<Item = (Self, T)> + 'a { 545 + kernels 546 + .iter() 547 + .filter_map(move |k| self.move_dir_checked(*k, bounds).map(|p| (p, *k))) 548 + } 549 + 550 + /// Get all positions relative to this position by a list of directions, 551 + /// repeating each direction a certain number of times 552 + /// 553 + /// # Examples 554 + /// 555 + /// ``` 556 + /// use utils::prelude::*; 557 + /// 558 + /// let relatives = Position::new(0, 0).relatives_expand_by(&[Direction::North, Direction::East], 2).collect::<Vec<_>>(); 559 + /// let expected = vec![ 560 + /// ((Direction::North, 1), Position::new(0, -1)), 561 + /// ((Direction::North, 2), Position::new(0, -2)), 562 + /// ((Direction::East, 1), Position::new(1, 0)), 563 + /// ((Direction::East, 2), Position::new(2, 0)), 564 + /// ]; 565 + /// 566 + /// assert_eq!(relatives, expected); 567 + /// ``` 568 + /// 569 + pub fn relatives_expand_by<'a, T: Movement>( 570 + self, 571 + kernels: &'a [T], 572 + times: usize, 573 + ) -> impl Iterator<Item = ((T, usize), Self)> + 'a { 574 + kernels 575 + .into_iter() 576 + .flat_map(move |k| (1..=times).map(move |t| ((*k, t), self.move_times(*k, t)))) 577 + } 578 + 579 + /// Get all positions relative to this position by a list of directions, 580 + /// repeating each direction a certain number of times, 581 + /// checking if they are within a range of (0..bound.0, 0..bound.1) 582 + /// 583 + /// # Examples 584 + /// 585 + /// ``` 586 + /// use utils::prelude::*; 587 + /// 588 + /// let relatives = Position::new(0, 0).relatives_expand_by_checked(&[Direction::North, Direction::East], 2, (10, 10)).collect::<Vec<_>>(); 589 + /// let expected = vec![ 590 + /// ((Direction::East, 1), Position::new(1, 0)), 591 + /// ((Direction::East, 2), Position::new(2, 0)), 592 + /// ]; 593 + /// 594 + /// assert_eq!(relatives, expected); 595 + /// ``` 596 + /// 597 + pub fn relatives_expand_by_checked<'a, T: Movement>( 598 + self, 599 + kernels: &'a [T], 600 + times: usize, 601 + bounds: PositiveType, 602 + ) -> impl Iterator<Item = ((T, usize), Self)> + 'a { 603 + kernels.into_iter().flat_map(move |k| { 604 + (1..=times) 605 + .filter_map(move |t| self.move_times_checked(*k, t, bounds).map(|p| ((*k, t), p))) 606 + }) 607 + } 608 + 609 + /// Get all positions adjacent to this position 610 + /// 611 + /// # Examples 612 + /// 613 + /// ``` 614 + /// use utils::prelude::*; 615 + /// 616 + /// let adjacents = Position::new(0, 0).adjacents().collect::<Vec<_>>(); 617 + /// let expected = vec![ 618 + /// (Position::new(0, -1), Direction::North), 619 + /// (Position::new(0, 1), Direction::South), 620 + /// (Position::new(1, 0), Direction::East), 621 + /// (Position::new(-1, 0), Direction::West), 622 + /// ]; 623 + /// 624 + /// assert_eq!(adjacents, expected); 625 + /// ``` 626 + /// 627 + pub fn adjacents(self) -> impl Iterator<Item = (Self, Direction)> { 628 + self.relatives(&CARDINALS) 629 + } 630 + 631 + /// Get all positions adjacent to this position 632 + /// 633 + /// # Examples 634 + /// 635 + /// ``` 636 + /// use utils::prelude::*; 637 + /// 638 + /// let adjacents = Position::new(0, 0).adjacents_checked((2, 2)).collect::<Vec<_>>(); 639 + /// let expected = vec![ 640 + /// (Position::new(0, 1), Direction::South), 641 + /// (Position::new(1, 0), Direction::East), 642 + /// ]; 643 + /// 644 + /// assert_eq!(adjacents, expected); 645 + /// ``` 646 + /// 647 + pub fn adjacents_checked( 648 + self, 649 + bounds: PositiveType, 650 + ) -> impl Iterator<Item = (Self, Direction)> { 651 + self.relatives_checked(&CARDINALS, bounds) 652 + } 653 + } 654 + 655 + impl Add for Position { 656 + type Output = Self; 657 + 658 + fn add(self, other: Self) -> Self { 659 + Self::add(&self, &other) 660 + } 661 + } 662 + 663 + impl Add<&Position> for Position { 664 + type Output = Self; 665 + 666 + fn add(self, other: &Self) -> Self { 667 + Self::add(&self, other) 668 + } 669 + } 670 + 671 + impl Sub for Position { 672 + type Output = Self; 673 + 674 + fn sub(self, other: Self) -> Self { 675 + Self::sub(&self, &other) 676 + } 677 + } 678 + 679 + impl Sub<&Position> for Position { 680 + type Output = Self; 681 + 682 + fn sub(self, other: &Self) -> Self { 683 + Self::sub(&self, other) 684 + } 685 + } 686 + 687 + impl Mul for Position { 688 + type Output = Self; 689 + 690 + fn mul(self, other: Self) -> Self { 691 + Self::multiply(&self, &other) 692 + } 693 + } 694 + 695 + impl Mul<&Position> for Position { 696 + type Output = Self; 697 + 698 + fn mul(self, other: &Self) -> Self { 699 + Self::multiply(&self, other) 700 + } 701 + } 702 + 703 + impl Mul<CompType> for Position { 704 + type Output = Self; 705 + 706 + fn mul(self, other: CompType) -> Self { 707 + Self::multiply_comp(&self, other) 708 + } 709 + } 710 + 711 + impl Mul<usize> for Position { 712 + type Output = Self; 713 + 714 + fn mul(self, other: usize) -> Self { 715 + Self::multiply_comp(&self, other as isize) 716 + } 717 + } 718 + 719 + impl Neg for Position { 720 + type Output = Self; 721 + 722 + fn neg(self) -> Self { 723 + self.multiply_comp(-1) 724 + } 725 + } 726 + 727 + impl Display for Position { 728 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 729 + write!(f, "({},{})", self.x, self.y) 730 + } 731 + } 732 + 733 + impl FromStr for Position { 734 + type Err = String; 735 + 736 + fn from_str(s: &str) -> Result<Self, Self::Err> { 737 + let mut split = s.split(','); 738 + let x = split.next().ok_or("No x")?.parse().expect("No x"); 739 + let y = split.next().ok_or("No y")?.parse().expect("No y"); 740 + Ok(Self { x, y }) 741 + } 742 + } 743 + 744 + impl From<(CompType, CompType)> for Position { 745 + fn from((x, y): (CompType, CompType)) -> Self { 746 + Self { x, y } 747 + } 748 + } 749 + 750 + impl Into<(CompType, CompType)> for Position { 751 + fn into(self) -> (CompType, CompType) { 752 + (self.x, self.y) 753 + } 754 + } 755 + 756 + impl From<(usize, usize)> for Position { 757 + fn from((x, y): (usize, usize)) -> Self { 758 + Self { 759 + x: x as isize, 760 + y: y as isize, 761 + } 762 + } 763 + } 764 + 765 + impl Into<(usize, usize)> for Position { 766 + fn into(self) -> (usize, usize) { 767 + (self.x as usize, self.y as usize) 768 + } 769 + } 770 + 771 + impl From<Direction> for Position { 772 + fn from(dir: Direction) -> Self { 773 + dir.get_kernel() 774 + } 775 + }
+172
utils/src/range.rs
··· 1 + use std::{fmt::Debug, ops::Range}; 2 + 3 + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 4 + /// Represents a range of values. 5 + /// 6 + /// End is exclusive. 7 + pub struct BetterRange<T: Copy + Clone + Debug> { 8 + pub start: T, 9 + pub end: T, 10 + } 11 + 12 + impl<T: Copy + Clone + Debug> BetterRange<T> { 13 + pub fn new(start: T, end: T) -> Self { 14 + Self { start, end } 15 + } 16 + } 17 + 18 + pub enum RangeSplitBehavior { 19 + IncludeLower, 20 + IncludeUpper, 21 + Exclude, 22 + } 23 + 24 + impl<T: Copy + Clone + Debug + Ord> BetterRange<T> { 25 + /// Checks if the range contains the given value. 26 + /// 27 + /// # Examples 28 + /// 29 + /// ``` 30 + /// use utils::prelude::*; 31 + /// 32 + /// let range = BetterRange::new(0, 10); 33 + /// assert!(range.contains(&5)); 34 + /// assert!(!range.contains(&10)); 35 + /// ``` 36 + /// 37 + pub fn contains(&self, value: &T) -> bool { 38 + self.start <= *value && *value < self.end 39 + } 40 + 41 + /// Checks if the range contains the given range. 42 + /// 43 + /// # Examples 44 + /// 45 + /// ``` 46 + /// use utils::prelude::*; 47 + /// 48 + /// let range = BetterRange::new(0, 10); 49 + /// assert!(range.contains_range(&BetterRange::new(5, 7))); 50 + /// assert!(!range.contains_range(&BetterRange::new(5, 15))); 51 + /// ``` 52 + /// 53 + pub fn contains_range(&self, other: &Self) -> bool { 54 + self.start <= other.start && other.end < self.end 55 + } 56 + 57 + /// Split the range at the given value. 58 + /// 59 + /// The behaviour determines if the value is included in the lower range, upper range, or neither. 60 + /// 61 + /// # Examples 62 + /// 63 + /// ``` 64 + /// use utils::prelude::*; 65 + /// 66 + /// let range = BetterRange::new(0, 10); 67 + /// 68 + /// let (lower, upper) = range.split(&5, RangeSplitBehavior::IncludeLower); 69 + /// assert_eq!(lower, Some(BetterRange::new(0, 6))); 70 + /// assert_eq!(upper, Some(BetterRange::new(6, 10))); 71 + /// ``` 72 + /// 73 + /// ``` 74 + /// use utils::prelude::*; 75 + /// 76 + /// let range = BetterRange::new(0, 10); 77 + /// 78 + /// let (lower, upper) = range.split(&5, RangeSplitBehavior::IncludeUpper); 79 + /// assert_eq!(lower, Some(BetterRange::new(0, 5))); 80 + /// assert_eq!(upper, Some(BetterRange::new(5, 10))); 81 + /// ``` 82 + /// 83 + /// ``` 84 + /// use utils::prelude::*; 85 + /// 86 + /// let range = BetterRange::new(0, 10); 87 + /// 88 + /// let (lower, upper) = range.split(&5, RangeSplitBehavior::Exclude); 89 + /// assert_eq!(lower, Some(BetterRange::new(0, 5))); 90 + /// assert_eq!(upper, Some(BetterRange::new(6, 10))); 91 + /// ``` 92 + /// 93 + pub fn split(&self, value: &T, behaviour: RangeSplitBehavior) -> (Option<Self>, Option<Self>) 94 + where 95 + T: std::ops::Add<usize, Output = T> + std::ops::Sub<usize, Output = T>, 96 + { 97 + if self.contains(value) { 98 + match behaviour { 99 + RangeSplitBehavior::IncludeLower => ( 100 + Some(Self::new(self.start, *value + 1)), 101 + Some(Self::new(*value + 1, self.end)), 102 + ), 103 + RangeSplitBehavior::IncludeUpper => ( 104 + Some(Self::new(self.start, *value)), 105 + Some(Self::new(*value, self.end)), 106 + ), 107 + RangeSplitBehavior::Exclude => ( 108 + Some(Self::new(self.start, *value)), 109 + Some(Self::new(*value + 1, self.end)), 110 + ), 111 + } 112 + } else { 113 + (None, None) 114 + } 115 + } 116 + } 117 + 118 + impl<T: Copy + Clone + Debug + Ord> Into<Range<T>> for BetterRange<T> { 119 + fn into(self) -> Range<T> { 120 + self.start..self.end 121 + } 122 + } 123 + 124 + impl<T: Copy + Clone + Debug + Ord> From<Range<T>> for BetterRange<T> { 125 + fn from(range: Range<T>) -> Self { 126 + Self::new(range.start, range.end) 127 + } 128 + } 129 + 130 + impl<T: Copy + Clone + Debug + Ord> std::ops::Add<usize> for BetterRange<T> 131 + where 132 + T: std::ops::Add<usize, Output = T>, 133 + { 134 + type Output = Self; 135 + 136 + fn add(self, rhs: usize) -> Self::Output { 137 + Self::new(self.start + rhs, self.end + rhs) 138 + } 139 + } 140 + 141 + impl<T: Copy + Clone + Debug + Ord> std::ops::Sub<usize> for BetterRange<T> 142 + where 143 + T: std::ops::Sub<usize, Output = T>, 144 + { 145 + type Output = Self; 146 + 147 + fn sub(self, rhs: usize) -> Self::Output { 148 + Self::new(self.start - rhs, self.end - rhs) 149 + } 150 + } 151 + 152 + impl<T: Copy + Clone + Debug + Ord> std::ops::BitAnd for BetterRange<T> 153 + where 154 + T: std::ops::BitAnd<Output = T>, 155 + { 156 + type Output = Self; 157 + 158 + fn bitand(self, rhs: Self) -> Self::Output { 159 + Self::new(self.start.max(rhs.start), self.end.min(rhs.end)) 160 + } 161 + } 162 + 163 + impl<T: Copy + Clone + Debug + Ord> std::ops::BitOr for BetterRange<T> 164 + where 165 + T: std::ops::BitOr<Output = T>, 166 + { 167 + type Output = Self; 168 + 169 + fn bitor(self, rhs: Self) -> Self::Output { 170 + Self::new(self.start.min(rhs.start), self.end.max(rhs.end)) 171 + } 172 + }
+5 -4
years/2023/src/day_25.rs
··· 1 1 2 2 use core::{Day, day_stuff, ex_for_day}; 3 3 4 + use utils::yippee; 5 + 4 6 pub struct Day25; 5 7 6 8 impl Day for Day25 { 7 9 8 - day_stuff!(25, "", ""); 10 + day_stuff!(25, "", "🥳"); 9 11 10 12 fn part_1(_input: Self::Input) -> Option<String> { 11 13 None 12 14 } 13 15 14 - fn part_2(_input: Self::Input) -> Option<String> { 15 - None 16 - } 16 + yippee!(); 17 + 17 18 }
-1
years/2023/src/lib.rs
··· 1 - 2 1 use macros::year; 3 2 4 3 year!(2023);
-1
years/2023/src/main.rs
··· 1 - 2 1 use macros::year_runner; 3 2 4 3 year_runner!(2023);