Complete Day 6

main
Wes Holland 1 year ago
parent 4e26cd97ec
commit b8e82c25be

@ -1,6 +1,6 @@
mod input_tools;
use std::cmp::Ordering;
mod input_tools;
use input_tools::*;
mod lexer;

@ -0,0 +1 @@
/target

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "day6"
version = "0.1.0"

@ -0,0 +1,6 @@
[package]
name = "day6"
version = "0.1.0"
edition = "2021"
[dependencies]

@ -0,0 +1,2 @@
Time: 7 15 30
Distance: 9 40 200

@ -0,0 +1,2 @@
Time: 40 70 98 79
Distance: 215 1051 2147 1005

@ -0,0 +1,59 @@
use std::io::{Lines, StdinLock};
/// A simple, but panic-y reader for stdin
pub fn simple_stdin() -> SimpleStdinLines {
SimpleStdinLines::new()
}
pub struct SimpleStdinLines {
pub inner: Lines<StdinLock<'static>>,
}
impl SimpleStdinLines {
pub fn new() -> Self {
Self { inner: std::io::stdin().lines() }
}
}
impl Iterator for SimpleStdinLines {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().transpose().unwrap()
}
}
/// A simple, but panic-y parser of arguments
pub fn simple_args() -> SimpleArgs {
SimpleArgs::init()
}
pub struct SimpleArgs {
args: Vec<String>,
}
impl SimpleArgs {
pub fn init() -> Self {
Self { args: std::env::args().collect() }
}
pub fn get_flag(&self, name: &str) -> bool {
self.args.iter().any(|x| x == name)
}
pub fn get_value(&self, name: &str, default: &str) -> String {
let pos = self.args.iter().position(|x| x == name);
if let Some(idx) = pos {
if let Some(s) = self.args.iter().nth(idx + 1) {
s.clone()
}
else {
String::from(default)
}
}
else {
String::from(default)
}
}
}

@ -0,0 +1,95 @@
const RADIX: u32 = 10;
#[derive(Clone, Debug)]
pub enum Token {
Integer(u32),
Special(char),
Keyword(String),
}
pub fn tokenize_line(input: &str) -> Vec<Token> {
let mut vals = vec![];
let mut idx = 0;
while idx < input.len() {
let c = input.chars().nth(idx).unwrap();
if c.is_digit(RADIX) {
let end = match input.chars().skip(idx)
.position(|x| !x.is_digit(RADIX)) {
Some(pos) => idx + pos,
None => input.len(),
};
let substr = &input[idx..end];
let v = u32::from_str_radix(&substr, RADIX).unwrap();
vals.push(Token::Integer(v));
idx = end;
}
else if is_special_char(c) {
vals.push(Token::Special(c));
idx = idx + 1;
}
else if is_keyword_char(c) {
let end = match input.chars().skip(idx)
.position(|x| !is_keyword_char(x)) {
Some(pos) => idx + pos,
None => input.len(),
};
vals.push(Token::Keyword(String::from(&input[idx..end])));
idx = end;
}
else {
idx = idx + 1;
}
}
vals
}
fn is_special_char(c: char) -> bool {
match c {
':' => true,
'|' => true,
'*' => true,
'.' => true,
'-' => true,
_ => false
}
}
fn is_keyword_char(c: char) -> bool {
match c {
'a'..='z'|'A'..='Z' => true,
_ => false
}
}
pub fn expect_int<'a>(iter: &mut impl Iterator<Item = &'a Token>) -> Option<u32> {
if let Some(Token::Integer(i)) = iter.next() {
Some(*i)
}
else {
None
}
}
pub fn expect_keyword<'a>(iter: &mut impl Iterator<Item = &'a Token>) -> Option<String> {
if let Some(Token::Keyword(k)) = iter.next() {
Some(k.clone())
}
else {
None
}
}
pub fn expect_special<'a>(iter: &mut impl Iterator<Item = &'a Token>) -> Option<char> {
if let Some(Token::Special(c)) = iter.next() {
Some(*c)
}
else {
None
}
}

@ -0,0 +1,99 @@
mod input_tools;
mod lexer;
use lexer::*;
use input_tools::*;
fn quadradic_eq(a: f64, b: f64, c: f64) -> (f64, f64) {
let term1 = -b / (2.0*a);
let term2 = b*b - 4.0*a*c;
let term3 = f64::sqrt(term2) / (2.0*a);
let sol1 = term1 - term3;
let sol2 = term1 + term3;
let left = f64::min(sol1, sol2);
let right = f64::max(sol1, sol2);
println!("Quad {}, {}, {} : {} {} {} -> ({}, {})", a, b, c, term1, term2, term3, left, right);
(f64::min(sol1, sol2), f64::max(sol1, sol2))
}
fn puzzle1(verbose: bool) {
println!("Part 1");
let mut stdin = simple_stdin();
let times = stdin.next().unwrap();
let distances = stdin.next().unwrap();
let time_toks = tokenize_line(&times);
let distance_toks = tokenize_line(&distances);
let num_extract = |x: &Token| match *x {
Token::Integer(i) => i as f64,
_ => panic!("Bad token")
};
let times: Vec<f64> = time_toks.iter().skip(2).map(num_extract).collect();
let distances: Vec<f64> = distance_toks.iter().skip(2).map(num_extract).collect();
let mut win_counts = vec![];
for idx in 0..times.len() {
let t = times[idx];
let d = distances[idx];
let (left, right) = quadradic_eq(-1.0, t, -d);
let discrete_left = f64::ceil(left + 0.01) as u32;
let discrete_right = f64::ceil(right) as u32;
win_counts.push(discrete_right - discrete_left);
}
if verbose {
println!("{:?}", times);
println!("{:?}", distances);
println!("{:?}", win_counts);
}
let products = win_counts.iter().fold(1, |acc, x| acc * x);
println!("Products: {}", products);
}
fn puzzle2(verbose: bool) {
println!("Part 2");
let mut stdin = simple_stdin();
let times = stdin.next().unwrap();
let distances = stdin.next().unwrap();
let race_time_str: String = times.chars().filter(|c| c.is_digit(10)).collect();
let distance_str: String = distances.chars().filter(|c| c.is_digit(10)).collect();
let race_time = u64::from_str_radix(&race_time_str, 10).unwrap() ;
let race_distance = u64::from_str_radix(&distance_str, 10).unwrap() as f64;
if verbose {
println!("Time: {}", race_time);
println!("Distance {}", race_distance);
}
let (left, right) = quadradic_eq(-1.0, race_time as f64, (-race_distance) as f64);
let discrete_left = f64::ceil(left + 0.01) as u32;
let discrete_right = f64::ceil(right) as u32;
let win_counts = discrete_right - discrete_left;
println!("Product: {}", win_counts);
}
fn main() {
let args = simple_args();
let verbose = args.get_flag("-v");
let part = args.get_value("-p", "1");
match part.as_str() {
"1" => puzzle1(verbose),
"2" => puzzle2(verbose),
_ => println!("Nothing to do")
}
}
Loading…
Cancel
Save

Powered by TurnKey Linux.