Compare commits

..

2 commits

Author SHA1 Message Date
Jan Christian Grünhage 726f629e30 implement day 15 2021-12-16 00:09:04 +01:00
Jan Christian Grünhage 403be5d4da implement day 14 2021-12-16 00:08:46 +01:00
7 changed files with 220 additions and 17 deletions

View file

@ -3,7 +3,7 @@ mod parsing;
use aoc_runner_derive::{aoc, aoc_generator};
use itertools::Itertools;
pub use model::{Polymer, Rule, Rules, Input};
pub use model::{Input, Polymer, Rule, Rules};
pub use parsing::parse_input as parse_input_tokens;
use yap::IntoTokens;
@ -22,7 +22,12 @@ pub fn solve(Input { polymer, rules }: &Input, iterations: usize) -> usize {
for _ in 0..iterations {
polymer.apply(rules)
}
let counts: Vec<(char, usize)> = polymer.element_counts().iter().sorted_by(|a, b| Ord::cmp(&b.1, &a.1)).map(|(element, count)| (*element, *count)).collect();
let counts: Vec<(char, usize)> = polymer
.element_counts()
.iter()
.sorted_by(|a, b| Ord::cmp(&b.1, &a.1))
.map(|(element, count)| (*element, *count))
.collect();
counts.first().unwrap().1 - counts.last().unwrap().1
}
@ -69,6 +74,6 @@ CN -> C";
#[test]
fn parse_example() {
let example = super::parse_input(EXAMPLE_INPUT);
let _example = super::parse_input(EXAMPLE_INPUT);
}
}

View file

