179 lines
4.5 KiB
Rust
179 lines
4.5 KiB
Rust
use std::{collections::HashMap, error::Error, fs};
|
|
|
|
/// Solves the problem for day 04.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// This function will return an error if the file cannot be read or if the input is invalid.
|
|
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
|
|
pub fn solve_day05(path: &str) -> Result<(i32, i32), Box<dyn Error>> {
|
|
let content = fs::read_to_string(path)?;
|
|
|
|
let (rules, updates) = parse_input(&content);
|
|
|
|
let ordered_updates = updates
|
|
.iter()
|
|
.map(|update| order_updates(update, &rules))
|
|
.collect::<Vec<_>>();
|
|
|
|
let result_one = updates
|
|
.iter()
|
|
.zip(ordered_updates.iter())
|
|
.filter(|(a, b)| a == b)
|
|
.map(|(a, _)| a.clone())
|
|
.collect::<Vec<_>>();
|
|
|
|
let result_two = updates
|
|
.iter()
|
|
.zip(ordered_updates.iter())
|
|
.filter(|(a, b)| a != b)
|
|
.map(|(_, b)| b.clone())
|
|
.collect::<Vec<_>>();
|
|
let part_one = sum_middle_value(&result_one);
|
|
let part_two = sum_middle_value(&result_two);
|
|
Ok((part_one, part_two))
|
|
}
|
|
|
|
fn parse_input(input: &str) -> (HashMap<i32, Vec<i32>>, Vec<Vec<i32>>) {
|
|
let parts: Vec<_> = input.split("\n\n").collect();
|
|
let mut map: HashMap<i32, Vec<i32>> = HashMap::new();
|
|
parts[0].split('\n').for_each(|r| {
|
|
let values = r
|
|
.split('|')
|
|
.map(|i| i.parse().unwrap())
|
|
.collect::<Vec<i32>>();
|
|
|
|
let index = values[0];
|
|
map.entry(index)
|
|
.or_default()
|
|
.append(values[1..].to_vec().as_mut());
|
|
});
|
|
// .collect();
|
|
|
|
let updates: Vec<Vec<i32>> = parts[1]
|
|
.split('\n')
|
|
.map(|r| r.split(',').map(|i| i.parse().unwrap()).collect())
|
|
.collect();
|
|
|
|
(map, updates)
|
|
}
|
|
|
|
fn order_updates(updates: &[i32], rules: &HashMap<i32, Vec<i32>>) -> Vec<i32> {
|
|
if !updates.iter().any(|u| rules.contains_key(u)) {
|
|
return updates.to_vec();
|
|
}
|
|
|
|
let mut ordered_updates: Vec<i32> = updates.to_vec();
|
|
|
|
ordered_updates.sort_by(|a, b| {
|
|
for (key, values) in rules {
|
|
if a == key && values.contains(b) {
|
|
return std::cmp::Ordering::Less;
|
|
// } else if b == key && values.contains(a) {
|
|
// return std::cmp::Ordering::Greater;
|
|
// } else if a < b {
|
|
// return std::cmp::Ordering::Less;
|
|
// } else if a > b {
|
|
// return std::cmp::Ordering::Greater;
|
|
}
|
|
}
|
|
std::cmp::Ordering::Equal
|
|
});
|
|
ordered_updates
|
|
}
|
|
|
|
fn sum_middle_value(input: &[Vec<i32>]) -> i32 {
|
|
input
|
|
.iter()
|
|
.filter_map(|row| {
|
|
if row.is_empty() || row.len() % 2 == 0 {
|
|
None
|
|
} else {
|
|
Some(row[row.len() / 2])
|
|
}
|
|
})
|
|
.sum()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_parse_input() {
|
|
let input = "47|53
|
|
97|13
|
|
97|61
|
|
97|47
|
|
75|29
|
|
61|13
|
|
75|53
|
|
29|13
|
|
97|29
|
|
53|29
|
|
61|53
|
|
97|53
|
|
61|29
|
|
47|13
|
|
75|47
|
|
97|75
|
|
47|61
|
|
75|61
|
|
47|29
|
|
75|13
|
|
53|13
|
|
|
|
75,47,61,53,29
|
|
97,61,53,29,13
|
|
29,13,75
|
|
75,97,47,61,53
|
|
61,13,29
|
|
97,13,75,29,47";
|
|
let (rules, updates) = parse_input(input);
|
|
assert_eq!(rules.len(), 6);
|
|
assert_eq!(rules[&47], vec![53, 13, 61, 29]);
|
|
assert_eq!(rules[&53], vec![29, 13]);
|
|
|
|
assert_eq!(updates.len(), 6);
|
|
assert_eq!(updates[0], vec![75, 47, 61, 53, 29]);
|
|
|
|
let sum = sum_middle_value(&updates);
|
|
assert_eq!(sum, 61 + 53 + 13 + 47 + 13 + 75);
|
|
|
|
let want = vec![75, 29, 13];
|
|
let got = order_updates(&updates[2], &rules);
|
|
dbg!(&got, &updates[2]);
|
|
assert_eq!(got, want);
|
|
|
|
let want = vec![97, 75, 47, 61, 53];
|
|
let got = order_updates(&updates[3], &rules);
|
|
dbg!(&got, &updates[3]);
|
|
assert_eq!(got, want);
|
|
|
|
let want = vec![61, 29, 13];
|
|
let got = order_updates(&updates[4], &rules);
|
|
dbg!(&got, &updates[4]);
|
|
assert_eq!(got, want);
|
|
|
|
let want = vec![97, 75, 47, 29, 13];
|
|
let got = order_updates(&updates[5], &rules);
|
|
dbg!(&got, &want, &updates[5]);
|
|
assert_eq!(got, want);
|
|
|
|
let want = 61;
|
|
let got = sum_middle_value(&[order_updates(&updates[0], &rules)]);
|
|
assert_eq!(got, want);
|
|
|
|
let want = 143;
|
|
let got = sum_middle_value(
|
|
&updates
|
|
.iter()
|
|
.take(3)
|
|
.map(|u| order_updates(u, &rules))
|
|
.collect::<Vec<_>>(),
|
|
);
|
|
|
|
assert_eq!(got, want);
|
|
}
|
|
}
|