-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday13.rs
111 lines (99 loc) · 3.09 KB
/
day13.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use crate::data::load;
use itertools::Itertools;
use ndarray::{prelude::*, Zip};
use std::{cmp, iter::zip};
use thiserror::Error;
#[derive(Error, Debug, PartialEq, Eq)]
pub enum PuzzleErr {
#[error("Input parsing error.")]
ParseInputError,
}
fn parse_grid(grid_str: &str) -> Result<Array2<bool>, PuzzleErr> {
let bools = grid_str
.trim()
.lines()
.map(|line| {
line.trim()
.chars()
.map(|c| match c {
'.' => Ok(false),
'#' => Ok(true),
_ => Err(PuzzleErr::ParseInputError),
})
.collect::<Result<Vec<_>, PuzzleErr>>()
})
.collect::<Result<Vec<_>, PuzzleErr>>()?;
let h = bools.len();
let w = bools.first().unwrap().len();
Ok(Array2::from_shape_vec((h, w), bools.concat()).unwrap())
}
fn parse_input(input: &str) -> Result<Vec<Array2<bool>>, PuzzleErr> {
input
.trim()
.split("\n\n")
.map(parse_grid)
.collect::<Result<Vec<_>, PuzzleErr>>()
}
fn hflip<T: Clone>(a: &Array2<T>) -> Array2<T> {
Array2::from_shape_vec(
a.raw_dim(),
a.axis_iter(Axis(0)).rev().map(|a| a.to_vec()).concat(),
)
.unwrap()
}
fn is_mirror_around(grid: &Array2<bool>, r: usize, with_smudge: bool) -> bool {
let max_a1 = r + 1;
let max_a2 = (grid.nrows() - 1) - r;
let m = cmp::min(max_a1, max_a2);
let a1 = grid.slice(s![(r + 1 - m)..(r + 1), ..]);
let a2 = grid.slice(s![(r + 1)..(r + 1 + m), ..]).to_owned();
if with_smudge {
Zip::from(&a1)
.and(&hflip(&a2))
.map_collect(|x, y| if x == y { 0 } else { 1 })
.sum()
== 1
} else {
a1 == hflip(&a2)
}
}
fn find_horizontal_mirror(grid: &Array2<bool>, with_smudge: bool) -> Option<usize> {
(0..(grid.nrows() - 1)).find(|&r| is_mirror_around(grid, r, with_smudge))
}
fn _solve(input: &str, with_smudge: bool) -> Result<usize, PuzzleErr> {
let grids = parse_input(input)?;
let h_results = grids
.iter()
.map(|g| find_horizontal_mirror(g, with_smudge))
.collect::<Vec<_>>();
Ok(zip(grids.iter(), h_results)
.map(|(g, h_res)| match h_res {
Some(x) => (x + 1) * 100,
None => find_horizontal_mirror(&g.t().to_owned(), with_smudge).unwrap() + 1,
})
.sum())
}
pub fn puzzle_1(input: &str) -> Result<usize, PuzzleErr> {
_solve(input, false)
}
pub fn puzzle_2(input: &str) -> Result<usize, PuzzleErr> {
_solve(input, true)
}
pub fn main(data_dir: &str) {
println!("Day 13: Point of Incidence");
let data = load(data_dir, 13, None);
// Puzzle 1.
let answer_1 = puzzle_1(&data);
match answer_1 {
Ok(x) => println!(" Puzzle 1: {}", x),
Err(e) => panic!("No solution to puzzle 1: {}.", e),
}
assert_eq!(answer_1, Ok(37113));
// Puzzle 2.
let answer_2 = puzzle_2(&data);
match answer_2 {
Ok(x) => println!(" Puzzle 2: {}", x),
Err(e) => panic!("No solution to puzzle 2: {}", e),
}
assert_eq!(answer_2, Ok(30449))
}