2020: day02: part 1
This commit is contained in:
parent
b2214c7195
commit
e5a5c638f6
|
@ -1,9 +1,11 @@
|
||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
|
|
||||||
use aoc2020::day01;
|
use aoc2020::day01;
|
||||||
|
use aoc2020::day02;
|
||||||
|
|
||||||
fn aoc2020_all(c: &mut Criterion) {
|
fn aoc2020_all(c: &mut Criterion) {
|
||||||
c.bench_function("day01", |b| b.iter(|| day01::run().unwrap()));
|
c.bench_function("day01", |b| b.iter(|| day01::run().unwrap()));
|
||||||
|
c.bench_function("day02", |b| b.iter(|| day02::run().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group! {
|
criterion_group! {
|
||||||
|
|
1000
aoc2020/input/day02.txt
Normal file
1000
aoc2020/input/day02.txt
Normal file
File diff suppressed because it is too large
Load diff
109
aoc2020/src/day02.rs
Normal file
109
aoc2020/src/day02.rs
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
use std::fmt::Write;
|
||||||
|
use std::ops::RangeInclusive;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use aoc::{err, Result};
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../input/day02.txt");
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct PassPolicy {
|
||||||
|
repetitions: RangeInclusive<usize>,
|
||||||
|
letter: u8,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PassPolicy {
|
||||||
|
fn new(repetitions: RangeInclusive<usize>, letter: u8, password: String) -> Self {
|
||||||
|
Self {
|
||||||
|
repetitions,
|
||||||
|
letter,
|
||||||
|
password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::naive_bytecount)] // let's not pull a crate just for that
|
||||||
|
fn is_valid(&self) -> bool {
|
||||||
|
let occurrences = self
|
||||||
|
.password
|
||||||
|
.as_bytes()
|
||||||
|
.iter()
|
||||||
|
.filter(|&&b| b == self.letter)
|
||||||
|
.count();
|
||||||
|
|
||||||
|
self.repetitions.contains(&occurrences)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for PassPolicy {
|
||||||
|
type Err = aoc::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
|
let s = s.trim_end();
|
||||||
|
|
||||||
|
let space = s
|
||||||
|
.find(' ')
|
||||||
|
.ok_or_else(|| err!("couldn't parse password policy: didn't find space"))?;
|
||||||
|
let dash = s
|
||||||
|
.find('-')
|
||||||
|
.ok_or_else(|| err!("couldn't parse password policy: didn't find dash"))?;
|
||||||
|
|
||||||
|
let min_bound = s[..dash]
|
||||||
|
.parse::<usize>()
|
||||||
|
.map_err(|e| err!("couldn't parse range: {}", e))?;
|
||||||
|
let max_bound = s[(dash + 1)..space]
|
||||||
|
.parse::<usize>()
|
||||||
|
.map_err(|e| err!("couldn't parse range: {}", e))?;
|
||||||
|
|
||||||
|
let colon = s
|
||||||
|
.find(':')
|
||||||
|
.ok_or_else(|| err!("couldn't parse password policy: didn't find colon"))?;
|
||||||
|
|
||||||
|
let letter = s.as_bytes()[colon - 1];
|
||||||
|
|
||||||
|
let password = &s[(colon + 2)..];
|
||||||
|
|
||||||
|
Ok(Self::new(
|
||||||
|
min_bound..=max_bound,
|
||||||
|
letter,
|
||||||
|
password.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run() -> Result<String> {
|
||||||
|
let mut res = String::with_capacity(128);
|
||||||
|
|
||||||
|
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> Result<usize> {
|
||||||
|
let policies = input
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.parse::<PassPolicy>().map_err(|e| err!("{}", e)))
|
||||||
|
.collect::<Result<Vec<PassPolicy>>>()?;
|
||||||
|
|
||||||
|
Ok(policies.iter().filter(|policy| policy.is_valid()).count())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
static PROVIDED: &'static str = "1-3 a: abcde
|
||||||
|
1-3 b: cdefg
|
||||||
|
2-9 c: ccccccccc
|
||||||
|
";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_provided() {
|
||||||
|
assert_eq!(part1(PROVIDED).unwrap(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_real() {
|
||||||
|
assert_eq!(part1(INPUT).unwrap(), 556);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1,2 @@
|
||||||
pub mod day01;
|
pub mod day01;
|
||||||
|
pub mod day02;
|
||||||
|
|
|
@ -2,9 +2,10 @@ use aoc::DayFunc;
|
||||||
use aoc::Result;
|
use aoc::Result;
|
||||||
|
|
||||||
use aoc2020::day01;
|
use aoc2020::day01;
|
||||||
|
use aoc2020::day02;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let days: &[DayFunc] = &[day01::run];
|
let days: &[DayFunc] = &[day01::run, day02::run];
|
||||||
|
|
||||||
aoc::run(days)
|
aoc::run(days)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue