Advent of Code solutions
0
fork

Configure Feed

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

Initial Project

Ben C 79ff0503

+1309
+1
.gitignore
··· 1 + /target
+3
.vscode/settings.json
··· 1 + { 2 + "rust-analyzer.showUnlinkedFileNotification": false 3 + }
+83
Cargo.lock
··· 1 + # This file is automatically @generated by Cargo. 2 + # It is not intended for manual editing. 3 + version = 3 4 + 5 + [[package]] 6 + name = "advent" 7 + version = "0.1.0" 8 + dependencies = [ 9 + "core", 10 + "macros", 11 + "y_2023", 12 + ] 13 + 14 + [[package]] 15 + name = "aho-corasick" 16 + version = "1.1.2" 17 + source = "registry+https://github.com/rust-lang/crates.io-index" 18 + checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" 19 + dependencies = [ 20 + "memchr", 21 + ] 22 + 23 + [[package]] 24 + name = "core" 25 + version = "0.1.0" 26 + dependencies = [ 27 + "regex", 28 + ] 29 + 30 + [[package]] 31 + name = "macros" 32 + version = "0.1.0" 33 + dependencies = [ 34 + "core", 35 + ] 36 + 37 + [[package]] 38 + name = "memchr" 39 + version = "2.6.4" 40 + source = "registry+https://github.com/rust-lang/crates.io-index" 41 + checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" 42 + 43 + [[package]] 44 + name = "regex" 45 + version = "1.10.2" 46 + source = "registry+https://github.com/rust-lang/crates.io-index" 47 + checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" 48 + dependencies = [ 49 + "aho-corasick", 50 + "memchr", 51 + "regex-automata", 52 + "regex-syntax", 53 + ] 54 + 55 + [[package]] 56 + name = "regex-automata" 57 + version = "0.4.3" 58 + source = "registry+https://github.com/rust-lang/crates.io-index" 59 + checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" 60 + dependencies = [ 61 + "aho-corasick", 62 + "memchr", 63 + "regex-syntax", 64 + ] 65 + 66 + [[package]] 67 + name = "regex-syntax" 68 + version = "0.8.2" 69 + source = "registry+https://github.com/rust-lang/crates.io-index" 70 + checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" 71 + 72 + [[package]] 73 + name = "utils" 74 + version = "0.1.0" 75 + 76 + [[package]] 77 + name = "y_2023" 78 + version = "0.1.0" 79 + dependencies = [ 80 + "core", 81 + "macros", 82 + "utils", 83 + ]
+24
Cargo.toml
··· 1 + [package] 2 + name = "advent" 3 + version = "0.1.0" 4 + edition = "2021" 5 + 6 + [workspace] 7 + 8 + members = [ 9 + "core", 10 + "macros", 11 + "utils", 12 + "years/*" 13 + ] 14 + 15 + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 16 + 17 + [dependencies] 18 + y_2023 = { path = "years/2023" } 19 + core = { path = "core" } 20 + macros = { path = "macros" } 21 + 22 + [[bin]] 23 + name = "advent" 24 + path = "src/main.rs"
+9
core/Cargo.toml
··· 1 + [package] 2 + name = "core" 3 + version = "0.1.0" 4 + edition = "2021" 5 + 6 + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 + 8 + [dependencies] 9 + regex = "1.10.2"
+166
core/src/bootstrap.rs
··· 1 + use std::path::Path; 2 + 3 + use regex::Regex; 4 + 5 + use crate::MAX_DAY; 6 + 7 + 8 + const DAY_TEMPLATE: &str = " 9 + use core::{Day, day_stuff, ex_for_day}; 10 + 11 + pub struct Day{day}; 12 + 13 + impl Day for Day{day} { 14 + 15 + day_stuff!({day}, \"\", \"\"); 16 + 17 + fn part_1(_input: Self::Input) -> Option<String> { 18 + None 19 + } 20 + 21 + fn part_2(_input: Self::Input) -> Option<String> { 22 + None 23 + } 24 + } 25 + "; 26 + 27 + const YEAR_TEMPLATE: &str = " 28 + use macros::year; 29 + 30 + year!({year}); 31 + "; 32 + 33 + const RUNNER_TEMPLATE: &str = " 34 + use macros::year_runner; 35 + 36 + year_runner!({year}); 37 + "; 38 + 39 + const CARGO_TEMPLATE: &str = " 40 + [package] 41 + name = \"y_{year}\" 42 + version = \"0.1.0\" 43 + edition = \"2021\" 44 + 45 + [dependencies] 46 + core = { path = \"../../core\" } 47 + macros = { path = \"../../macros\" } 48 + utils = { path = \"../../utils\" } 49 + "; 50 + 51 + fn make_day(folder: &Path, day: usize) { 52 + let day = day.to_string(); 53 + 54 + let day_path = folder.join(format!("day_{}.rs", day)); 55 + 56 + let contents = DAY_TEMPLATE.replace("{day}", &day); 57 + 58 + std::fs::write(day_path, contents).unwrap(); 59 + } 60 + 61 + fn make_example(folder: &Path, day: usize) { 62 + let day = day.to_string(); 63 + 64 + let example_path = folder.join(format!("day_{}", day)); 65 + 66 + let part_1_path = example_path.join("1.txt"); 67 + let part_2_path = example_path.join("2.txt"); 68 + 69 + std::fs::create_dir_all(&example_path).unwrap(); 70 + std::fs::write(part_1_path, "").unwrap(); 71 + std::fs::write(part_2_path, "").unwrap(); 72 + } 73 + 74 + fn make_days(folder: &Path) { 75 + for day in 1..=MAX_DAY { 76 + make_day(folder, day); 77 + } 78 + } 79 + 80 + fn make_examples(folder: &Path) { 81 + let examples_path = folder.join("examples"); 82 + for day in 1..=MAX_DAY { 83 + make_example(&examples_path, day); 84 + } 85 + } 86 + 87 + fn make_lib(folder: &Path, year: &str) { 88 + let lib_path = folder.join("lib.rs"); 89 + 90 + let contents = YEAR_TEMPLATE.replace("{year}", &year); 91 + 92 + std::fs::write(lib_path, contents).unwrap(); 93 + } 94 + 95 + fn make_main(folder: &Path, year: &str) { 96 + let main_path = folder.join("main.rs"); 97 + 98 + let contents = RUNNER_TEMPLATE.replace("{year}", &year); 99 + 100 + std::fs::write(main_path, contents).unwrap(); 101 + } 102 + 103 + fn make_src(folder: &Path, year: &str) { 104 + let src_path = folder.join("src"); 105 + 106 + std::fs::create_dir_all(&src_path).unwrap(); 107 + 108 + make_days(&src_path); 109 + make_examples(&src_path); 110 + make_lib(&src_path, &year); 111 + make_main(&src_path, &year); 112 + } 113 + 114 + fn make_cargo(folder: &Path, year: &str) { 115 + let cargo_path = folder.join("Cargo.toml"); 116 + 117 + let contents = CARGO_TEMPLATE.replace("{year}", &year); 118 + 119 + std::fs::write(cargo_path, contents).unwrap(); 120 + } 121 + 122 + fn replace_year_list(new_year: &str ) { 123 + let main = include_str!("../../src/main.rs"); 124 + 125 + let global_runner_pattern = Regex::new(r"global_runner!\(([\d,]+)\)").unwrap(); 126 + 127 + let matches = global_runner_pattern.captures(main).unwrap(); 128 + 129 + let full = matches.get(0).unwrap().as_str(); 130 + 131 + let mut years = matches.get(1).unwrap().as_str().split(",").map(|s| s.parse::<usize>().unwrap()).collect::<Vec<_>>(); 132 + 133 + years.push(new_year.parse::<usize>().unwrap()); 134 + 135 + years.sort(); 136 + 137 + let new_years = years.iter().map(|y| y.to_string()).collect::<Vec<_>>().join(","); 138 + 139 + let new_main = main.replace(full, &format!("global_runner!({})", new_years)); 140 + 141 + std::fs::write("src/main.rs", new_main).unwrap(); 142 + } 143 + 144 + fn replace_cargo_dependencies(new_year: &str) { 145 + let cargo = include_str!("../../Cargo.toml"); 146 + 147 + let new_dep = format!("y_{year} = {{ path = \"years/{year}\" }}", year = new_year); 148 + 149 + let cargo = cargo.replace("[dependencies]", &format!("[dependencies]\n{}", new_dep)); 150 + 151 + std::fs::write("Cargo.toml", cargo).unwrap(); 152 + } 153 + 154 + pub fn make_year(year: &str) { 155 + let cwd = std::env::current_dir().unwrap(); 156 + 157 + let year_path = cwd.join(format!("years/{}", year)); 158 + 159 + std::fs::create_dir_all(&year_path).unwrap(); 160 + 161 + make_src(&year_path, year); 162 + make_cargo(&year_path, year); 163 + 164 + replace_cargo_dependencies(year); 165 + replace_year_list(year); 166 + }
+175
core/src/day.rs
··· 1 + use std::time::Instant; 2 + 3 + #[macro_export] 4 + macro_rules! ex_for_day { 5 + ($day:literal, $part:literal) => { 6 + include_str!(concat!("examples/day_", stringify!($day), "/", stringify!($part), ".txt")) 7 + }; 8 + } 9 + 10 + #[macro_export] 11 + macro_rules! day_stuff { 12 + ($day:literal, $e_1:literal, $e_2:literal) => { 13 + day_stuff!($day, $e_1, $e_2, String); 14 + 15 + fn parse_input(input: &str) -> Self::Input { 16 + input.to_string() 17 + } 18 + }; 19 + 20 + ($day:literal, $e_1:literal, $e_2:literal, $i: ty) => { 21 + type Input = $i; 22 + 23 + const DAY: usize = $day; 24 + const EXAMPLE_INPUT_1: &'static str = ex_for_day!($day, 1); 25 + const EXAMPLE_INPUT_2: &'static str = ex_for_day!($day, 2); 26 + const EXPECTED_1: &'static str = $e_1; 27 + const EXPECTED_2: &'static str = $e_2; 28 + } 29 + } 30 + 31 + /// A trait for a day of Advent of Code. 32 + /// 33 + /// This trait is implemented for each day of Advent of Code. 34 + /// You're expected to implement the `EXAMPLE_INPUT_1` and `EXAMPLE_INPUT_2` constants 35 + /// with the example inputs for each part of the day. 36 + /// 37 + /// You're also expected to implement the `EXPECTED_1` and `EXPECTED_2` constants 38 + /// with the expected outputs for each part of the day. 39 + /// 40 + /// Then, any runner can use `run_part` to run a part of the day with a given input or the example input. 41 + /// 42 + pub trait Day { 43 + 44 + type Input; 45 + 46 + const DAY: usize = 0; 47 + 48 + const EXAMPLE_INPUT_1: &'static str = ""; 49 + const EXAMPLE_INPUT_2: &'static str = ""; 50 + 51 + const EXPECTED_1: &'static str = ""; 52 + const EXPECTED_2: &'static str = ""; 53 + 54 + fn get_example_input(part: usize) -> &'static str { 55 + match part { 56 + 1 => Self::EXAMPLE_INPUT_1, 57 + 2 => Self::EXAMPLE_INPUT_2, 58 + _ => panic!("Invalid part number"), 59 + } 60 + } 61 + 62 + fn run_part(part: usize, input: Option<&str>) -> Option<String> { 63 + let input = input.unwrap_or_else(|| Self::get_example_input(part)); 64 + let input = Self::parse_input(input); 65 + let instant = Instant::now(); 66 + let solution = match part { 67 + 1 => Self::part_1(input), 68 + 2 => Self::part_2(input), 69 + _ => panic!("Invalid part number"), 70 + }; 71 + println!("Day {} Part {}: {} ({}ms)", Self::DAY, part, solution.as_ref().unwrap_or(&"Not implemented".to_string()), instant.elapsed().as_millis()); 72 + solution 73 + } 74 + 75 + fn run_all_parts(extra_indent: &str) { 76 + println!("{extra_indent}Day {day}:", extra_indent = extra_indent, day = Self::DAY); 77 + for part in 1..=2 { 78 + let part_time = Instant::now(); 79 + let solution = match part { 80 + 1 => Self::part_1(Self::parse_input(Self::EXAMPLE_INPUT_1)), 81 + 2 => Self::part_2(Self::parse_input(Self::EXAMPLE_INPUT_2)), 82 + _ => panic!("Invalid part number"), 83 + }; 84 + println!("{extra_indent} Part {}: {} ({}ms)", part, solution.as_ref().unwrap_or(&"Not implemented".to_string()), part_time.elapsed().as_millis()); 85 + } 86 + } 87 + 88 + fn parse_input(input: &str) -> Self::Input; 89 + 90 + fn part_1(_input: Self::Input) -> Option<String> { 91 + None 92 + } 93 + fn part_2(_input: Self::Input) -> Option<String> { 94 + None 95 + } 96 + 97 + fn assert_part_1() { 98 + let expected = Self::EXPECTED_1; 99 + let actual = Self::run_part(1, None); 100 + if let Some(actual) = actual { 101 + assert_eq!(actual, expected); 102 + } 103 + } 104 + 105 + fn assert_part_2() { 106 + let expected = Self::EXPECTED_2; 107 + let actual = Self::run_part(2, None); 108 + if let Some(actual) = actual { 109 + assert_eq!(actual, expected); 110 + } 111 + } 112 + } 113 + 114 + #[cfg(test)] 115 + mod tests { 116 + 117 + use super::*; 118 + 119 + struct TestDay; 120 + 121 + impl Day for TestDay { 122 + 123 + type Input = String; 124 + 125 + const EXAMPLE_INPUT_1: &'static str = "Hello, world!"; 126 + const EXAMPLE_INPUT_2: &'static str = "Hello, world!"; 127 + 128 + const EXPECTED_1: &'static str = "Goodbye, world!"; 129 + const EXPECTED_2: &'static str = "Hello, moon!"; 130 + 131 + fn parse_input(input: &str) -> String { 132 + input.to_string() 133 + } 134 + 135 + fn part_1(input: String) -> Option<String> { 136 + Some(input.replace("Hello", "Goodbye")) 137 + } 138 + 139 + fn part_2(input: String) -> Option<String> { 140 + Some(input.replace("world", "moon")) 141 + } 142 + } 143 + 144 + struct TestDay2; 145 + 146 + impl Day for TestDay2 { 147 + 148 + type Input = Vec<String>; 149 + 150 + const EXAMPLE_INPUT_1: &'static str = "A\nB\nC"; 151 + 152 + const EXPECTED_1: &'static str = "A,B,C"; 153 + 154 + fn parse_input(input: &str) -> Vec<String> { 155 + input.lines().map(|l| l.to_string()).collect::<Vec<_>>() 156 + } 157 + 158 + fn part_1(input: Vec<String>) -> Option<String> { 159 + Some(input.join(",").to_string()) 160 + } 161 + } 162 + 163 + #[test] 164 + fn test_day_1() { 165 + TestDay::assert_part_1(); 166 + TestDay::assert_part_2(); 167 + } 168 + 169 + #[test] 170 + fn test_day_2() { 171 + TestDay2::assert_part_1(); 172 + // Should skip 173 + TestDay2::assert_part_2(); 174 + } 175 + }
+11
core/src/lib.rs
··· 1 + mod day; 2 + mod year; 3 + mod parser; 4 + mod bootstrap; 5 + 6 + pub const MAX_DAY: usize = 25; 7 + 8 + pub use day::Day; 9 + 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;
+120
core/src/parser.rs
··· 1 + use std::io::{stdin, Read}; 2 + use std::env::args; 3 + #[derive(Clone, Debug)] 4 + pub enum Selection { 5 + All, 6 + Single(usize), // TODO: Add range maybe? 7 + } 8 + 9 + impl Selection { 10 + 11 + fn parse(input: &str) -> Self { 12 + if input == "*" { 13 + Self::All 14 + } else { 15 + let input = input.parse::<usize>().unwrap(); 16 + Self::Single(input) 17 + } 18 + } 19 + 20 + } 21 + 22 + #[derive(Clone, Debug)] 23 + pub struct DP { 24 + pub day: Selection, 25 + pub part: Selection, 26 + } 27 + 28 + const DP_ALL: DP = DP { 29 + day: Selection::All, 30 + part: Selection::All, 31 + }; 32 + 33 + impl DP { 34 + 35 + fn parse(input: &str) -> Self { 36 + let mut split = input.split(':'); 37 + 38 + let day = split.next().map(Selection::parse).unwrap_or(Selection::All); 39 + let part = split.next().map(Selection::parse).unwrap_or(Selection::All); 40 + 41 + Self { 42 + day, 43 + part, 44 + } 45 + } 46 + 47 + } 48 + 49 + #[derive(Clone, Debug)] 50 + pub struct YDP { 51 + pub year: Selection, 52 + pub day: Selection, 53 + pub part: Selection, 54 + } 55 + 56 + impl YDP { 57 + 58 + fn parse(input: &str) -> Self { 59 + let mut split = input.split(':'); 60 + 61 + let year = split.next().map(Selection::parse).unwrap_or(Selection::All); 62 + let day = split.next().map(Selection::parse).unwrap_or(Selection::All); 63 + let part = split.next().map(Selection::parse).unwrap_or(Selection::All); 64 + 65 + Self { 66 + year, 67 + day, 68 + part, 69 + } 70 + } 71 + 72 + pub fn to_dp(&self) -> DP { 73 + DP { 74 + day: self.day.clone(), 75 + part: self.part.clone(), 76 + } 77 + } 78 + 79 + } 80 + 81 + pub fn get_dp_and_input() -> (DP, Option<String>) { 82 + let mut args = args().skip(1); 83 + 84 + let dp = args.next().map(|s| DP::parse(&s.trim())).unwrap_or(DP_ALL); 85 + 86 + let input = args.next().map(|s| s.trim().to_string()).map(|i| { 87 + if i == "-" { 88 + let mut input = String::new(); 89 + stdin().read_to_string(&mut input).expect("Failed to read input"); 90 + input.trim().to_string() 91 + } else { 92 + i 93 + } 94 + }); 95 + 96 + (dp, input) 97 + } 98 + 99 + pub fn get_ydp_and_input(args: Vec<String>) -> (YDP, Option<String>) { 100 + 101 + let mut args = args.into_iter(); 102 + 103 + let ydp = args.next().map(|s| YDP::parse(&s.trim())).unwrap_or(YDP { 104 + year: Selection::All, 105 + day: Selection::All, 106 + part: Selection::All, 107 + }); 108 + 109 + let input = args.next().map(|s| s.trim().to_string()).map(|i| { 110 + if i == "-" { 111 + let mut input = String::new(); 112 + stdin().read_to_string(&mut input).expect("Failed to read input"); 113 + input.trim().to_string() 114 + } else { 115 + i 116 + } 117 + }); 118 + 119 + (ydp, input) 120 + }
+36
core/src/year.rs
··· 1 + use crate::parser::{DP, Selection}; 2 + 3 + use super::MAX_DAY; 4 + 5 + pub trait Year { 6 + const YEAR: usize; 7 + 8 + fn solve_day(day: usize, part: usize, input: Option<&str>) -> Option<String>; 9 + 10 + fn solve_day_both_parts(day: usize, extra_indent: &str); 11 + 12 + fn solve_all_days() { 13 + println!("Year {}:", Self::YEAR); 14 + for day in 1..=MAX_DAY { 15 + Self::solve_day_both_parts(day, " "); 16 + } 17 + } 18 + 19 + fn run_dp(input: Option<&str>, dp: DP) { 20 + match dp.day { 21 + Selection::All => { 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 + }, 32 + } 33 + }, 34 + } 35 + } 36 + }
+12
macros/Cargo.toml
··· 1 + [package] 2 + name = "macros" 3 + version = "0.1.0" 4 + edition = "2021" 5 + 6 + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 + 8 + [lib] 9 + proc-macro = true 10 + 11 + [dependencies] 12 + core = { path = "../core" }
+158
macros/src/lib.rs
··· 1 + extern crate proc_macro; 2 + 3 + use core::MAX_DAY; 4 + 5 + use proc_macro::TokenStream; 6 + 7 + fn make_day_mods() -> String { 8 + (1..=MAX_DAY).map(|day| format!("mod day_{day};", day = day)).collect::<Vec<_>>().join("\n") 9 + } 10 + 11 + fn make_use_days() -> String { 12 + (1..=MAX_DAY).map(|day| format!("use day_{day}::Day{day};", day = day)).collect::<Vec<_>>().join("\n") 13 + } 14 + 15 + 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") 17 + } 18 + 19 + fn make_day_tests() -> String { 20 + (1..=MAX_DAY).map(|day| format!(" 21 + #[test] 22 + fn test_day_{day}_part_1() {{ 23 + Day{day}::assert_part_1(); 24 + }} 25 + 26 + #[test] 27 + fn test_day_{day}_part_2() {{ 28 + Day{day}::assert_part_2(); 29 + }}")).collect::<Vec<_>>().join("\n") 30 + } 31 + 32 + fn get_solve_day() -> String { 33 + let inner = make_day_match("Day{day}::run_part(part, input)"); 34 + format!(" 35 + fn solve_day(day: usize, part: usize, input: Option<&str>) -> Option<String> {{ 36 + match day {{ 37 + {inner} 38 + _ => None, 39 + }} 40 + }}", inner = inner) 41 + } 42 + 43 + fn get_solve_day_both_parts() -> String { 44 + let inner = make_day_match("Day{day}::run_all_parts(extra_indent)"); 45 + format!(" 46 + fn solve_day_both_parts(day: usize, extra_indent: &str) {{ 47 + match day {{ 48 + {inner} 49 + _ => (), 50 + }} 51 + }}", inner = inner) 52 + } 53 + 54 + fn make_year_struct(year: &str) -> String { 55 + format!(" 56 + pub struct Year{year}; 57 + 58 + impl Year for Year{year} {{ 59 + const YEAR: usize = {year}; 60 + 61 + {solve_day} 62 + 63 + {solve_day_both_parts} 64 + }}", solve_day = get_solve_day(), solve_day_both_parts = get_solve_day_both_parts()) 65 + } 66 + 67 + fn make_tests() -> String { 68 + format!(" 69 + #[cfg(test)] 70 + mod tests {{ 71 + use super::*; 72 + use core::{{Day, Year}}; 73 + 74 + {day_tests} 75 + }}", day_tests = make_day_tests()) 76 + } 77 + 78 + #[proc_macro] 79 + pub fn year(item: TokenStream) -> TokenStream { 80 + let year = item.to_string(); 81 + 82 + let mods = make_day_mods(); 83 + let uses = make_use_days(); 84 + 85 + let year_struct = make_year_struct(&year); 86 + 87 + let tests = make_tests(); 88 + 89 + format!(" 90 + {mods} 91 + 92 + use core::{{Year, Day}}; 93 + {uses} 94 + 95 + {year_struct} 96 + 97 + {tests} 98 + ").parse::<TokenStream>().unwrap() 99 + } 100 + 101 + #[proc_macro] 102 + pub fn year_runner(item: TokenStream) -> TokenStream { 103 + let year = item.to_string(); 104 + 105 + format!(" 106 + use core::{{Year, get_dp_and_input}}; 107 + 108 + use y_{year}::Year{year}; 109 + 110 + fn main() {{ 111 + let (dp, input) = get_dp_and_input(); 112 + Year{year}::run_dp(input.as_deref(), dp); 113 + }}").parse::<TokenStream>().unwrap() 114 + } 115 + 116 + 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") 118 + } 119 + 120 + 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") 122 + } 123 + 124 + 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") 126 + } 127 + 128 + fn make_run_year(years: &Vec<&str>) -> String { 129 + let inner = make_year_match(years, "Year{year}::run_dp(input.as_deref(), dp)"); 130 + format!(" 131 + fn run_year(year: usize, dp: DP, input: Option<&str>) {{ 132 + match year {{ 133 + {inner} 134 + _ => {{ 135 + println!(\"Unknown year: {{year}}\"); 136 + }} 137 + }} 138 + }}", inner = inner) 139 + } 140 + 141 + #[proc_macro] 142 + pub fn global_runner(item: TokenStream) -> TokenStream { 143 + let item = item.to_string(); 144 + let years = item.split(',').map(|s| s.trim()).collect::<Vec<_>>(); 145 + 146 + let year_uses = make_year_uses(&years); 147 + let run_all_years = make_run_all_years(&years); 148 + let run_year = make_run_year(&years); 149 + 150 + format!(" 151 + {year_uses} 152 + 153 + {run_year} 154 + 155 + fn run_all_years(dp: &DP, input: Option<String>) {{ 156 + {run_all_years} 157 + }}").parse::<TokenStream>().unwrap() 158 + }
+46
src/main.rs
··· 1 + use core::{get_ydp_and_input, make_year, Year, Selection, YDP, DP}; 2 + use macros::global_runner; 3 + 4 + global_runner!(2023); 5 + 6 + fn run_ydp(ydp: YDP, input: Option<String>) { 7 + let dp = ydp.to_dp(); 8 + 9 + match ydp.year { 10 + Selection::All => { 11 + run_all_years(&dp, input); 12 + }, 13 + Selection::Single(year) => { 14 + run_year(year, dp, input.as_deref()); 15 + }, 16 + } 17 + } 18 + 19 + fn main() { 20 + let args = std::env::args().skip(1).collect::<Vec<_>>(); 21 + 22 + let command = args.get(0); 23 + 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 + } 39 + } 40 + }, 41 + None => { 42 + println!("No command provided"); 43 + println!("Available commands: new, solve"); 44 + } 45 + } 46 + }
+8
utils/Cargo.toml
··· 1 + [package] 2 + name = "utils" 3 + version = "0.1.0" 4 + edition = "2021" 5 + 6 + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 + 8 + [dependencies]
+14
utils/src/lib.rs
··· 1 + pub fn add(left: usize, right: usize) -> usize { 2 + left + right 3 + } 4 + 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 + } 14 + }
+10
years/2023/Cargo.toml
··· 1 + 2 + [package] 3 + name = "y_2023" 4 + version = "0.1.0" 5 + edition = "2021" 6 + 7 + [dependencies] 8 + core = { path = "../../core" } 9 + macros = { path = "../../macros" } 10 + utils = { path = "../../utils" }
+17
years/2023/src/day_1.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day1; 5 + 6 + impl Day for Day1 { 7 + 8 + day_stuff!(1, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_10.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day10; 5 + 6 + impl Day for Day10 { 7 + 8 + day_stuff!(10, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_11.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day11; 5 + 6 + impl Day for Day11 { 7 + 8 + day_stuff!(11, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_12.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day12; 5 + 6 + impl Day for Day12 { 7 + 8 + day_stuff!(12, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_13.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day13; 5 + 6 + impl Day for Day13 { 7 + 8 + day_stuff!(13, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_14.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day14; 5 + 6 + impl Day for Day14 { 7 + 8 + day_stuff!(14, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_15.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day15; 5 + 6 + impl Day for Day15 { 7 + 8 + day_stuff!(15, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_16.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day16; 5 + 6 + impl Day for Day16 { 7 + 8 + day_stuff!(16, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_17.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day17; 5 + 6 + impl Day for Day17 { 7 + 8 + day_stuff!(17, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_18.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day18; 5 + 6 + impl Day for Day18 { 7 + 8 + day_stuff!(18, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_19.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day19; 5 + 6 + impl Day for Day19 { 7 + 8 + day_stuff!(19, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_2.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day2; 5 + 6 + impl Day for Day2 { 7 + 8 + day_stuff!(2, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_20.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day20; 5 + 6 + impl Day for Day20 { 7 + 8 + day_stuff!(20, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_21.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day21; 5 + 6 + impl Day for Day21 { 7 + 8 + day_stuff!(21, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_22.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day22; 5 + 6 + impl Day for Day22 { 7 + 8 + day_stuff!(22, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_23.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day23; 5 + 6 + impl Day for Day23 { 7 + 8 + day_stuff!(23, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_24.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day24; 5 + 6 + impl Day for Day24 { 7 + 8 + day_stuff!(24, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_25.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day25; 5 + 6 + impl Day for Day25 { 7 + 8 + day_stuff!(25, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_3.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day3; 5 + 6 + impl Day for Day3 { 7 + 8 + day_stuff!(3, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_4.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day4; 5 + 6 + impl Day for Day4 { 7 + 8 + day_stuff!(4, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_5.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day5; 5 + 6 + impl Day for Day5 { 7 + 8 + day_stuff!(5, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_6.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day6; 5 + 6 + impl Day for Day6 { 7 + 8 + day_stuff!(6, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_7.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day7; 5 + 6 + impl Day for Day7 { 7 + 8 + day_stuff!(7, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_8.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day8; 5 + 6 + impl Day for Day8 { 7 + 8 + day_stuff!(8, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
+17
years/2023/src/day_9.rs
··· 1 + 2 + use core::{Day, day_stuff, ex_for_day}; 3 + 4 + pub struct Day9; 5 + 6 + impl Day for Day9 { 7 + 8 + day_stuff!(9, "", ""); 9 + 10 + fn part_1(_input: Self::Input) -> Option<String> { 11 + None 12 + } 13 + 14 + fn part_2(_input: Self::Input) -> Option<String> { 15 + None 16 + } 17 + }
years/2023/src/examples/day_1/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_1/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_10/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_10/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_11/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_11/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_12/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_12/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_13/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_13/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_14/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_14/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_15/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_15/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_16/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_16/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_17/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_17/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_18/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_18/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_19/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_19/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_2/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_2/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_20/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_20/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_21/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_21/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_22/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_22/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_23/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_23/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_24/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_24/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_25/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_25/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_3/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_3/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_4/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_4/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_5/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_5/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_6/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_6/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_7/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_7/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_8/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_8/2.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_9/1.txt

This is a binary file and will not be displayed.

years/2023/src/examples/day_9/2.txt

This is a binary file and will not be displayed.

+4
years/2023/src/lib.rs
··· 1 + 2 + use macros::year; 3 + 4 + year!(2023);
+4
years/2023/src/main.rs
··· 1 + 2 + use macros::year_runner; 3 + 4 + year_runner!(2023);