Completed day 12 part 1

This commit is contained in:
Tyler Hallada 2019-08-04 22:33:16 -04:00
parent 0d84ff39b8
commit e5f615cf48
4 changed files with 324 additions and 6 deletions

34
inputs/12.txt Normal file
View File

@ -0,0 +1,34 @@
initial state: ##.##.##..#..#.#.#.#...#...#####.###...#####.##..#####.#..#.##..#..#.#...#...##.##...#.##......####.
##.#. => #
#.#.. => #
##... => .
...## => #
###.# => #
#.##. => #
#.### => #
####. => #
.#..# => #
...#. => .
#..#. => .
#.#.# => .
.##.# => .
..#.. => .
.#.## => #
..##. => .
.#.#. => #
#..## => #
..#.# => #
#.... => .
..### => .
#...# => .
##### => #
###.. => #
....# => .
##.## => #
.#### => .
..... => .
##..# => #
.##.. => .
.###. => .
.#... => #

16
inputs/12_test.txt Normal file
View File

@ -0,0 +1,16 @@
initial state: #..#.#..##......###...###
...## => #
..#.. => #
.#... => #
.#.#. => #
.#.## => #
.##.. => #
.#### => #
#.#.# => #
#.### => #
##.#. => #
##.## => #
###.. => #
###.# => #
####. => #

265
src/day12.rs Normal file
View File

