Add login checks and example solving

This commit is contained in:
Tyler Beckman 2023-12-05 00:03:50 -07:00
parent 7bbd5ff22c
commit 161b341400
Signed by: Ty
GPG key ID: 2813440C772555A4
3 changed files with 67 additions and 57 deletions

View file

@ -28,21 +28,18 @@ impl Day for Day5 {
.map(|(name, list)| { .map(|(name, list)| {
( (
name.split_once(' ').unwrap().0.split_once("-to-").unwrap(), name.split_once(' ').unwrap().0.split_once("-to-").unwrap(),
list.into_iter().map(|line| { list.into_iter()
let nums = line.split_whitespace() .map(|line| {
let nums = line
.split_whitespace()
.map(|n| n.parse::<usize>().unwrap()) .map(|n| n.parse::<usize>().unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
(nums[0], nums[1], nums[2]) (nums[0], nums[1], nums[2])
}).collect::<Vec<_>>(), })
.collect::<Vec<_>>(),
) )
}) })
.map(|((from, to), mappings)| ( .map(|((from, to), mappings)| (from, (to, mappings)))
from,
(
to,
mappings
)
))
.collect::<HashMap<&str, (&str, Vec<(usize, usize, usize)>)>>(); .collect::<HashMap<&str, (&str, Vec<(usize, usize, usize)>)>>();
let mut locations = Vec::<usize>::new(); let mut locations = Vec::<usize>::new();
@ -90,29 +87,24 @@ impl Day for Day5 {
.split_whitespace() .split_whitespace()
.map(|s| s.parse::<usize>().unwrap()) .map(|s| s.parse::<usize>().unwrap())
.collect::<Vec<usize>>(); .collect::<Vec<usize>>();
let seeds = seeds let seeds = seeds.as_slice().chunks(2);
.as_slice()
.chunks(2);
let groups = groups let groups = groups
.map(|(name, list)| { .map(|(name, list)| {
( (
name.split_once(' ').unwrap().0.split_once("-to-").unwrap(), name.split_once(' ').unwrap().0.split_once("-to-").unwrap(),
list.into_iter().map(|line| { list.into_iter()
let nums = line.split_whitespace() .map(|line| {
let nums = line
.split_whitespace()
.map(|n| n.parse::<usize>().unwrap()) .map(|n| n.parse::<usize>().unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
(nums[0], nums[1], nums[2]) (nums[0], nums[1], nums[2])
}).collect::<Vec<_>>(), })
.collect::<Vec<_>>(),
) )
}) })
.map(|((from, to), mappings)| ( .map(|((from, to), mappings)| (from, (to, mappings)))
from,
(
to,
mappings
)
))
.collect::<HashMap<&str, (&str, Vec<(usize, usize, usize)>)>>(); .collect::<HashMap<&str, (&str, Vec<(usize, usize, usize)>)>>();
let mut location = 100000000usize; let mut location = 100000000usize;
@ -122,7 +114,14 @@ impl Day for Day5 {
let (initial, range) = (chunk[0], chunk[1]); let (initial, range) = (chunk[0], chunk[1]);
for (j, seed) in (initial..(initial + range)).enumerate() { for (j, seed) in (initial..(initial + range)).enumerate() {
if j % 1000 == 0 { if j % 1000 == 0 {
println!("Chunk {}/{}, Seed {}/{} ({:.2}%)", i, seedslen, j, range, j as f64 / range as f64 * 100.0); println!(
"Chunk {}/{}, Seed {}/{} ({:.2}%)",
i,
seedslen,
j,
range,
j as f64 / range as f64 * 100.0
);
} }
let (mut category, mut value) = ("seed", seed); let (mut category, mut value) = ("seed", seed);
while category != "location" { while category != "location" {
@ -138,7 +137,9 @@ impl Day for Day5 {
} }
} }
if location > value { location = value } if location > value {
location = value
}
} }
} }
@ -146,7 +147,6 @@ impl Day for Day5 {
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{day5::Day5, utils::Day}; use crate::{day5::Day5, utils::Day};
@ -186,7 +186,8 @@ temperature-to-humidity map:
humidity-to-location map: humidity-to-location map:
60 56 37 60 56 37
56 93 4"#.to_string(), 56 93 4"#
.to_string(),
} }
.solve(1)); .solve(1));
} }
@ -226,7 +227,8 @@ temperature-to-humidity map:
humidity-to-location map: humidity-to-location map:
60 56 37 60 56 37
56 93 4"#.to_string(), 56 93 4"#
.to_string(),
} }
.solve(2)); .solve(2));
} }

