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
use crate::common::character_recognition::{recognize, CHAR_HEIGHT, CHAR_WIDTH};
use crate::input::Input;
pub fn solve(input: &mut Input) -> Result<String, String> {
const NUM_LETTERS: usize = 8;
let mut dots = Vec::new();
let parse_number = |num_str: &str| {
num_str
.parse::<u16>()
.map_err(|_| "Invalid number - not an u16")
};
for line in input.text.lines() {
if let Some((x, y)) = line.split_once(',') {
let x = parse_number(x)?;
let y = parse_number(y)?;
dots.push((x, y));
} else if let Some((prefix, coord)) = line.split_once('=') {
let coord = parse_number(coord)?;
let updater = |n: &mut u16| {
if *n > coord {
if *n > 2 * coord {
return Err("Folding would create dot with negative coordinate".to_string());
}
*n = 2 * coord - *n;
}
Ok(())
};
if prefix.ends_with('x') {
for p in dots.iter_mut() {
updater(&mut p.0)?;
}
} else if prefix.ends_with('y') {
for p in dots.iter_mut() {
updater(&mut p.1)?;
}
} else {
return Err("Invalid line not ending width x=.. or y=..".to_string());
}
if input.is_part_one() {
dots.sort_unstable();
dots.dedup();
return Ok(dots.len().to_string());
}
}
}
let mut screen = [false; NUM_LETTERS * CHAR_HEIGHT * CHAR_WIDTH];
for (x, y) in dots {
screen[usize::from(y) * NUM_LETTERS * CHAR_WIDTH + usize::from(x)] = true;
}
recognize(&screen)
}
#[test]
pub fn tests() {
use crate::input::{test_part_one, test_part_two};
let example = "6,10
0,14
9,10
0,3
10,4
4,11
6,0
6,12
4,1
0,13
10,12
3,4
3,0
8,4
1,10
2,14
8,10
9,0
fold along y=7
fold along x=5";
test_part_one!(example => "17".to_string());
let real_input = include_str!("day13_input.txt");
test_part_one!(real_input => "763".to_string());
test_part_two!(real_input => "RHALRCRA".to_string());
}