auto grab input & day 5

This commit is contained in:
Frederik Palmø 2023-05-26 11:44:02 +02:00
parent 4f15848269
commit b7a13cbc27
10 changed files with 171 additions and 50 deletions

7
.gitignore vendored
View file

@ -1,9 +1,10 @@
# temporary files
/target
/input
session.txt
# secrets
.env
# don't include inputs
/input
session.txt
# editors
.vscode

2
Cargo.lock generated
View file

@ -12,7 +12,7 @@ dependencies = [
]
[[package]]
name = "aoc-2022"
name = "aoc"
version = "0.1.0"
dependencies = [
"eyes",

View file

@ -1,5 +1,5 @@
[package]
name = "aoc-2022"
name = "aoc"
version = "0.1.0"
edition = "2021"
@ -8,6 +8,4 @@ regex = "1"
itertools = "0.10"
rayon = "1"
eyes = "1"
[build-dependencies]
reqwest = { version = "0.11", features = ["blocking", "cookies"] }

View file

@ -1,39 +0,0 @@
use reqwest::{blocking::Client, cookie::Jar};
use std::{collections::HashMap, env, fs, path::PathBuf, sync::Arc};
const BASE_URL: &str = "https://adventofcode.com";
const YEAR: &str = "2022";
fn main() {
// get env and dotenv into hashmap
let file = fs::read_to_string(".env").unwrap_or(String::new());
let env = file
.lines()
.filter_map(|line| line.split_once('='))
.map(|(key, value)| (key.to_string(), value.to_string()))
.chain(env::vars())
.collect::<HashMap<_, _>>();
// create session cookie
let session = env
.get("SESSION")
.expect("SESSION environment variable not set, retrieve it from https://adventofcode.com");
let cookie = format!("session={session}");
// setup client
let jar = Arc::new(Jar::default());
jar.add_cookie_str(&cookie, &BASE_URL.parse().unwrap());
let client = Client::builder().cookie_provider(jar).build().unwrap();
// download until day fails
for day in 1..=25 {
let path = PathBuf::from(format!("input/day{day}.txt"));
if path.try_exists().is_err() {
let url = format!("{BASE_URL}/{YEAR}/day/{day}/input");
let Ok(res) = client.get(url).send() else {
break
};
fs::write(path, res.text().unwrap()).unwrap();
}
}
}

View file

@ -1,7 +1,7 @@
use itertools::Itertools;
fn main() {
let input = std::fs::read_to_string("input/day1.txt").unwrap();
let input = aoc::input!();
println!("part 1: {}", part1(&input));
println!("part 1: {}", part2(&input));
}

View file

@ -1,7 +1,7 @@
use eyes::parse;
fn main() {
let input = std::fs::read_to_string("input/day2.txt").unwrap();
let input = aoc::input!();
println!("part 1: {}", part1(&input));
println!("part 1: {}", part2(&input));
}

View file

@ -2,7 +2,7 @@ use itertools::Itertools;
use std::collections::HashSet;
fn main() {
let input = std::fs::read_to_string("input/day3.txt").unwrap();
let input = aoc::input!();
println!("part 1: {}", part1(&input));
println!("part 1: {}", part2(&input));
}

View file

@ -1,7 +1,7 @@
use eyes::parse;
fn main() {
let input = std::fs::read_to_string("input/day4.txt").unwrap();
let input = aoc::input!();
println!("part 1: {}", part1(&input));
println!("part 1: {}", part2(&input));
}

109
src/bin/2022-5.rs Normal file
View file

@ -0,0 +1,109 @@
use eyes::parse;
use itertools::Itertools;
fn main() {
let input = aoc::input!();
println!("part 1: {}", part1(&input));
println!("part 1: {}", part2(&input));
}
fn part1(input: &str) -> String {
// parsing challenge..... yay......
let (crates, instructions) = input.split_once("\n\n").unwrap();
let mut stacks = crates
.lines()
.rev()
.skip(1)
.map(|line| {
line.chars()
.chunks(4)
.into_iter()
.map(|mut cr| (cr.next() == Some('[')).then(|| cr.next().unwrap()))
.collect::<Vec<_>>()
})
.fold(vec![vec![]; 9], |mut stacks, crates| {
for (i, c) in crates.into_iter().enumerate() {
if let Some(c) = c {
stacks[i].push(c)
}
}
stacks
});
// perform instructions
instructions
.lines()
.map(|line| parse!(line, "move {} from {} to {}", usize, usize, usize))
.for_each(|(n, from, to)| {
(0..n).for_each(|_| {
if let Some(c) = stacks[from - 1].pop() {
stacks[to - 1].push(c)
}
})
});
// get message
stacks
.into_iter()
.filter_map(|mut stack| stack.pop())
.collect::<String>()
}
fn part2(input: &str) -> String {
let (crates, instructions) = input.split_once("\n\n").unwrap();
let mut stacks = crates
.lines()
.rev()
.skip(1)
.map(|line| {
line.chars()
.chunks(4)
.into_iter()
.map(|mut cr| (cr.next() == Some('[')).then(|| cr.next().unwrap()))
.collect::<Vec<_>>()
})
.fold(vec![vec![]; 9], |mut stacks, crates| {
for (i, c) in crates.into_iter().enumerate() {
if let Some(c) = c {
stacks[i].push(c)
}
}
stacks
});
// perform instructions
instructions
.lines()
.map(|line| parse!(line, "move {} from {} to {}", usize, usize, usize))
.for_each(|(n, from, to)| {
let len = stacks[from - 1].len();
let split = stacks[from - 1].split_off(len - n);
stacks[to - 1].extend(split);
});
// get message
stacks
.into_iter()
.filter_map(|mut stack| stack.pop())
.collect::<String>()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn examples() {
let example = r#" [D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2"#;
assert_eq!(part1(example), "CMZ".to_string());
assert_eq!(part2(example), "MCD".to_string());
}
}

View file

@ -1 +1,53 @@
use reqwest::{blocking::Client, cookie::Jar};
use std::{env, error::Error, fs, path::PathBuf, sync::Arc};
const BASE_URL: &str = "https://adventofcode.com";
#[macro_export]
macro_rules! input {
() => {{
let stem = std::path::Path::new(file!())
.file_stem()
.unwrap()
.to_string_lossy();
let (year, day) = stem.split_once('-').unwrap();
$crate::get_day(year, day).unwrap()
}};
}
pub fn get_day(year: &str, day: &str) -> Result<String, Box<dyn Error>> {
let path = PathBuf::from(format!("input/{year}/day{day}.txt"));
fs::create_dir_all(path.parent().unwrap())?;
if let Ok(input) = fs::read_to_string(&path) {
Ok(input)
} else {
// get session token
let file = fs::read_to_string(".env").unwrap_or(String::new());
let session = file
.lines()
.filter_map(|line| line.split_once('='))
.map(|(key, value)| (key.to_string(), value.to_string()))
.chain(env::vars())
.find_map(|(k, v)| (k == "SESSION").then_some(v))
.ok_or(
"SESSION environment variable not set, retrieve it from https://adventofcode.com",
)?;
// create session cookie
let cookie = format!("session={session}");
// setup client
let jar = Arc::new(Jar::default());
jar.add_cookie_str(&cookie, &BASE_URL.parse()?);
let client = Client::builder().cookie_provider(jar).build()?;
// download until day fails
let url = format!("{BASE_URL}/{year}/day/{day}/input");
let text = client.get(url).send()?.text()?;
fs::create_dir_all(path.parent().unwrap())?;
fs::write(path, &text)?;
Ok(text)
}
}