-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathday22.rs
More file actions
117 lines (99 loc) · 3.18 KB
/
day22.rs
File metadata and controls
117 lines (99 loc) · 3.18 KB
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
112
113
114
115
116
117
use std::collections::{HashMap, HashSet};
const MODULUS: usize = 1 << 24;
const N_ITERATIONS: usize = 2_000;
fn parse_input(input: &str) -> Vec<usize> {
input.lines().map(|line| line.parse().unwrap()).collect()
}
fn mix_prune(secret: &mut usize, update: &usize) {
*secret = (*secret ^ *update) % MODULUS;
}
fn update_secret(secret: &mut usize, lookup: &mut HashMap<usize, usize>) {
if lookup.contains_key(secret) {
*secret = lookup.get(secret).unwrap().clone();
} else {
let old_secret = *secret;
let mut result = *secret << 6;
mix_prune(secret, &result);
result = *secret >> 5;
mix_prune(secret, &result);
result = *secret << 11;
mix_prune(secret, &result);
lookup.insert(old_secret, *secret);
}
}
pub fn task01(input: &str) -> String {
let mut secrets = parse_input(input);
let mut lookup = HashMap::with_capacity(MODULUS);
secrets
.iter_mut()
.map(|secret| {
for _ in 0..N_ITERATIONS {
update_secret(secret, &mut lookup);
}
*secret
})
.sum::<usize>()
.to_string()
}
pub fn task02(input: &str) -> String {
let mut secrets = parse_input(input);
let mut lookup = HashMap::with_capacity(MODULUS);
// Map price pattern -> number of bananas
let mut bananas = HashMap::new();
secrets.iter_mut().for_each(|secret| {
let mut price_deltas = Vec::new();
let mut used_patterns = HashSet::new();
(0..N_ITERATIONS).fold(0, |last_price, i| {
update_secret(secret, &mut lookup);
let price = *secret % 10;
if i > 0 {
price_deltas.push(price as isize - last_price as isize);
}
if price_deltas.len() >= 4 {
// String conversion turned out easier (for me) than extracting a fixed sized array or tuple...
let pattern = price_deltas
.iter()
.rev()
.take(4)
.map(|delta| delta.to_string())
.collect::<Vec<_>>()
.join(",");
// Make sure we only use each pattern once
if !used_patterns.contains(&pattern) {
bananas.insert(
pattern.clone(),
price + *bananas.get(&pattern).unwrap_or(&0),
);
used_patterns.insert(pattern.clone());
}
}
price
});
});
bananas.values().max().unwrap().to_string()
}
#[cfg(test)]
mod tests {
use super::super::fs_utils::{read_example, read_input};
use super::*;
#[test]
fn test_task01() {
let input = read_example(22, 1);
assert_eq!(task01(&input), "37327623");
}
#[test]
fn run_task01() {
let input = read_input(22);
assert_eq!(task01(&input), "12664695565");
}
#[test]
fn test_task02() {
let input = read_example(22, 2);
assert_eq!(task02(&input), "23");
}
#[test]
fn run_task02() {
let input = read_input(22);
assert_eq!(task02(&input), "1444");
}
}