@ -0,0 +1,265 @@
extern crate regex;
use std::collections::{HashMap, VecDeque};
use std::error::Error;
use std::fmt;
use std::fs;
use std::result;
use std::str::FromStr;
use regex::Regex;
type Result<T> = result::Result<T, Box<Error>>;
const INPUT: &str = "inputs/12.txt";
#[derive(Debug, PartialEq)]
struct Pots(VecDeque<bool>);
#[derive(Debug, PartialEq)]
struct SpreadRules(HashMap<[bool; 5], bool>);
#[derive(Debug, PartialEq)]
struct GrowthSimulation {
pots: Pots,
spread_rules: SpreadRules,
generations: usize,
}
impl fmt::Display for Pots {
#[allow(clippy::write_with_newline)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for pot in self.0.iter() {
if *pot {
write!(f, "#")?;
} else {
write!(f, ".")?;
}
}
write!(f, "\n")?;
Ok(())
}
}
impl fmt::Display for SpreadRules {
#[allow(clippy::write_with_newline)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (pattern, result) in self.0.iter() {
for pot in pattern {
if *pot {
write!(f, "#")?;
} else {
write!(f, ".")?;
}
}
write!(f, " => ")?;
if *result {
write!(f, "#")?;
} else {
write!(f, ".")?;
}
write!(f, "\n")?;
}
write!(f, "\n")?;
Ok(())
}
}
impl fmt::Display for GrowthSimulation {
#[allow(clippy::write_with_newline)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.pots)?;
write!(f, "\n")?;
write!(f, "{}", self.spread_rules)?;
Ok(())
}
}
impl FromStr for GrowthSimulation {
type Err = Box<Error>;
fn from_str(s: &str) -> Result<GrowthSimulation> {
let sections: Vec<&str> = s.split("\n\n").collect();
let (initial_state_str, spread_rules_str) = (sections[0], sections[1]);
let mut pots = Pots(VecDeque::new());
let mut spread_rules = SpreadRules(HashMap::new());
lazy_static! {
static ref initial_state_regex: Regex =
Regex::new(r"initial state: (?P<initial_state>[#.]+)").unwrap();
static ref spread_rules_regex: Regex =
Regex::new(r"(?P<pattern>[#.]{5}) => (?P<result>[#.])").unwrap();
}
let initial_state_captures = match initial_state_regex.captures(initial_state_str) {
None => {
return Err(From::from(
"Malformed initial state, no fields could be found",
));
}
Some(captures) => captures,
};
for pot in initial_state_captures["initial_state"].chars() {
pots.0.push_back(pot == '#');
}
for rule in spread_rules_str.lines() {
let spread_rules_captures = match spread_rules_regex.captures(rule) {
None => {
return Err(From::from(
"Malformed spread rules, no fields could be found",
));
}
Some(captures) => captures,
};
let mut pattern = [false; 5];
let pattern_vec: Vec<bool> = spread_rules_captures["pattern"]
.chars()
.map(|c| c == '#')
.collect();
pattern.copy_from_slice(&pattern_vec);
let result = &spread_rules_captures["result"] == "#";
spread_rules.0.insert(pattern, result);
}
Ok(GrowthSimulation { pots, spread_rules, generations: 0 })
}
}
impl GrowthSimulation {
fn advance_generation(&mut self) {
let mut next_generation = VecDeque::new();
let padding = &[false; 4];
let pots_slice = self.pots.0.as_slices();
let pots_slice = [padding, pots_slice.0, pots_slice.1, padding].concat();
for (index, pot_window) in pots_slice.windows(5).enumerate() {
match self.spread_rules.0.get(pot_window) {
Some(result) => {
next_generation.push_back(*result);
},
None => {
next_generation.push_back(pots_slice[2]);
},
}
}
self.pots = Pots(next_generation);
self.generations += 1;
}
fn sum_plant_indices(&self) -> i32 {
let mut sum: i32 = 0;
for (index, pot) in self.pots.0.iter().enumerate() {
if *pot {
let shifted_index = index as i32 - self.generations as i32 * 2;
sum += shifted_index;
}
}
sum
}
}
fn read_initial_state_and_rules(filename: &str) -> Result<GrowthSimulation> {
let input = fs::read_to_string(filename)?;
Ok(input.parse()?)
}
pub fn solve_part1() -> Result<i32> {
let mut growth_sim = read_initial_state_and_rules(INPUT)?;
for _ in 0..20 {
growth_sim.advance_generation();
}
Ok(growth_sim.sum_plant_indices())
}
pub fn solve_part2() -> Result<i32> {
let mut growth_sim = read_initial_state_and_rules(INPUT)?;
for _ in 0..50_000_000_000_i64 {
growth_sim.advance_generation();
}
Ok(growth_sim.sum_plant_indices())
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_INPUT: &str = "inputs/12_test.txt";
fn test_growth_sim() -> GrowthSimulation {
GrowthSimulation {
pots: Pots(VecDeque::from(vec![
true, false, false, true, false, true, false, false, true, true, false, false,
false, false, false, false, true, true, true, false, false, false, true, true,
true,
])),
spread_rules: SpreadRules([
([true, true, true, true, false], true),
([true, true, false, true, true], true),
([false, false, true, false, false], true),
([false, true, false, false, false], true),
([true, true, false, true, false], true),
([false, true, true, true, true], true),
([true, false, true, true, true], true),
([true, true, true, false, true], true),
([false, true, false, true, true], true),
([true, false, true, false, true], true),
([false, true, false, true, false], true),
([false, true, true, false, false], true),
([true, true, true, false, false], true),
([false, false, false, true, true], true),
]
.iter()
.cloned()
.collect()),
generations: 0,
}
}
#[test]
fn reads_initial_state_and_rules_file() {
let growth_sim = read_initial_state_and_rules(TEST_INPUT).unwrap();
assert_eq!(growth_sim, test_growth_sim());
}
#[test]
fn displays_growth_simulation() {
assert_eq!(
format!("{}", test_growth_sim()).lines().collect::<Vec<&str>>().sort(),
vec![
"#..#.#..##......###...###",
"",
"####. => #",
"##.## => #",
"..#.. => #",
".#... => #",
"##.#. => #",
".#### => #",
"#.### => #",
"###.# => #",
".#.## => #",
"#.#.# => #",
".#.#. => #",
".##.. => #",
"###.. => #",
"...## => #",
].sort()
);
}
#[test]
fn advances_simulation_by_one_generation() {
let mut growth_sim = test_growth_sim();
growth_sim.advance_generation();
assert_eq!(format!("{}", growth_sim.pots), "..#...#....#.....#..#..#..#..\n");
}
#[test]
fn returns_correct_sum_after_20_generations() {
let mut growth_sim = test_growth_sim();
for _ in 0..20 {
growth_sim.advance_generation();
}
assert_eq!(growth_sim.sum_plant_indices(), 325);
}
}

View File

@ -14,6 +14,7 @@ mod day8;
mod day9;
mod day10;
mod day11;
mod day12;
fn main() {
// println!("Day 1:");
@ -47,10 +48,12 @@ fn main() {
// let parts = day10::solve_parts().unwrap();
// println!("{}", parts.0);
// println!("{}", parts.1);
println!("Day 11:");
let part1 = day11::solve_part1().unwrap();
println!("{},{}", part1.coord.x, part1.coord.y);
let part2 = day11::solve_part2().unwrap();
println!("{},{},{}", part2.coord.x, part2.coord.y, part2.size);
// println!("{}", parts.1);
// println!("Day 11:");
// let part1 = day11::solve_part1().unwrap();
// println!("{},{}", part1.coord.x, part1.coord.y);
// let part2 = day11::solve_part2().unwrap();
// println!("{},{},{}", part2.coord.x, part2.coord.y, part2.size);
println!("Day 12:");
println!("{}", day12::solve_part1().unwrap());
println!("{}", day12::solve_part2().unwrap());
}