Do Day 2, playing around with nom v6

This commit is contained in:
2020-12-02 09:55:36 -08:00
parent e6be53686f
commit 5a495ddc17
6 changed files with 1130 additions and 10 deletions

View File

@@ -5,3 +5,4 @@ authors = ["Adam Wick <awick@uhsure.com>"]
edition = "2018"
[dependencies]
nom = "6.0.1"

1000
inputs/day2.txt Normal file

File diff suppressed because it is too large Load Diff

3
inputs/day2_test.txt Normal file
View File

@@ -0,0 +1,3 @@
1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc

View File

@@ -7,7 +7,7 @@ use std::str::FromStr;
fn real_main() -> Result<(), TopLevelError> {
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)?;
for line in contents.lines() {
match u64::from_str(line) {

97
src/bin/password_check.rs Normal file
View 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(_) => {}
}
}

View File

@@ -1,5 +1,17 @@
use nom;
use std::fmt;
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 {
IOError(io::Error),
@@ -19,14 +31,21 @@ impl fmt::Display for TopLevelError {
}
}
macro_rules! convert_error {
($type: ty, $pattern: ident) => {
impl From<$type> for TopLevelError {
fn from(x: $type) -> TopLevelError {
TopLevelError::$pattern(x)
}
}
};
convert_error!(io::Error, TopLevelError, IOError);
pub enum PasswordParseError {
StringToIntError(ParseIntError),
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);