Skip to content

Commit c2a29bc

Browse files
committed
feat(2018): refactor days 4-6 to use aoc-rust-common
1 parent 7c403bb commit c2a29bc

5 files changed

Lines changed: 123 additions & 299 deletions

File tree

2018/src/day04/mod.rs

Lines changed: 31 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,36 @@
1+
use aoc_rust_common::Solution;
2+
use std::fmt::Display;
13
use std::collections::HashMap;
2-
3-
use chrono::offset::TimeZone;
4-
use chrono::offset::Utc;
5-
use chrono::DateTime;
6-
use chrono::Timelike;
4+
use chrono::{DateTime, Utc, Timelike, NaiveDateTime};
75
use regex::Regex;
86

9-
#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Copy, Clone)]
10-
enum EventType {
11-
Wake,
12-
Sleep,
13-
Shift(usize),
14-
}
7+
pub struct Day04;
158

169
#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Copy, Clone)]
17-
struct Event {
18-
time: DateTime<Utc>,
19-
event: EventType,
20-
}
21-
22-
#[derive(Default)]
23-
pub struct Day04 {
24-
events: Vec<Event>,
25-
}
10+
enum EventType { Wake, Sleep, Shift(usize) }
11+
#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Copy, Clone)]
12+
struct Event { time: DateTime<Utc>, event: EventType }
2613

