diff --git a/inputs/7.txt b/inputs/7.txt new file mode 100755 index 0000000..157eeb5 --- /dev/null +++ b/inputs/7.txt @@ -0,0 +1,101 @@ +Step I must be finished before step Q can begin. +Step B must be finished before step O can begin. +Step J must be finished before step M can begin. +Step W must be finished before step Y can begin. +Step U must be finished before step X can begin. +Step T must be finished before step Q can begin. +Step G must be finished before step M can begin. +Step K must be finished before step C can begin. +Step F must be finished before step Z can begin. +Step D must be finished before step A can begin. +Step N must be finished before step Y can begin. +Step Y must be finished before step Q can begin. +Step Q must be finished before step Z can begin. +Step V must be finished before step E can begin. +Step A must be finished before step X can begin. +Step E must be finished before step C can begin. +Step O must be finished before step R can begin. +Step P must be finished before step L can begin. +Step H must be finished before step R can begin. +Step M must be finished before step R can begin. +Step C must be finished before step Z can begin. +Step R must be finished before step L can begin. +Step L must be finished before step S can begin. +Step S must be finished before step X can begin. +Step Z must be finished before step X can begin. +Step T must be finished before step O can begin. +Step D must be finished before step Z can begin. +Step P must be finished before step R can begin. +Step M must be finished before step Z can begin. +Step L must be finished before step Z can begin. +Step W must be finished before step N can begin. +Step Q must be finished before step R can begin. +Step P must be finished before step C can begin. +Step U must be finished before step O can begin. +Step F must be finished before step O can begin. +Step K must be finished before step X can begin. +Step G must be finished before step K can begin. +Step M must be finished before step C can begin. +Step Y must be finished before step Z can begin. +Step A must be finished before step O can begin. +Step D must be finished before step P can begin. +Step K must be finished before step S can begin. +Step I must be finished before step E can begin. +Step G must be finished before step F can begin. +Step S must be finished before step Z can begin. +Step N must be finished before step V can begin. +Step F must be finished before step D can begin. +Step A must be finished before step Z can begin. +Step F must be finished before step X can begin. +Step T must be finished before step Y can begin. +Step W must be finished before step H can begin. +Step D must be finished before step H can begin. +Step W must be finished before step G can begin. +Step J must be finished before step X can begin. +Step T must be finished before step X can begin. +Step U must be finished before step R can begin. +Step O must be finished before step P can begin. +Step L must be finished before step X can begin. +Step I must be finished before step B can begin. +Step M must be finished before step L can begin. +Step C must be finished before step R can begin. +Step R must be finished before step X can begin. +Step F must be finished before step N can begin. +Step V must be finished before step H can begin. +Step K must be finished before step A can begin. +Step W must be finished before step O can begin. +Step U must be finished before step Q can begin. +Step O must be finished before step C can begin. +Step K must be finished before step V can begin. +Step R must be finished before step S can begin. +Step E must be finished before step S can begin. +Step J must be finished before step A can begin. +Step E must be finished before step X can begin. +Step K must be finished before step Y can begin. +Step Y must be finished before step X can begin. +Step P must be finished before step Z can begin. +Step W must be finished before step X can begin. +Step Y must be finished before step A can begin. +Step V must be finished before step X can begin. +Step O must be finished before step M can begin. +Step I must be finished before step J can begin. +Step W must be finished before step L can begin. +Step I must be finished before step G can begin. +Step D must be finished before step O can begin. +Step D must be finished before step N can begin. +Step M must be finished before step X can begin. +Step I must be finished before step R can begin. +Step Y must be finished before step M can begin. +Step F must be finished before step M can begin. +Step U must be finished before step M can begin. +Step Y must be finished before step H can begin. +Step K must be finished before step D can begin. +Step N must be finished before step O can begin. +Step H must be finished before step S can begin. +Step G must be finished before step L can begin. +Step T must be finished before step D can begin. +Step J must be finished before step N can begin. +Step K must be finished before step M can begin. +Step K must be finished before step P can begin. +Step E must be finished before step R can begin. +Step N must be finished before step H can begin. diff --git a/inputs/7_test.txt b/inputs/7_test.txt new file mode 100644 index 0000000..9ab25bf --- /dev/null +++ b/inputs/7_test.txt @@ -0,0 +1,7 @@ +Step C must be finished before step A can begin. +Step C must be finished before step F can begin. +Step A must be finished before step B can begin. +Step A must be finished before step D can begin. +Step B must be finished before step E can begin. +Step D must be finished before step E can begin. +Step F must be finished before step E can begin. diff --git a/src/day7.rs b/src/day7.rs new file mode 100644 index 0000000..9750400 --- /dev/null +++ b/src/day7.rs @@ -0,0 +1,132 @@ +extern crate regex; + +use std::error::Error; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::fmt; +use std::collections::HashMap; + +use regex::{Regex, Captures}; + +const INPUT: &str = "inputs/7.txt"; + +#[derive(Debug, Clone, PartialEq)] +struct MalformedInstruction { + details: String +} + +impl MalformedInstruction { + fn new(msg: &str) -> MalformedInstruction { + MalformedInstruction{ details: msg.to_string() } + } +} + +impl fmt::Display for MalformedInstruction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.details) + } +} + +impl Error for MalformedInstruction { + fn description(&self) -> &str { + &self.details + } +} + +pub fn solve_part1() -> Result> { + let mut instructions = read_instructions(INPUT)?; + Ok(get_step_sequence(&mut instructions)) +} + +fn read_instructions(filename: &str) -> Result>, Box> { + let mut instructions: HashMap> = HashMap::new(); + lazy_static! { + static ref INSTRUCTION_REGEX: Regex = Regex::new( + r"Step (?P\w) must be finished before step (?P\w) can begin." + ).unwrap(); + } + let file = File::open(filename)?; + for (index, line) in BufReader::new(file).lines().enumerate() { + match INSTRUCTION_REGEX.captures(&line?) { + Some(captures) => { + let step = get_captured_field(&captures, "step")?.parse()?; + let dependency: String = get_captured_field(&captures, "dependency")?.parse()?; + instructions.entry(dependency.clone()).or_insert(Vec::new()); + let dependencies = instructions.entry(step).or_insert(Vec::new()); + dependencies.push(dependency); + }, + None => return Err(Box::new(MalformedInstruction { + details: "Malformed instruction line, no fields could be found".to_string() + })), + }; + } + Ok(instructions) +} + +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(MalformedInstruction { + details: format!("Malformed instruction line, field {} could not be found", field) + })) + } +} + +fn get_step_sequence(instructions: &mut HashMap>) -> String { + let mut sequence: Vec = Vec::new(); + loop { + let mut available: Vec = instructions + .iter() + .filter(|(_, dependencies)| dependencies.len() == 0) + .map(|(step, _)| step.clone()) + .collect(); + if available.len() == 0 { break; } + available.sort(); + available.reverse(); + let next = available.pop().unwrap(); + instructions.remove(&next); + for dependencies in instructions.values_mut() { + match dependencies.iter().position(|d| *d == next) { + Some(index) => { dependencies.remove(index); }, + None => () + } + } + sequence.push(next); + } + sequence.join("") +} + +#[cfg(test)] +mod tests { + use super::*; + + const TEST_INPUT: &str = "inputs/7_test.txt"; + + #[test] + fn reads_instructions_file() { + let expected: HashMap> = [ + ("A".to_string(), vec!["C".to_string()]), + ("F".to_string(), vec!["C".to_string()]), + ("C".to_string(), vec![]), + ("B".to_string(), vec!["A".to_string()]), + ("D".to_string(), vec!["A".to_string()]), + ("E".to_string(), vec!["B".to_string(), "D".to_string(), "F".to_string()]), + + ].iter().cloned().collect(); + assert_eq!(read_instructions(TEST_INPUT).unwrap(), expected); + } + + #[test] + fn gets_step_sequence() { + let mut instructions: HashMap> = [ + ("A".to_string(), vec!["C".to_string()]), + ("F".to_string(), vec!["C".to_string()]), + ("C".to_string(), vec![]), + ("B".to_string(), vec!["A".to_string()]), + ("D".to_string(), vec!["A".to_string()]), + ("E".to_string(), vec!["B".to_string(), "D".to_string(), "F".to_string()]), + + ].iter().cloned().collect(); + assert_eq!(get_step_sequence(&mut instructions), "CABDFE"); + } +} diff --git a/src/main.rs b/src/main.rs index 7af8cb4..63a32d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod day3; mod day4; mod day5; mod day6; +mod day7; fn main() { // println!("Day 1:"); @@ -24,7 +25,9 @@ fn main() { // println!("Day 5:"); // println!("{}", day5::solve_part1().unwrap()); // println!("{}", day5::solve_part2().unwrap()); - println!("Day 6:"); - println!("{}", day6::solve_part1().unwrap()); - println!("{}", day6::solve_part2().unwrap()); + // println!("Day 6:"); + // println!("{}", day6::solve_part1().unwrap()); + // println!("{}", day6::solve_part2().unwrap()); + println!("Day 7:"); + println!("{}", day7::solve_part1().unwrap()); }