Commits vergleichen

..

10 Commits

13 geänderte Dateien mit 310 neuen und 104 gelöschten Zeilen

4
.gitignore gevendort
Datei anzeigen

@ -1,3 +1,5 @@
/target /target
/data /data/**/*.txt
!/data/2023/01a.txt
!/data/2023/01b.txt
!/data/20*/.gitkeep !/data/20*/.gitkeep

51
Cargo.lock generiert
Datei anzeigen

@ -3,14 +3,15 @@
version = 4 version = 4
[[package]] [[package]]
name = "adventofcode" name = "advent-of-code"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"adventofcode-macros", "advent-of-code-macros",
"regex",
] ]
[[package]] [[package]]
name = "adventofcode-macros" name = "advent-of-code-macros"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
@ -18,6 +19,21 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.92" version = "1.0.92"
@ -36,6 +52,35 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.90" version = "2.0.90"

Datei anzeigen

@ -1,5 +1,5 @@
[package] [package]
name = "adventofcode" name = "advent-of-code"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
description = "My solutions for Advent of code 2024" description = "My solutions for Advent of code 2024"
@ -310,9 +310,13 @@ name = "advent_of_code"
[dependencies] [dependencies]
[dependencies.adventofcode-macros] [dependencies.advent-of-code-macros]
path = "macros" path = "macros"
[dependencies.regex]
version = "1.11.*"
features = []
[workspace] [workspace]
[workspace.dependencies] [workspace.dependencies]

1
data/2023/01a.txt Softlink
Datei anzeigen

@ -0,0 +1 @@
01.txt

1
data/2023/01b.txt Softlink
Datei anzeigen

@ -0,0 +1 @@
01.txt

Datei anzeigen

@ -1,5 +1,5 @@
[package] [package]
name = "adventofcode-macros" name = "advent-of-code-macros"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
@ -8,5 +8,8 @@ proc-macro = true
[dependencies] [dependencies]
quote = "1.0.*" quote = "1.0.*"
syn = "2.0.*"
proc-macro2 = {version = "*", features = ["span-locations"]} proc-macro2 = {version = "*", features = ["span-locations"]}
[dependencies.syn]
version = ">=2.0.90"
features = ["full"]

Datei anzeigen

