diff --git a/Cargo.lock b/Cargo.lock index 9eb3ea8..6559230 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,7 @@ dependencies = [ name = "adventofcode-macros" version = "0.1.0" dependencies = [ + "proc-macro2", "quote", "syn", ] diff --git a/Cargo.toml b/Cargo.toml index 9708ac4..8dd3943 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,156 @@ edition = "2021" description = "My solutions for Advent of code 2024" +[[bin]] +name = "2023-01" +test = false +bench = false +path = "src/bin/2023/01.rs" + +[[bin]] +name = "2023-02" +test = false +bench = false +path = "src/bin/2023/02.rs" + +[[bin]] +name = "2023-03" +test = false +bench = false +path = "src/bin/2023/03.rs" + +[[bin]] +name = "2023-04" +test = false +bench = false +path = "src/bin/2023/04.rs" + +[[bin]] +name = "2023-05" +test = false +bench = false +path = "src/bin/2023/05.rs" + +[[bin]] +name = "2023-06" +test = false +bench = false +path = "src/bin/2023/06.rs" + +[[bin]] +name = "2023-07" +test = false +bench = false +path = "src/bin/2023/07.rs" + +[[bin]] +name = "2023-08" +test = false +bench = false +path = "src/bin/2023/08.rs" + +[[bin]] +name = "2023-09" +test = false +bench = false +path = "src/bin/2023/09.rs" + +[[bin]] +name = "2023-10" +test = false +bench = false +path = "src/bin/2023/10.rs" + +[[bin]] +name = "2023-11" +test = false +bench = false +path = "src/bin/2023/11.rs" + +[[bin]] +name = "2023-12" +test = false +bench = false +path = "src/bin/2023/12.rs" + +[[bin]] +name = "2023-13" +test = false +bench = false +path = "src/bin/2023/13.rs" + +[[bin]] +name = "2023-14" +test = false +bench = false +path = "src/bin/2023/14.rs" + +[[bin]] +name = "2023-15" +test = false +bench = false +path = "src/bin/2023/15.rs" + +[[bin]] +name = "2023-16" +test = false +bench = false +path = "src/bin/2023/16.rs" + +[[bin]] +name = "2023-17" +test = false +bench = false +path = "src/bin/2023/17.rs" + +[[bin]] +name = "2023-18" +test = false +bench = false +path = "src/bin/2023/18.rs" + +[[bin]] +name = "2023-19" +test = false +bench = false +path = "src/bin/2023/19.rs" + +[[bin]] +name = "2023-20" +test = false +bench = false +path = "src/bin/2023/20.rs" + +[[bin]] +name = "2023-21" +test = false +bench = false +path = "src/bin/2023/21.rs" + +[[bin]] +name = "2023-22" +test = false +bench = false +path = "src/bin/2023/22.rs" + +[[bin]] +name = "2023-23" +test = false +bench = false +path = "src/bin/2023/23.rs" + +[[bin]] +name = "2023-24" +test = false +bench = false +path = "src/bin/2023/24.rs" + +[[bin]] +name = "2023-25" +test = false +bench = false +path = "src/bin/2023/25.rs" + [[bin]] name = "2024-01" test = false diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..5339304 --- /dev/null +++ b/build.rs @@ -0,0 +1,8 @@ +fn main() { + for year in 2015..2025 { + for day in 1..26 { + println!("cargo::rerun-if-changed=data/{year:04}/{day:02}.txt"); + } + } + println!("cargo::rerun-if-changed=build.rs"); +} diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 74680c1..9194f08 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -9,3 +9,4 @@ proc-macro = true [dependencies] quote = "1.0.*" syn = "2.0.*" +proc-macro2 = {version = "*", features = ["span-locations"]} \ No newline at end of file diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 12b6fbe..bb25b57 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -13,8 +13,26 @@ struct IncludeData { } fn get_string<'a, 'b>(cursor: StepCursor<'a, 'b>) -> Result<(String, Cursor<'a>)> { - let (lit, c) = cursor.literal().unwrap(); - Ok((lit.span().source_text().unwrap(), c)) + let (lit, c) = match cursor.literal() { + Some(literal) => literal, + None => return Err(Error::new(cursor.span(), "Failed to get literal")), + }; + let span = lit.span(); + let text = match span.source_text() { + Some(text) => text, + None => { + let start = span.start(); + let end = span.end(); + return Err(Error::new( + span, + format!( + "Failed to get sourcetext for {}:{}-{}:{}", + start.line, start.column, end.line, end.column, + ), + )); + } + }; + Ok((text, c)) } impl Parse for IncludeData { @@ -26,41 +44,59 @@ impl Parse for IncludeData { let mut look = input.lookahead1(); if !look.peek(LitInt) { let s = input.span(); - return Err(Error::new(s, format!("{} is not an valid Year", s.source_text().unwrap()))); + return Err(Error::new( + s, + format!("{} is not an valid Year", s.source_text().unwrap()), + )); } data.year = input.step(get_string).expect("Wanted an string"); look = input.lookahead1(); if !look.peek(LitInt) { let s = input.span(); - return Err(Error::new(s, format!("{} is not an valid Day", s.source_text().unwrap()))); + return Err(Error::new( + s, + format!("{} is not an valid Day", s.source_text().unwrap()), + )); } data.day = input.step(get_string).expect("Wanted an string"); Ok(data) } } +fn get_stream(dir: &str, data: Result) -> TokenStream { + match data { + Ok(id) => { + let path = format!("../../../{}/{}/{}.txt", dir, id.year, id.day); + quote! { + static DATA: &str = include_str!(#path); + } + } + Err(_)=> { + quote! { + static DATA: &str = ""; + } + } + }.into() +} + /// includes Data from Advent of code /// ```ignore (cannot-doctest-external-file-dependency) /// include_data!(2015 01) -/// +/// /// fn main() { /// print!("{DATA}"); /// } /// ``` +/// The Equivalent is +/// ```ignore (cannot-doctest-external-file-dependency) +/// static DATA: &str = include_str!("../../../data/2015/01.txt"); +/// ``` #[proc_macro] -pub fn include_data(data: TokenStream)->TokenStream { - let gen = match parse::(data) { - Ok(data) => { - let path = format!("../../../data/{}/{}.txt", data.year, data.day); - quote! { - static DATA: &str = include_str!(#path); - } - }, - Err(_) => { - quote! { - static DATA: &str = ""; - } - }, - }; - gen.into() +pub fn include_data(data: TokenStream) -> TokenStream { + get_stream("data", parse::(data)) } + +#[proc_macro] +pub fn include_example(data: TokenStream)->TokenStream { + get_stream("examples", parse::(data)) +} \ No newline at end of file diff --git a/src/bin/2023/01.rs b/src/bin/2023/01.rs new file mode 100644 index 0000000..b8beef8 --- /dev/null +++ b/src/bin/2023/01.rs @@ -0,0 +1,34 @@ +use advent_of_code::strings::{get_numbers, get_string_numbers}; +#[allow(unused_imports)] +use adventofcode_macros::{include_example, include_example}; + +include_example!(2023 01); +//static DATA: &str; + +fn main() { + let mut sum: u32 = 0; + let data: String = DATA.into(); + for coordinates in data.split('\n').map(get_numbers) { + if coordinates.len() == 0 { + continue; + } + let first = coordinates.first().unwrap() * 10; + let last = *coordinates.last().unwrap(); + let number = first + last; + println!("Number: {}", number); + sum += number; + } + println!("Sum of Numbers {}", sum); + sum = 0; + for coordinates in data.split('\n').map(get_string_numbers) { + if coordinates.len() == 0 { + continue; + } + let first = coordinates.first().unwrap() * 10; + let last = *coordinates.last().unwrap(); + let number = first + last; + println!("Number: {}", number); + sum += number; + } + println!("Sum of Numbers with strings {}", sum); +} diff --git a/src/bin/2023/02.rs b/src/bin/2023/02.rs new file mode 100644 index 0000000..493433e --- /dev/null +++ b/src/bin/2023/02.rs @@ -0,0 +1,111 @@ +use advent_of_code::strings::parsenumber; +#[allow(unused_imports)] +use adventofcode_macros::{include_example, include_example}; + +include_example!(2023 02); +//static DATA: &str; + +#[derive(Debug, Clone, Copy)] +struct Take { + red: u32, + green: u32, + blue: u32, +} + +#[derive(Debug, Clone)] +struct Round { + roundid: u32, + takes: Vec, +} + +#[derive(Debug, Clone, Copy)] +struct Sack { + reds: u32, + greens: u32, + blues: u32, +} + +impl Round { + pub fn possible(&self, sack: Sack) -> bool { + let mut ok = true; + for take in self.takes.clone() { + ok = ok + && if sack.reds.checked_sub(take.red).is_none() { + false + } else if sack.greens.checked_sub(take.green).is_none() { + false + } else if sack.blues.checked_sub(take.blue).is_none() { + false + } else { + true + }; + } + ok + } + fn power(&self) -> u64 { + let mut sack = Sack{reds:0, greens:0, blues:0}; + for take in self.takes.clone() { + if take.red > sack.reds { + sack.reds = take.red + }if take.green > sack.greens { + sack.greens = take.green + }if take.blue > sack.blues { + sack.blues = take.blue + } + } + sack.reds as u64 *sack.greens as u64*sack.blues as u64 + } +} + +impl From<&str> for Round { + fn from(value: &str) -> Self { + let doublecolon = value.find(':').unwrap(); + let mut round = Round { + roundid: parsenumber(value.get(5..doublecolon).unwrap()), + takes: Vec::::new(), + }; + for taking in value.get(doublecolon + 1..).unwrap().split(";") { + let mut take = Take { + red: 0, + green: 0, + blue: 0, + }; + for color in taking.split(',').map(str::trim) { + let mut i = color.splitn(2, char::is_whitespace); + let amount = parsenumber(i.next().unwrap()); + match i.next() { + Some("red") => take.red = amount, + Some("green") => take.green = amount, + Some("blue") => take.blue = amount, + None | Some(_) => panic!(), + } + } + round.takes.push(take); + } + round + } +} + +fn main() { + let mut gamerounds = Vec::::with_capacity(100); + for game in DATA.split('\n') { + gamerounds.push(game.into()); + } + let sack = Sack { + reds: 12, + greens: 13, + blues: 14, + }; + let mut sum = 0; + for round in gamerounds.clone() { + if round.possible(sack) { + sum += round.roundid; + } + } + println!("Sum with putback: {}", sum); + let mut sum = 0; + for round in gamerounds { + sum += round.power(); + } + println!("Combined Power: {}", sum); +} diff --git a/src/strings.rs b/src/strings.rs index 09338f2..7feb745 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -30,3 +30,129 @@ pub fn parsenumber(input: &str) -> u32 { } output } + +pub fn get_numbers(input: &str) -> Vec { + let mut numbers = Vec::new(); + for char in input.chars() { + match char { + '1' => numbers.push(1), + '2' => numbers.push(2), + '3' => numbers.push(3), + '4' => numbers.push(4), + '5' => numbers.push(5), + '6' => numbers.push(6), + '7' => numbers.push(7), + '8' => numbers.push(8), + '9' => numbers.push(9), + '0' => numbers.push(0), + _ => {} + } + } + numbers +} + +pub fn get_string_numbers(input: &str) -> Vec { + let len = input.len(); + let mut output = Vec::new(); + for i in 0..len { + match input.get(i..i + 1).unwrap() { + "1" => { + output.push(1); + continue; + } + "2" => { + output.push(2); + continue; + } + "3" => { + output.push(3); + continue; + } + "4" => { + output.push(4); + continue; + } + "5" => { + output.push(5); + continue; + } + "6" => { + output.push(6); + continue; + } + "7" => { + output.push(7); + continue; + } + "8" => { + output.push(8); + continue; + } + "9" => { + output.push(9); + continue; + } + "0" => { + output.push(0); + continue; + } + _ => {} + } + if (i + 3) <= len { + match input.get(i..i + 3).unwrap() { + "one" => { + output.push(1); + continue; + } + "two" => { + output.push(2); + continue; + } + "six" => { + output.push(6); + continue; + } + _ => {} + }; + } + if (i + 4) <= len { + match input.get(i..i + 4).unwrap() { + "four" => { + output.push(4); + continue; + } + "five" => { + output.push(5); + continue; + } + "nine" => { + output.push(9); + continue; + } + "zero" => { + output.push(0); + continue; + } + _ => {} + }; + } + if (i + 5) <= len { + match input.get(i..i + 5).unwrap() { + "three" => { + output.push(3); + continue; + } + "seven" => { + output.push(7); + continue; + } + "eight" => { + output.push(8); + continue; + } + _ => {} + }; + } + } + output +}