From ac311a1b1cd71ee696c31f4621748f774db56208 Mon Sep 17 00:00:00 2001 From: Tyler Hallada Date: Sat, 15 Dec 2018 17:52:48 -0500 Subject: [PATCH] Day 4 WIP parsing lines --- Cargo.lock | 66 ++++++++++++ Cargo.toml | 1 + inputs/4_test.txt | 17 +++ inputs/4_test_malformed.txt | 5 + src/day4.rs | 206 ++++++++++++++++++++++++++++++++++++ src/main.rs | 1 + 6 files changed, 296 insertions(+) create mode 100644 inputs/4_test.txt create mode 100644 inputs/4_test_malformed.txt create mode 100644 src/day4.rs diff --git a/Cargo.lock b/Cargo.lock index 840fba7..dbd79ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,7 @@ name = "advent-of-code-2018" version = "0.1.0" dependencies = [ + "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -18,6 +19,16 @@ name = "cfg-if" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.2.0" @@ -38,6 +49,24 @@ dependencies = [ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-integer" +version = "0.1.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_syscall" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "regex" version = "1.1.0" @@ -66,6 +95,16 @@ dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "time" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ucd-util" version = "0.1.3" @@ -81,15 +120,42 @@ name = "version_check" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74" "checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9" +"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" +"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" +"checksum redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a84bcd297b87a545980a2d25a0beb72a1f490c31f0a9fde52fca35bfbb1ceb70" "checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" "checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "847da467bf0db05882a9e2375934a8a55cffdc9db0d128af1518200260ba1f6c" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 2636da2..93114f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,5 @@ authors = ["Tyler Hallada "] edition = "2018" [dependencies] +chrono = "0.4" regex = "1" diff --git a/inputs/4_test.txt b/inputs/4_test.txt new file mode 100644 index 0000000..496d314 --- /dev/null +++ b/inputs/4_test.txt @@ -0,0 +1,17 @@ +[1518-11-01 00:00] Guard #10 begins shift +[1518-11-01 00:05] falls asleep +[1518-11-01 00:25] wakes up +[1518-11-01 00:30] falls asleep +[1518-11-01 00:55] wakes up +[1518-11-01 23:58] Guard #99 begins shift +[1518-11-02 00:40] falls asleep +[1518-11-02 00:50] wakes up +[1518-11-03 00:05] Guard #10 begins shift +[1518-11-03 00:24] falls asleep +[1518-11-03 00:29] wakes up +[1518-11-04 00:02] Guard #99 begins shift +[1518-11-04 00:36] falls asleep +[1518-11-04 00:46] wakes up +[1518-11-05 00:03] Guard #99 begins shift +[1518-11-05 00:45] falls asleep +[1518-11-05 00:55] wakes up diff --git a/inputs/4_test_malformed.txt b/inputs/4_test_malformed.txt new file mode 100644 index 0000000..0213531 --- /dev/null +++ b/inputs/4_test_malformed.txt @@ -0,0 +1,5 @@ +[1518-11-01 00:00] Guard #10 begins shift +[1518-11-01 00:05] falls asleep +[1518-11-01 00:25] wakes up +[1518-11-01 00:30] falls asleep +[1518-11-01 00:55] dies diff --git a/src/day4.rs b/src/day4.rs new file mode 100644 index 0000000..9703290 --- /dev/null +++ b/src/day4.rs @@ -0,0 +1,206 @@ +extern crate chrono; +extern crate regex; + +use std::error::Error; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::fmt; +use std::collections::{HashMap, HashSet}; +use std::iter::FromIterator; + +use chrono::prelude::*; +use regex::{Regex, Captures}; + +const INPUT: &str = "inputs/4.txt"; + +#[derive(Debug, PartialEq)] +enum Record { + Start { + time: NaiveDateTime, + guard_id: u32, + }, + Sleep { + time: NaiveDateTime, + }, + Wake { + time: NaiveDateTime, + }, +} + +#[derive(Debug, Clone, PartialEq)] +struct MalformedRecord { + details: String +} + +impl MalformedRecord { + fn new(msg: &str) -> MalformedRecord { + MalformedRecord{ details: msg.to_string() } + } +} + +impl fmt::Display for MalformedRecord { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.details) + } +} + +impl Error for MalformedRecord { + fn description(&self) -> &str { + &self.details + } +} + +fn read_records(filename: &str) -> Result, Box> { + let mut records: Vec = Vec::new(); + let record_regex = + Regex::new(r"\[(?P\d{4}-\d{2}-\d{2}\s\d{2}:\d{2})\]\s(?:(?PGuard #(?P\d+) begins shift)|(?Pfalls asleep)|(?Pwakes up))")?; + let file = File::open(filename)?; + for line in BufReader::new(file).lines() { + match record_regex.captures(&line?) { + Some(captures) => { + println!("{:?}", NaiveDateTime::parse_from_str( + &get_captured_field(&captures, "timestamp")?, + "%Y-%m-%d %H:%M")?); + if has_captured_field(&captures, "start")? { + records.push(Record::Start { + time: NaiveDateTime::parse_from_str( + &get_captured_field(&captures, "timestamp")?, + "%Y-%m-%d %H:%M")?, + guard_id: get_captured_field(&captures, "guard_id")?.parse()?, + }); + } else if has_captured_field(&captures, "sleep")? { + records.push(Record::Sleep { + time: NaiveDateTime::parse_from_str( + &get_captured_field(&captures, "timestamp")?, + "%Y-%m-%d %H:%M")?, + }); + } else { + records.push(Record::Wake { + time: NaiveDateTime::parse_from_str( + &get_captured_field(&captures, "timestamp")?, + "%Y-%m-%d %H:%M")?, + }); + } + }, + None => return Err(Box::new(MalformedRecord { + details: "Malformed record line, no fields could be found".to_string() + })), + }; + } + Ok(records) +} + +fn get_captured_field(captures: &Captures, field: &str) -> Result> { + match captures.name(field) { + Some(capture) => Ok(String::from(capture.as_str())), + None => return Err(Box::new(MalformedRecord { + details: format!("Malformed record line, field {} could not be found", field) + })) + } +} + +fn has_captured_field(captures: &Captures, field: &str) -> Result> { + match captures.name(field) { + Some(_) => Ok(true), + None => Ok(false) + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + const TEST_INPUT: &str = "inputs/4_test.txt"; + const TEST_INPUT_MALFORMED: &str = "inputs/4_test_malformed.txt"; + + #[test] + fn reads_records_file() { + assert_eq!(read_records(TEST_INPUT).unwrap(), vec![ + Record::Start { + time: NaiveDateTime::parse_from_str( + "1518-11-01 00:00", "%Y-%m-%d %H:%M").unwrap(), + guard_id: 10, + }, + Record::Sleep { + time: NaiveDateTime::parse_from_str( + "1518-11-01 00:05", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Wake { + time: NaiveDateTime::parse_from_str( + "1518-11-01 00:25", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Sleep { + time: NaiveDateTime::parse_from_str( + "1518-11-01 00:30", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Wake { + time: NaiveDateTime::parse_from_str( + "1518-11-01 00:55", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Start { + time: NaiveDateTime::parse_from_str( + "1518-11-01 23:58", "%Y-%m-%d %H:%M").unwrap(), + guard_id: 99, + }, + Record::Sleep { + time: NaiveDateTime::parse_from_str( + "1518-11-02 00:40", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Wake { + time: NaiveDateTime::parse_from_str( + "1518-11-02 00:50", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Start { + time: NaiveDateTime::parse_from_str( + "1518-11-03 00:05", "%Y-%m-%d %H:%M").unwrap(), + guard_id: 10, + }, + Record::Sleep { + time: NaiveDateTime::parse_from_str( + "1518-11-03 00:24", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Wake { + time: NaiveDateTime::parse_from_str( + "1518-11-03 00:29", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Start { + time: NaiveDateTime::parse_from_str( + "1518-11-04 00:02", "%Y-%m-%d %H:%M").unwrap(), + guard_id: 99, + }, + Record::Sleep { + time: NaiveDateTime::parse_from_str( + "1518-11-04 00:36", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Wake { + time: NaiveDateTime::parse_from_str( + "1518-11-04 00:46", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Start { + time: NaiveDateTime::parse_from_str( + "1518-11-05 00:03", "%Y-%m-%d %H:%M").unwrap(), + guard_id: 99, + }, + Record::Sleep { + time: NaiveDateTime::parse_from_str( + "1518-11-05 00:45", "%Y-%m-%d %H:%M").unwrap(), + }, + Record::Wake { + time: NaiveDateTime::parse_from_str( + "1518-11-05 00:55", "%Y-%m-%d %H:%M").unwrap(), + }, + ]); + } + + #[test] + fn errors_on_malformed_records_file() { + match read_records(TEST_INPUT_MALFORMED) { + Ok(_) => assert!(false, "read_records should have returned an error"), + Err(err) => assert_eq!( + (*err).description(), + "Malformed record line, no fields could be found".to_string(), + ), + } + } +} diff --git a/src/main.rs b/src/main.rs index 59d32e7..2b0cea0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod day1; mod day2; mod day3; +mod day4; fn main() { println!("Day 1:");