diff --git a/Makefile b/Makefile index 3cc0991..057cf6b 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -DAYS= day1 +DAYS= $(wildcard day*) .PHONY: all @@ -9,5 +9,5 @@ day%/part2: day% all: $(addsuffix /part2,$(DAYS)) clean: - for d in "$(shell find . -type d -name day\*)"; do cd $$d && $(MAKE) clean; done + for d in $(DAYS); do pushd $$d && $(MAKE) clean && popd; done diff --git a/day2/Cargo.toml b/day2/Cargo.toml new file mode 100644 index 0000000..d3c5281 --- /dev/null +++ b/day2/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "day2" +version = "0.1.0" +authors = ["Avril "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +smallmap = "1.2.0" diff --git a/day2/Makefile b/day2/Makefile new file mode 100644 index 0000000..b998fc9 --- /dev/null +++ b/day2/Makefile @@ -0,0 +1,13 @@ + + +.PHONY: all +all: target/release/day2 + +target/release/day2: + cargo build --release + ln -sf $@ part2 + strip $@ + +clean: + rm -f target/release/day2 + rm -f part2 diff --git a/day2/src/main.rs b/day2/src/main.rs new file mode 100644 index 0000000..72f96a0 --- /dev/null +++ b/day2/src/main.rs @@ -0,0 +1,39 @@ +#![feature(str_split_once)] + +use std::{ + fs, + io::{ + BufReader, + BufRead, + }, + error, +}; + +const INPUT_FILE: &str = "input"; + +mod rule; + +fn main() -> Result<(), Box> { + let input = BufReader::new(fs::OpenOptions::new() + .read(true) + .open(INPUT_FILE)?); + let mut ok=0; + let mut ok2 =0; + for line in input.lines() + { + if let Some((rule, pass)) = line?.split_once(':') + { + let rule: rule::Policy = rule.parse()?; + let pass = pass.trim(); + if rule.validate_str(pass) { + ok+=1; + } + if rule.into_v2().validate_str(pass) { + ok2+=1; + } + } + } + println!("{}", ok); + println!("{}", ok2); + Ok(()) +} diff --git a/day2/src/rule.rs b/day2/src/rule.rs new file mode 100644 index 0000000..e665eac --- /dev/null +++ b/day2/src/rule.rs @@ -0,0 +1,128 @@ +use std::{ + ops::RangeInclusive, + str, + fmt, + error, +}; +use smallmap::Map; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Policy +{ + letter: char, + rep: RangeInclusive, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct PolicyV2 +{ + letter: char, + i: usize, + j: usize, +} + +impl PolicyV2 +{ + #[inline] pub fn validate_str(&self, s: &str) -> bool + { + self.validate(s.chars().collect::>()) + } + pub fn validate(&self, vec: impl AsRef<[char]>) -> bool + { + let vec = vec.as_ref(); + if self.i>=vec.len() || self.j>=vec.len() { return false; } + + match (vec[self.i], vec[self.j]) { + (l, ll) if l == ll => false, + (x, _) | (_, x) if x == self.letter => true, + _ => false, + } + } +} + +impl Policy +{ + #[inline] pub fn into_v2(self) -> PolicyV2 + { + PolicyV2 + { + letter: self.letter, + i: (*self.rep.start())-1, + j: (*self.rep.end())-1, + } + } + + #[inline(always)] pub fn validate_str(&self, s: impl AsRef) -> bool + { + self.validate(s.as_ref().chars()) + } + + pub fn validate(&self, chars: impl IntoIterator) -> bool + { + let map: Map = { + let chars = chars.into_iter(); + let mut mp = Map::new(); + for ch in chars + { + let cnt = mp.entry(ch).or_insert(0); + *cnt += 1; + } + mp + }; + if let Some(n) = map.get(&self.letter) + { + self.rep.contains(n) + } else { + false + } + } +} + +impl fmt::Display for Policy +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "{}-{} {}", self.rep.start(), self.rep.end(), self.letter) + } +} + + +impl str::FromStr for Policy +{ + type Err = FromStrError; + + fn from_str(s: &str) -> Result + { + let mut first = s.split('-'); + let num1 = first.next().ok_or(FromStrError)?; + let (num2, letter) = { + let num2_rest = first.next().ok_or(FromStrError)?; + let mut rest = num2_rest.split(' '); + (rest.next().ok_or(FromStrError)?, rest.next().ok_or(FromStrError)?) + }; + Ok(Self{ + letter: letter.chars().next().ok_or(FromStrError)?, + rep: (num1.parse()?)..=(num2.parse()?), + }) + } +} + +#[derive(Debug)] +pub struct FromStrError; + +impl From for FromStrError +{ + #[inline] fn from(_: std::num::ParseIntError) -> Self + { + Self + } +} + +impl error::Error for FromStrError{} +impl fmt::Display for FromStrError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "failed to parse policy rule") + } +}