Do Day 2, playing around with nom v6
This commit is contained in:
@@ -5,3 +5,4 @@ authors = ["Adam Wick <awick@uhsure.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
nom = "6.0.1"
|
||||||
|
|||||||
1000
inputs/day2.txt
Normal file
1000
inputs/day2.txt
Normal file
File diff suppressed because it is too large
Load Diff
3
inputs/day2_test.txt
Normal file
3
inputs/day2_test.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
1-3 a: abcde
|
||||||
|
1-3 b: cdefg
|
||||||
|
2-9 c: ccccccccc
|
||||||
@@ -7,7 +7,7 @@ use std::str::FromStr;
|
|||||||
fn real_main() -> Result<(), TopLevelError> {
|
fn real_main() -> Result<(), TopLevelError> {
|
||||||
let mut numbers = Vec::new();
|
let mut numbers = Vec::new();
|
||||||
|
|
||||||
for argument in env::args().skip(2) {
|
for argument in env::args().skip(1) {
|
||||||
let contents = fs::read_to_string(argument)?;
|
let contents = fs::read_to_string(argument)?;
|
||||||
for line in contents.lines() {
|
for line in contents.lines() {
|
||||||
match u64::from_str(line) {
|
match u64::from_str(line) {
|
||||||
|
|||||||
97
src/bin/password_check.rs
Normal file
97
src/bin/password_check.rs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
use advent2020::errors::{PasswordParseError, TopLevelError};
|
||||||
|
use nom::character::complete::{anychar, char, digit1, multispace1};
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
struct PasswordData {
|
||||||
|
first_number: usize,
|
||||||
|
second_number: usize,
|
||||||
|
character: char,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for PasswordData {
|
||||||
|
type Err = PasswordParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let (rest0, min_chars) = digit1(s)?;
|
||||||
|
let (rest1, _) = char('-')(rest0)?;
|
||||||
|
let (rest2, max_chars) = digit1(rest1)?;
|
||||||
|
let (rest3, _) = multispace1(rest2)?;
|
||||||
|
let (rest4, character) = anychar(rest3)?;
|
||||||
|
let (rest5, _) = char(':')(rest4)?;
|
||||||
|
let (password_chars, _) = multispace1(rest5)?;
|
||||||
|
|
||||||
|
let min_count = usize::from_str(min_chars)?;
|
||||||
|
let max_count = usize::from_str(max_chars)?;
|
||||||
|
let password = password_chars.to_string();
|
||||||
|
|
||||||
|
Ok(PasswordData {
|
||||||
|
first_number: min_count,
|
||||||
|
second_number: max_count,
|
||||||
|
character,
|
||||||
|
password,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PasswordData {
|
||||||
|
fn is_valid_interpretation1(&self) -> bool {
|
||||||
|
let count = self.password.chars().filter(|x| *x == self.character).count();
|
||||||
|
(count >= self.first_number) && (count <= self.second_number)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_valid_interpretation2(&self) -> bool {
|
||||||
|
let mut first_matches = false;
|
||||||
|
let mut second_matches = false;
|
||||||
|
|
||||||
|
for (idx, char) in self.password.char_indices() {
|
||||||
|
if (idx + 1) == self.first_number {
|
||||||
|
first_matches = char == self.character;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx + 1) == self.second_number {
|
||||||
|
second_matches = char == self.character;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
first_matches ^ second_matches
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn real_main() -> Result<(), TopLevelError> {
|
||||||
|
let mut good_items_interpretation1 = 0u64;
|
||||||
|
let mut good_items_interpretation2 = 0u64;
|
||||||
|
|
||||||
|
for argument in env::args().skip(1) {
|
||||||
|
println!("Processing {}", argument);
|
||||||
|
let contents = fs::read_to_string(argument)?;
|
||||||
|
for line in contents.lines() {
|
||||||
|
match PasswordData::from_str(line) {
|
||||||
|
Err(e) => eprintln!("Skipping line with '{}': {}", line, e),
|
||||||
|
Ok(v) => {
|
||||||
|
if v.is_valid_interpretation1() {
|
||||||
|
good_items_interpretation1 += 1;
|
||||||
|
}
|
||||||
|
if v.is_valid_interpretation2() {
|
||||||
|
good_items_interpretation2 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("# of good passwords, according to interpretation #1: {}", good_items_interpretation1);
|
||||||
|
println!("# of good passwords, according to interpretation #2: {}", good_items_interpretation2);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match real_main() {
|
||||||
|
Err(e) => eprintln!("ERROR: {}", e),
|
||||||
|
Ok(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,17 @@
|
|||||||
|
use nom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
|
||||||
|
macro_rules! convert_error {
|
||||||
|
($type: ty, $super_type: ident, $pattern: ident) => {
|
||||||
|
impl From<$type> for $super_type {
|
||||||
|
fn from(x: $type) -> $super_type {
|
||||||
|
$super_type::$pattern(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub enum TopLevelError {
|
pub enum TopLevelError {
|
||||||
IOError(io::Error),
|
IOError(io::Error),
|
||||||
@@ -19,14 +31,21 @@ impl fmt::Display for TopLevelError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! convert_error {
|
convert_error!(io::Error, TopLevelError, IOError);
|
||||||
($type: ty, $pattern: ident) => {
|
|
||||||
impl From<$type> for TopLevelError {
|
pub enum PasswordParseError {
|
||||||
fn from(x: $type) -> TopLevelError {
|
StringToIntError(ParseIntError),
|
||||||
TopLevelError::$pattern(x)
|
NomError(nom::Err<()>)
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_error!(io::Error, IOError);
|
impl fmt::Display for PasswordParseError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
PasswordParseError::NomError(e) => write!(f, "Parse error: {}", e),
|
||||||
|
PasswordParseError::StringToIntError(e) => write!(f, "Error converting string to integer: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
convert_error!(ParseIntError, PasswordParseError, StringToIntError);
|
||||||
|
convert_error!(nom::Err<()>, PasswordParseError, NomError);
|
||||||
Reference in New Issue
Block a user