@ -15,12 +15,13 @@ impl FromStr for Polymer {
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut map = HashMap::new();
for neighbours in s.chars().tuple_windows::<(char, char)>() {
map.entry(neighbours).and_modify(|count| *count += 1).or_insert(1);
map.entry(neighbours)
.and_modify(|count| *count += 1)
.or_insert(1);
}
let first = s.chars().next().unwrap();
let last = s.chars().last().unwrap();
Ok(Self { first, last, map })
}
}
@ -41,10 +42,12 @@ impl TryFrom<Vec<Rule>> for Rules {
if rule_vec.is_empty() {
return Err("rule set can't be empty");
}
let mut rules = Rules { map: Default::default() };
let mut rules = Rules {
map: Default::default(),
};
for rule in rule_vec {
if rules.map.contains_key(&rule.neighbours) {
return Err("ambigous rule set")
return Err("ambigous rule set");
}
rules.map.insert(rule.neighbours, rule.separator);
}
@ -57,11 +60,20 @@ impl Polymer {
let mut new_map = HashMap::new();
for (neighbours, count) in self.map.iter() {
if let Some(separator) = rules.map.get(&neighbours) {
new_map.entry((neighbours.0, *separator)).and_modify(|old_count| *old_count += count).or_insert(*count);
new_map.entry((*separator, neighbours.1)).and_modify(|old_count| *old_count += count).or_insert(*count);
if let Some(separator) = rules.map.get(neighbours) {
new_map
.entry((neighbours.0, *separator))
.and_modify(|old_count| *old_count += count)
.or_insert(*count);
new_map
.entry((*separator, neighbours.1))
.and_modify(|old_count| *old_count += count)
.or_insert(*count);
} else {
new_map.entry(*neighbours).and_modify(|old_count| *old_count += count).or_insert(*count);
new_map
.entry(*neighbours)
.and_modify(|old_count| *old_count += count)
.or_insert(*count);
}
}
self.map = new_map
@ -71,10 +83,16 @@ impl Polymer {
map.insert(self.first, 1);
map.insert(self.last, 1);
for ((left, right), count) in self.map.iter() {
map.entry(*left).and_modify(|old_count| *old_count += count).or_insert(*count);
map.entry(*right).and_modify(|old_count| *old_count += count).or_insert(*count);
map.entry(*left)
.and_modify(|old_count| *old_count += count)
.or_insert(*count);
map.entry(*right)
.and_modify(|old_count| *old_count += count)
.or_insert(*count);
}
map.iter().map(|(element, count)| (*element, count / 2)).collect()
map.iter()
.map(|(element, count)| (*element, count / 2))
.collect()
}
}

View file

@ -33,10 +33,13 @@ pub fn parse_rule(tokens: &mut impl Tokens<Item = char>) -> Option<Rule> {
let neighbours = parse_neighbours(t);
let tag = t.tokens(" -> ".chars());
let separator = parse_element(t);
if let (Some(neighbours), true, Some(separator)) = (neighbours, tag, separator) {
let neighbours = (neighbours[0], neighbours[1]);
Some(Rule { neighbours, separator })
Some(Rule {
neighbours,
separator,
})
} else {
None
}
@ -64,4 +67,3 @@ pub fn parse_rules(tokens: &mut impl Tokens<Item = char>) -> Option<Rules> {
rules.try_into().ok()
})
}

57
src/day_15/mod.rs Normal file
View file

@ -0,0 +1,57 @@
mod model;
mod parsing;
use aoc_runner_derive::{aoc, aoc_generator};
pub use model::Grid;
pub use parsing::parse_grid;
use yap::IntoTokens;
#[aoc_generator(day15)]
pub fn parse_input(input: &str) -> Grid {
let grid = parse_grid(&mut input.into_tokens()).unwrap();
Grid { grid }
}
#[aoc(day15, part1)]
pub fn part1(input: &Grid) -> usize {
input.dijkstra((0, 0), (input.grid[0].len() - 1, input.grid.len() - 1))
}
#[aoc(day15, part2)]
pub fn part2(input: &Grid) -> usize {
let input = input.grow();
input.dijkstra((0, 0), (input.grid[0].len() - 1, input.grid.len() - 1))
}
#[cfg(test)]
mod test {
const EXAMPLE_INPUT: &str = "1163751742
1381373672
2136511328
3694931569
7463417111
1319128137
1359912421
3125421639
1293138521
2311944581";
const RESULT_PART_1: usize = 40;
const RESULT_PART_2: usize = 315;
#[test]
fn part1_example() {
let result = super::part1(&super::parse_input(EXAMPLE_INPUT));
assert_eq!(result, RESULT_PART_1);
}
#[test]
fn part2_example() {
let result = super::part2(&super::parse_input(EXAMPLE_INPUT));
assert_eq!(result, RESULT_PART_2);
}
#[test]
fn parse_example() {
super::parse_input(EXAMPLE_INPUT);
}
}

103
src/day_15/model.rs Normal file
View file

@ -0,0 +1,103 @@
use std::collections::HashSet;
use itertools::Itertools;
pub struct Grid {
pub grid: Vec<Vec<usize>>,
}
impl ToString for Grid {
fn to_string(&self) -> String {
self.grid
.iter()
.map(|line| {
line.iter()
.map(|digit| digit.to_string())
.collect::<String>()
})
.join("\n")
}
}
impl Grid {
pub fn dijkstra(&self, start: (usize, usize), end: (usize, usize)) -> usize {
let mut cost = Vec::new();
let mut prev = Vec::new();
let mut dist = Vec::new();
let mut visited = HashSet::new();
let mut seen = HashSet::new();
for y in 0..self.grid.len() {
let mut cost_line = Vec::new();
let mut prev_line = Vec::new();
let mut dist_line = Vec::new();
for x in 0..self.grid[y].len() {
cost_line.push(self.grid[y][x]);
prev_line.push(None);
dist_line.push(None);
}
cost.push(cost_line);
prev.push(prev_line);
dist.push(dist_line);
}
seen.insert((0, 0));
dist[start.1][start.0] = Some(0);
loop {
let min_square = seen
.iter()
//.filter(|s| !visited.contains(*s))
.min_by(|a, b| {
Ord::cmp(
&dist[a.1][a.0].unwrap_or(usize::MAX),
&dist[b.1][b.0].unwrap_or(usize::MAX),
)
})
.cloned();
if let Some((x, y)) = min_square {
seen.remove(&(x, y));
let current = (x, y);
let current_dist = dist[current.1][current.0].unwrap();
for (x_off, y_off) in [(-1, 0), (1, 0), (0, -1), (0, 1)] {
let neighbour = ((x as isize + x_off) as usize, (y as isize + y_off) as usize);
if !(cost.len() > neighbour.1 && cost[neighbour.1].len() > neighbour.0)
|| visited.contains(&neighbour)
{
continue;
}
let neighbour_dist = dist[neighbour.1][neighbour.0].unwrap_or(usize::MAX);
let neighbour_cost = cost[neighbour.1][neighbour.0];
if neighbour_dist > current_dist + neighbour_cost {
prev[neighbour.1][neighbour.0] = Some(current);
dist[neighbour.1][neighbour.0] = Some(current_dist + neighbour_cost);
seen.insert(neighbour);
}
}
visited.insert(current);
} else {
break;
}
}
dist[end.1][end.0].unwrap()
}
pub fn grow(&self) -> Self {
let mut grid = Vec::new();
let y_max = self.grid.len();
let x_max = self.grid[0].len();
for i in 0..5 {
for y in 0..y_max {
let mut line = Vec::new();
for j in 0..5 {
for x in 0..x_max {
line.push(((self.grid[y][x] + i + j - 1) % 9) + 1)
}
}
grid.push(line);
}
}
Self { grid }
}
}

17
src/day_15/parsing.rs Normal file
View file

@ -0,0 +1,17 @@
use yap::Tokens;
use crate::parsing::{newline, parse_digit};
pub fn parse_line(tokens: &mut impl Tokens<Item = char>) -> Option<Vec<usize>> {
tokens.optional(|t| {
let vec: Vec<usize> = t.many(|t| parse_digit(t)).collect();
(!vec.is_empty()).then(|| vec)
})
}
pub fn parse_grid(tokens: &mut impl Tokens<Item = char>) -> Option<Vec<Vec<usize>>> {
tokens.optional(|t| {
let vec: Vec<Vec<usize>> = t.sep_by(|t| parse_line(t), |t| newline(t)).collect();
(!vec.is_empty()).then(|| vec)
})
}

View file

@ -16,5 +16,6 @@ pub mod day_11;
pub mod day_12;
pub mod day_13;
pub mod day_14;
pub mod day_15;
aoc_lib! { year = 2021 }