@ -1,101 +1,87 @@
use std::fs; use std::fs;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote; use quote::{format_ident, quote};
use syn::{parse, Result};
use syn::{ use syn::{
buffer::Cursor, parse::{Parse, ParseStream},
parse::{Parse, ParseStream, StepCursor}, spanned::Spanned,
Error, Error, Ident, Lit, LitInt,
}; };
use syn::{parse, LitInt, Result};
const DATA_DIR: &str = "data"; const DATA_DIR: &str = "data";
const EXAMPLE_DIR: &str = "examples"; const EXAMPLE_DIR: &str = "examples";
const VAR_NAME: &str = "DATA";
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct IncludeData { struct IncludeData {
year: String, var: String,
day: String, year: Option<String>,
day: Option<String>,
} }
fn get_string<'a, 'b>(cursor: StepCursor<'a, 'b>) -> Result<(String, Cursor<'a>)> { impl Default for IncludeData {
let (lit, c) = match cursor.literal() { fn default() -> Self {
Some(literal) => literal, IncludeData {
None => return Err(Error::new(cursor.span(), "Failed to get literal")), var: VAR_NAME.into(),
}; year: None,
let span = lit.span(); day: None,
let text = match span.source_text() { }
Some(text) => text, }
}
fn get_text<T: Spanned>(item: T) -> Result<String> {
let span = item.span();
match span.source_text() {
Some(text) => Ok(text),
None => { None => {
let start = span.start(); let start = span.start();
let end = span.end(); let end = span.end();
return Err(Error::new( Err(Error::new(
span, span,
format!( format!(
"Failed to get sourcetext for {}:{}-{}:{}", "Failed to get sourcetext for {}:{}-{}:{}",
start.line, start.column, end.line, end.column, start.line, start.column, end.line, end.column,
), ),
)); ))
} }
}; }
Ok((text, c))
} }
impl Parse for IncludeData { impl Parse for IncludeData {
fn parse(input: ParseStream) -> Result<Self> { fn parse(input: ParseStream) -> Result<Self> {
let mut data = IncludeData { let mut data = IncludeData::default();
year: "".into(), if input.peek(Ident) && !input.peek(LitInt) {
day: "".into(), data.var = get_text(input.parse::<Ident>().unwrap())?;
};
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()),
));
} }
data.year = input.step(get_string).expect("Wanted an string"); data.year = Some(get_text(input.parse::<LitInt>()?)?);
look = input.lookahead1(); data.day = Some(get_text(input.parse::<Lit>()?)?);
if !look.peek(LitInt) {
let s = input.span();
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) Ok(data)
} }
} }
fn canonicalize(dir: &str, input: Result<IncludeData>) -> Option<String> { fn canonicalize(dir: &str, input: IncludeData) -> Option<String> {
let pathname = match input { let pathname = format!("{}/{}/{}.txt", dir, input.year.unwrap(), input.day.unwrap());
Ok(id) => Some(format!("{}/{}/{}.txt", dir, id.year, id.day)), match fs::canonicalize(pathname) {
Err(_) => None, Ok(canon) => {
}; if canon.is_file() {
if let Some(p) = pathname { match canon.to_str() {
match fs::canonicalize(p.clone()) { Some(c) => Some(c.to_string()),
Ok(canon) => { None => None,
if canon.is_file() {
Some(canon.to_str().unwrap().to_string())
} else {
println!("ERROR: {:?} is not a file", canon);
None
} }
} } else {
Err(err) => {
println!("ERROR: {} does not exist: {}", p, err);
None None
} }
} }
} else { Err(_) => None,
None
} }
} }
/// includes Data from Advent of code /// includes Data from Advent of code
/// ```ignore (cannot-doctest-external-file-dependency) /// ```ignore (cannot-doctest-external-file-dependency)
/// include_data!(DATA 2015 01)
/// // or
/// include_data!(2015 01) /// include_data!(2015 01)
/// ///
/// fn main() { /// fn main() {
@ -108,33 +94,73 @@ fn canonicalize(dir: &str, input: Result<IncludeData>) -> Option<String> {
/// ``` /// ```
#[proc_macro] #[proc_macro]
pub fn include_data(data: TokenStream) -> TokenStream { pub fn include_data(data: TokenStream) -> TokenStream {
let input = parse::<IncludeData>(data); let input = match parse::<IncludeData>(data) {
let mut path = canonicalize(DATA_DIR, input.clone()); Ok(include) => include,
if path.is_none() { Err(error) => return error.into_compile_error().into(),
path = canonicalize(EXAMPLE_DIR, input) };
} let ident = format_ident!("{}", input.var);
match path { let mut comment: String;
Some(p) => quote! { if input.day.is_some() && input.year.is_some() {
static DATA: &str = include_str!(#p); comment = "Data from the data dir".into();
let mut path = canonicalize(DATA_DIR, input.clone());
if path.is_none() {
comment = "Data from the examples".into();
path = canonicalize(EXAMPLE_DIR, input)
} }
.into(), match path {
None => quote! { Some(p) => {
static DATA: &str = ""; return quote! {
#[doc = #comment]
const #ident: &str = include_str!(#p).trim_ascii();
}
.into()
}
None => comment = "failed to get data from the paths".into(),
} }
.into(), } else {
comment = format!(
"Failed to get the year({:?}) or day({:?}) falling back to default",
input.year, input.day
);
} }
quote! {
#[doc = #comment]
const #ident: &str = "";
}
.into()
} }
/// Same as include_data!, but it only gets data from the example directory.
/// This is useful for testing the examples, even when Data from the AOC is available
#[proc_macro] #[proc_macro]
pub fn include_example(data: TokenStream) -> TokenStream { pub fn include_example(data: TokenStream) -> TokenStream {
match canonicalize(EXAMPLE_DIR, parse::<IncludeData>(data)) { let input = match parse::<IncludeData>(data) {
Some(p) => quote! { Ok(include) => include,
static DATA: &str = include_str!(#p); Err(error) => return error.into_compile_error().into(),
};
let ident = format_ident!("{}", input.var);
let mut comment: String;
if input.day.is_some() && input.year.is_some() {
comment = "Data from the Example dir".into();
match canonicalize(EXAMPLE_DIR, input.clone()) {
Some(p) => {
return quote! {
#[doc = #comment]
const #ident: &str = include_str!(#p).trim_ascii();
}
.into()
}
None => comment = "failed to get data from the path".into(),
} }
.into(), } else {
None => quote! { comment = format!(
static DATA: &str = ""; "Failed to get the year({:?}) or day({:?}) falling back to default",
} input.year, input.day
.into(), );
} }
quote! {
#[doc = #comment]
const #ident: &str = "";
}
.into()
} }

Datei anzeigen

@ -1,14 +1,13 @@
use advent_of_code::strings::{get_numbers, get_string_numbers}; use advent_of_code::strings::{get_numbers, get_string_numbers};
#[allow(unused_imports)] #[allow(unused_imports)]
use adventofcode_macros::{include_example, include_example}; use advent_of_code_macros::{include_data, include_example};
include_example!(2023 01); include_data!(DATAa 2023 01a);
//static DATA: &str; include_data!(DATAb 2023 01b);
fn main() { fn main() {
let mut sum: u32 = 0; let mut sum: u32 = 0;
let data: String = DATA.into(); for coordinates in DATAa.split('\n').map(get_numbers) {
for coordinates in data.split('\n').map(get_numbers) {
if coordinates.len() == 0 { if coordinates.len() == 0 {
continue; continue;
} }
@ -20,7 +19,7 @@ fn main() {
} }
println!("Sum of Numbers {}", sum); println!("Sum of Numbers {}", sum);
sum = 0; sum = 0;
for coordinates in data.split('\n').map(get_string_numbers) { for coordinates in DATAb.split('\n').map(get_string_numbers) {
if coordinates.len() == 0 { if coordinates.len() == 0 {
continue; continue;
} }

Datei anzeigen

@ -1,9 +1,8 @@
use advent_of_code::strings::parsenumber; use advent_of_code::strings::parsenumber;
#[allow(unused_imports)] #[allow(unused_imports)]
use adventofcode_macros::{include_example, include_example}; use advent_of_code_macros::{include_data, include_example};
include_example!(2023 02); include_example!(DATA 2023 02);
//static DATA: &str;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
struct Take { struct Take {
@ -43,17 +42,23 @@ impl Round {
ok ok
} }
fn power(&self) -> u64 { fn power(&self) -> u64 {
let mut sack = Sack{reds:0, greens:0, blues:0}; let mut sack = Sack {
reds: 0,
greens: 0,
blues: 0,
};
for take in self.takes.clone() { for take in self.takes.clone() {
if take.red > sack.reds { if take.red > sack.reds {
sack.reds = take.red sack.reds = take.red
}if take.green > sack.greens { }
if take.green > sack.greens {
sack.greens = take.green sack.greens = take.green
}if take.blue > sack.blues { }
if take.blue > sack.blues {
sack.blues = take.blue sack.blues = take.blue
} }
} }
sack.reds as u64 *sack.greens as u64*sack.blues as u64 sack.reds as u64 * sack.greens as u64 * sack.blues as u64
} }
} }

Datei anzeigen

@ -1,8 +1,8 @@
use advent_of_code::strings::{parsenumber, splitspace}; use advent_of_code::strings::{parsenumber, splitspace};
#[allow(unused_imports)] #[allow(unused_imports)]
use adventofcode_macros::{include_data, include_example}; use advent_of_code_macros::{include_data, include_example};
include_data!(2024 01); include_data!(DATA 2024 01);
fn distance(leftlist: &Vec<u32>, rightlist: &Vec<u32>) -> u32 { fn distance(leftlist: &Vec<u32>, rightlist: &Vec<u32>) -> u32 {
let mut distance = 0; let mut distance = 0;

Datei anzeigen

@ -2,9 +2,9 @@ use std::fmt::Display;
use advent_of_code::strings::parsenumber; use advent_of_code::strings::parsenumber;
#[allow(unused_imports)] #[allow(unused_imports)]
use adventofcode_macros::{include_data, include_example}; use advent_of_code_macros::{include_data, include_example};
include_data!(2024 02); include_data!(DATA 2024 02);
fn get_numbers(input: &str) -> Vec<u32> { fn get_numbers(input: &str) -> Vec<u32> {
input.split(char::is_whitespace).map(parsenumber).collect() input.split(char::is_whitespace).map(parsenumber).collect()

42
src/bin/2024/03.rs Normale Datei
Datei anzeigen

@ -0,0 +1,42 @@
use advent_of_code::strings::parsenumber;
#[allow(unused_imports)]
use advent_of_code_macros::{include_data, include_example};
use regex::{Captures, Regex};
include_data!(DATA 2024 03);
fn main() {
let part1re = Regex::new(r"mul\((?<i>\d{1,3}),(?<j>\d{1,3})\)").unwrap();
let multiplies: Vec<(u32, u32)> = part1re
.captures_iter(DATA)
.map(|capture| {
let i = capture.name("i").unwrap().as_str();
let j = capture.name("j").unwrap().as_str();
let a = parsenumber(i);
let b = parsenumber(j);
(a, b)
})
.collect();
let mut sum = 0;
for (i, j) in multiplies {
sum += i * j;
}
println!("The Cleaned output is: {}", sum);
let part2re = Regex::new(r"(mul\((?<i>\d{1,3}),(?<j>\d{1,3})\)|do\(\)|don't\(\))").unwrap();
let inputs: Vec<Captures<'_>> = part2re.captures_iter(DATA).collect();
let mut parse = true;
let mut sum = 0;
for capture in inputs {
match (capture.get(1).unwrap().as_str(), parse) {
("do()", _) => parse = true,
("don't()", _) => parse = false,
(_, true) => {
let a = parsenumber(capture.name("i").unwrap().as_str());
let b = parsenumber(capture.name("j").unwrap().as_str());
sum += a * b
}
(_, _) => {}
}
}
println!("The Cleaned with check output is: {}", sum);
}

78
src/bin/2024/04.rs Normale Datei
Datei anzeigen

@ -0,0 +1,78 @@
#[allow(unused_variables)]
use std::ops::RangeInclusive;
#[allow(unused_imports)]
use advent_of_code_macros::{include_data, include_example};
include_data!(DATA 2024 04);
#[derive(Debug, Clone)]
enum Direction {
Forward(usize, usize),
Backward(usize, usize),
}
impl Direction {
fn iter(&self) -> RangeInclusive<usize> {
let (from, to) = match self {
Direction::Forward(from, to) => (from, to),
Direction::Backward(to, from) => (from, to),
};
*from..=*to
}
}
fn main() {
let table: Vec<Vec<char>> = DATA
.split('\n')
.map(|line| line.chars().collect())
.collect();
let length = table[0].len();
let mut xmas;
let mut amount = 0;
let directions = [
Direction::Forward(0, length - 1),
Direction::Backward(0, length - 1),
];
for r in directions.clone() {
for c in directions.clone() {
println!("Horizontal: {:?}, vertical: {:?}", r.clone(), c.clone());
for row in r.iter() {
xmas = 0;
for column in c.iter() {
println!(
"Row {}, Column {}, dir {:?} {:?}",
row,
column,
r.clone(),
c.clone()
);
match (xmas, table[row][column]) {
(_x, 'X') => {
xmas = 1;
//println!("Found X, previous was {}", _x)
}
(1, 'M') => {
xmas = 2;
//println!("Found XM")
}
(2, 'A') => {
xmas = 3;
//println!("Found XMA")
}
(3, 'S') => {
xmas = 0;
amount += 1;
//println!("found XMAS in {}:{}", row, column);
}
(_x, _ch) => {
xmas = 0;
//println!("Reset, was {}({})", _x, _ch)
}
}
}
}
}
}
println!("There are {} XMAS in text", amount);
}