View file

@ -1,7 +1,7 @@
use scraper::{Html, Selector}; use scraper::{Html, Selector};
pub async fn fetch_input(auth: String, day: u8) -> String { pub async fn fetch_input(auth: String, day: u8) -> String {
reqwest::Client::new() let input = reqwest::Client::new()
.get(format!("https://adventofcode.com/2023/day/{day}/input")) .get(format!("https://adventofcode.com/2023/day/{day}/input"))
.header("Cookie", format!("session={auth}")) .header("Cookie", format!("session={auth}"))
.send() .send()
@ -11,7 +11,12 @@ pub async fn fetch_input(auth: String, day: u8) -> String {
.await .await
.expect("Unable to parse string from input response") .expect("Unable to parse string from input response")
.trim_end() .trim_end()
.to_owned() .to_owned();
if input != "Puzzle inputs differ by user. Please log in to get your puzzle input." {
input
} else {
panic!("Invalid auth")
}
} }
pub async fn fetch_example(auth: String, day: u8, part: u8) -> (String, String) { pub async fn fetch_example(auth: String, day: u8, part: u8) -> (String, String) {
@ -44,7 +49,7 @@ pub async fn fetch_example(auth: String, day: u8, part: u8) -> (String, String)
let solution = dom let solution = dom
.select(&solution_selector) .select(&solution_selector)
.last() .last()
.unwrap() .expect("Unable to find example solution for part, is auth correct?")
.inner_html() .inner_html()
.trim_end() .trim_end()
.to_string(); .to_string();

View file

@ -35,6 +35,9 @@ enum Subcommands {
day: u8, day: u8,
/// The part to solve for /// The part to solve for
part: u8, part: u8,
/// If used, then the example input will be solved and checked rather than the real one
#[arg(short, long)]
example: bool,
}, },
/// Runs solution N amount of times, averaging speed /// Runs solution N amount of times, averaging speed
Benchmark { Benchmark {
@ -67,32 +70,28 @@ async fn main() {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
match cli.subcommand { match cli.subcommand {
Subcommands::Solve { day, part } => { Subcommands::Solve { day, part, example } => {
let response = client let (input, solution) = match example {
.get(format!("https://adventofcode.com/2023/day/{day}/input")) false => (fetcher::fetch_input(cli.auth, day).await, None),
.header("Cookie", format!("session={auth}", auth = cli.auth)) true => {
.send() let example = fetcher::fetch_example(cli.auth, day, part).await;
.await (example.0, Some(example.1))
.unwrap() }
.text() };
.await
.unwrap()
.trim_end()
.to_owned();
let mut day: Box<dyn Day> = match day { let mut day: Box<dyn Day> = match day {
1 => Box::new(Day1 { input: response }), 1 => Box::new(Day1 { input }),
2 => Box::new(Day2 { 2 => Box::new(Day2 {
input: response, input,
games: vec![], games: vec![],
}), }),
3 => Box::new(Day3 { input: response }), 3 => Box::new(Day3 { input }),
4 => Box::new(Day4 { 4 => Box::new(Day4 {
input: response, input,
acc: 0usize, acc: 0usize,
cards: HashMap::new(), cards: HashMap::new(),
}), }),
5 => Box::new(Day5 { input: response }), 5 => Box::new(Day5 { input }),
_ => panic!("Invalid day #"), _ => panic!("Invalid day #"),
}; };
let start = std::time::Instant::now(); let start = std::time::Instant::now();
@ -100,6 +99,10 @@ async fn main() {
let end = std::time::Instant::now(); let end = std::time::Instant::now();
println!("Solution: {result}"); println!("Solution: {result}");
if let Some(solution) = solution {
println!("Correct solution: {solution}")
}
let timing = (end - start).as_nanos(); let timing = (end - start).as_nanos();
let (timing, timing_units) = if timing >= 1000000000 { let (timing, timing_units) = if timing >= 1000000000 {
(timing as f64 / 1000000000.0, "s") (timing as f64 / 1000000000.0, "s")