27-
fn read_events(input: String) -> Vec<Event> {
14+
fn get_sleeps(input: &str) -> HashMap<usize, [u32; 60]> {
2815
let scanner = Regex::new(r"^\[([^]]+)] (Guard #(\d+)|falls asleep|wakes up)").unwrap();
29-
30-
let mut events = Vec::new();
31-
for line in input.lines() {
16+
let mut events: Vec<Event> = input.lines().map(|line| {
3217
let captures = scanner.captures(line).unwrap();
33-
let timestamp = Utc
34-
.datetime_from_str(&captures[1], "%Y-%m-%d %H:%M")
35-
.unwrap();
36-
18+
let timestamp = NaiveDateTime::parse_from_str(&captures[1], "%Y-%m-%d %H:%M").unwrap().and_local_timezone(Utc).unwrap();
3719
let event = match &captures[2] {
38-
"falls asleep" => EventType::Sleep,
39-
"wakes up" => EventType::Wake,
20+
"falls asleep" => EventType::Sleep, "wakes up" => EventType::Wake,
4021
_ => EventType::Shift(captures[3].parse().unwrap()),
4122
};
42-
43-
events.push(Event {
44-
time: timestamp,
45-
event,
46-
});
47-
}
23+
Event { time: timestamp, event }
24+
}).collect();
4825
events.sort_unstable();
49-
events
50-
}
51-
fn format_results(sleepers: &HashMap<usize, [u32; 60]>, scores: &HashMap<usize, u32>) -> usize {
52-
let (best_sleeper, _) = scores.iter().max_by(|&(_, a), &(_, b)| a.cmp(b)).unwrap();
5326

54-
let best_minute = sleepers[best_sleeper]
55-
.iter()
56-
.enumerate()
57-
.max_by(|&(_, a), &(_, b)| a.cmp(b))
58-
.unwrap()
59-
.0;
60-
61-
best_sleeper * best_minute
62-
}
63-
64-
fn get_sleeps(events: Vec<Event>) -> HashMap<usize, [u32; 60]> {
6527
let mut sleeps = HashMap::new();
6628
let mut guard: Option<usize> = None;
6729
let mut sleep_start: Option<DateTime<Utc>> = None;
68-
6930
for event in events.iter() {
7031
match &event.event {
71-
EventType::Shift(val) => {
72-
guard = Some(*val);
73-
sleep_start = None;
74-
}
75-
EventType::Sleep => {
76-
sleep_start = Some(event.time);
77-
}
32+
EventType::Shift(val) => { guard = Some(*val); sleep_start = None; }
33+
EventType::Sleep => { sleep_start = Some(event.time); }
7834
EventType::Wake => {
7935
let minutes = sleeps.entry(guard.unwrap()).or_insert([0u32; 60]);
8036
for m in sleep_start.unwrap().minute()..event.time.minute() {
@@ -85,51 +41,24 @@ fn get_sleeps(events: Vec<Event>) -> HashMap<usize, [u32; 60]> {
8541
}
8642
sleeps
8743
}
88-
fn part1(input: String) -> (HashMap<usize, [u32; 60]>, HashMap<usize, u32>) {
89-
let events = read_events(input);
90-
let sleepers = get_sleeps(events);
91-
let scores: HashMap<usize, u32> = sleepers.iter().map(|(k, v)| (*k, v.iter().sum())).collect();
9244

93-
(sleepers, scores)
94-
}
95-
96-
fn part2(input: String) -> (HashMap<usize, [u32; 60]>, HashMap<usize, u32>) {
97-
let events = read_events(input);
98-
let sleepers = get_sleeps(events);
99-
let scores: HashMap<usize, u32> = sleepers
100-
.iter()
101-
.map(|(k, v)| (*k, *v.iter().max().unwrap()))
102-
.collect();
103-
104-
(sleepers, scores)
105-
}
106-
107-
#[cfg(test)]
108-
mod tests {
109-
use super::*;
45+
impl Solution for Day04 {
46+
fn year(&self) -> u32 { 2018 }
47+
fn day(&self) -> u32 { 4 }
11048

111-
#[test]
112-
#[ignore]
113-
fn test_first() {
114-
let example = include_str!("./example.data");
115-
let (sleepers, scores) = part1(example.to_owned());
116-
let result = format_results(&sleepers, &scores);
117-
assert_eq!(240, result);
118-
let prod = include_str!("./prod.data");
119-
let (sleepers, scores) = part1(prod.to_owned());
120-
let result = format_results(&sleepers, &scores);
121-
assert_eq!(76357, result);
49+
fn part1(&self, input: &str) -> Box<dyn Display> {
50+
let sleepers = get_sleeps(input);
51+
let scores: HashMap<usize, u32> = sleepers.iter().map(|(k, v)| (*k, v.iter().sum())).collect();
52+
let (best_sleeper, _) = scores.iter().max_by_key(|&(_, v)| v).unwrap();
53+
let best_minute = sleepers[best_sleeper].iter().enumerate().max_by_key(|&(_, count)| count).unwrap().0;
54+
Box::new(best_sleeper * best_minute)
12255
}
123-
#[test]
124-
#[ignore]
125-
fn test_second() {
126-
let example = include_str!("./example.data");
127-
let (sleepers, scores) = part2(example.to_owned());
128-
let result = format_results(&sleepers, &scores);
129-
assert_eq!(4455, result);
130-
let prod = include_str!("./prod.data");
131-
let (sleepers, scores) = part2(prod.to_owned());
132-
let result = format_results(&sleepers, &scores);
133-
assert_eq!(41668, result);
56+
57+
fn part2(&self, input: &str) -> Box<dyn Display> {
58+
let sleepers = get_sleeps(input);
59+
let (guard, (minute, _)) = sleepers.iter().map(|(guard, minutes)| {
60+
(guard, minutes.iter().enumerate().max_by_key(|&(_, count)| count).unwrap())
61+
}).max_by_key(|&(_, (_, count))| count).unwrap();
62+
Box::new(guard * minute)
13463
}
13564
}

2018/src/day05/mod.rs

Lines changed: 25 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,39 @@
1-
fn part1(content: String) -> String {
2-
let mut local = content;
3-
loop {
4-
let len = local.len();
5-
local = react(local);
6-
if len == local.len() {
7-
break;
8-
}
9-
}
10-
11-
local
12-
}
13-
14-
fn part2(content: String) -> (Vec<char>, Vec<usize>) {
15-
let local = content;
16-
let mut remaining = Vec::new();
17-
let mut scores = Vec::new();
18-
for c in "abcdefghijklmnopqrstuvwxyz".chars() {
19-
let mut local = local.clone();
20-
local = local.replace(c, "");
21-
local = local.replace(c.to_ascii_uppercase(), "");
22-
loop {
23-
let len = local.len();
24-
local = react(local);
25-
if len == local.len() {
26-
break;
27-
}
28-
}
29-
remaining.push(c);
30-
scores.push(local.len());
31-
}
1+
use aoc_rust_common::Solution;
2+
use std::fmt::Display;
323

33-
(remaining, scores)
34-
}
4+
pub struct Day05;
355

36-
fn react(content: String) -> String {
37-
let mut local = content;
6+
fn react(polymer: &mut Vec<char>) {
387
let mut i = 0;
39-
while i < local.len() - 1 {
40-
let a = local.chars().nth(i).unwrap();
41-
let b = local.chars().nth(i + 1).unwrap();
42-
if a != b && a.to_ascii_lowercase() == b.to_ascii_lowercase() {
43-
local.remove(i);
44-
local.remove(i);
45-
if i > 0 {
46-
i = i.saturating_sub(1);
47-
}
8+
while i < polymer.len().saturating_sub(1) {
9+
if polymer[i].eq_ignore_ascii_case(&polymer[i+1]) && polymer[i] != polymer[i+1] {
10+
polymer.remove(i);
11+
polymer.remove(i);
12+
i = i.saturating_sub(1);
4813
} else {
4914
i += 1;
5015
}
5116
}
52-
53-
local.to_owned()
5417
}
5518

56-
#[cfg(test)]
57-
mod tests {
58-
use super::*;
19+
impl Solution for Day05 {
20+
fn year(&self) -> u32 { 2018 }
21+
fn day(&self) -> u32 { 5 }
5922

60-
#[test]
61-
#[ignore]
62-
fn test_first() {
63-
let example = include_str!("./example.data");
64-
let remaining = part1(example.to_owned());
65-
assert_eq!(10, remaining.len());
66-
let prod = include_str!("./prod.data");
67-
let remaining = part1(prod.to_owned());
68-
assert_eq!(10384, remaining.len());
23+
fn part1(&self, input: &str) -> Box<dyn Display> {
24+
let mut polymer: Vec<char> = input.trim().chars().collect();
25+
react(&mut polymer);
26+
Box::new(polymer.len())
6927
}
7028

71-
#[test]
72-
#[ignore]
73-
fn test_second() {
74-
let example = include_str!("./example.data");
75-
let (remaining, scores) = part2(example.to_owned());
76-
let result = remaining
77-
.iter()
78-
.zip(scores.iter())
79-
.min_by_key(|(_, &v)| v)
80-
.unwrap();
81-
assert_eq!(4, *result.1);
82-
83-
let example = include_str!("./prod.data");
84-
let (remaining, scores) = part2(example.to_owned());
85-
let result = remaining
86-
.iter()
87-
.zip(scores.iter())
88-
.min_by_key(|(_, &v)| v)
89-
.unwrap();
90-
assert_eq!(5412, *result.1);
29+
fn part2(&self, input: &str) -> Box<dyn Display> {
30+
let original_polymer: Vec<char> = input.trim().chars().collect();
31+
let min_len = ('a'..='z').map(|unit_to_remove| {
32+
let mut polymer = original_polymer.clone();
33+
polymer.retain(|&c| !c.eq_ignore_ascii_case(&unit_to_remove));
34+
react(&mut polymer);
35+
polymer.len()
36+
}).min().unwrap_or(0);
37+
Box::new(min_len)
9138
}
9239
}

0 commit comments

Comments
 (0)