summaryrefslogtreecommitdiff
path: root/2024_rust/src/day5.rs
diff options
context:
space:
mode:
Diffstat (limited to '2024_rust/src/day5.rs')
-rw-r--r--2024_rust/src/day5.rs220
1 files changed, 0 insertions, 220 deletions
diff --git a/2024_rust/src/day5.rs b/2024_rust/src/day5.rs
deleted file mode 100644
index e13f8e5..0000000
--- a/2024_rust/src/day5.rs
+++ /dev/null
@@ -1,220 +0,0 @@
-use regex::Regex;
-use std::collections::{HashMap, HashSet};
-use std::str::FromStr;
-
-type Page = u32;
-
-#[derive(Debug, Clone)]
-struct Rule {
- before: Page,
- after: Page,
-}
-
-#[derive(Debug)]
-enum ParseError {
- ParseError,
-}
-
-impl FromStr for Rule {
- type Err = ParseError;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let Some(cs) = Regex::new("^([0-9]+)\\|([0-9]+)$").unwrap().captures(s) else {
- return Err(ParseError::ParseError);
- };
- let (_full, [bf, af]) = cs.extract();
- Ok(Rule {
- before: bf.parse().unwrap(),
- after: af.parse().unwrap(),
- })
- }
-}
-
-#[derive(Debug)]
-struct RuleStatus {
- previous: HashMap<Page, HashSet<Page>>,
- invalid: HashSet<Page>,
-}
-
-impl RuleStatus {
- fn new(rules: &Vec<Rule>) -> Self {
- let mut previous = HashMap::new();
- for &Rule { before, after } in rules.iter() {
- match previous.get_mut(&after) {
- None => {
- let mut set = HashSet::new();
- set.insert(before);
- previous.insert(after, set);
- }
- Some(set) => {
- set.insert(before);
- }
- }
- }
- RuleStatus {
- previous,
- invalid: HashSet::new(),
- }
- }
-
- fn step(&mut self, page: &Page) -> bool {
- let RuleStatus { previous, invalid } = self;
- if invalid.contains(page) {
- return false;
- }
- if let Some(prev) = previous.get(page) {
- for p in prev.iter() {
- invalid.insert(*p);
- }
- }
- true
- }
-}
-
-type Update = Vec<Page>;
-
-fn update_from_str(s: &str) -> Update {
- Regex::new("([0-9]+)")
- .unwrap()
- .find_iter(s)
- .map(|s| s.as_str().parse().unwrap())
- .collect()
-}
-
-fn is_update_valid(update: &Update, rules: &Vec<Rule>) -> bool {
- let mut status = RuleStatus::new(&rules);
- for page in update.iter() {
- if !status.step(page) {
- return false;
- }
- }
- true
-}
-
-fn middle_page(update: &Update) -> Page {
- update[update.len() / 2]
-}
-
-#[derive(Debug)]
-struct Input {
- rules: Vec<Rule>,
- updates: Vec<Update>,
-}
-
-impl FromStr for Input {
- type Err = ParseError;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let mut lines = s.lines();
-
- let mut input = Input {
- rules: vec![],
- updates: vec![],
- };
-
- // Read rules
- while let Some(l) = lines.next() {
- if l == "" {
- break;
- }
- input.rules.push(Rule::from_str(l).unwrap());
- }
-
- // Read updates
- while let Some(l) = lines.next() {
- input.updates.push(update_from_str(l));
- }
-
- Ok(input)
- }
-}
-
-fn sum_valid_updates(Input { rules, updates }: &Input) -> u32 {
- updates
- .iter()
- .filter(|u| is_update_valid(u, &rules))
- .map(|u| middle_page(u))
- .sum()
-}
-
-pub fn p1(input: &str) -> String {
- let input = Input::from_str(input).unwrap();
- sum_valid_updates(&input).to_string()
-}
-
-// Remove useless rules for this particular update
-fn filter_rules(rules: &Vec<Rule>, update: &Update) -> Vec<Rule> {
- let updated: HashSet<&Page> = update.iter().collect();
- rules
- .iter()
- .cloned()
- .filter(|r| updated.contains(&r.before))
- .collect()
-}
-
-fn sort_rules(rules: &Vec<Rule>) -> Vec<Rule> {
- let mut sorted: Vec<Rule> = vec![];
- let mut afters: HashMap<Page, u8> = HashMap::new();
- for a in rules.iter().map(|r| r.after) {
- *afters.entry(a).or_default() += 1;
- }
-
- // Allocate new "droppable" rules by wrapping the originals into Options
- let mut rules: Vec<Option<&Rule>> = rules.iter().map(|r| Some(r)).collect();
- while rules.iter().any(|x| x.is_some()) {
- for rule in rules.iter_mut() {
- let Some(r) = *rule else { continue };
- if let None = afters.get(&r.before) {
- sorted.push(r.clone());
- match afters.get_mut(&r.after) {
- None => {
- panic!("This should not happen");
- }
- Some(1) => {
- afters.remove(&r.after);
- }
- Some(x) => {
- *x -= 1;
- }
- };
- *rule = None;
- }
- }
- }
-
- sorted
-}
-
-fn update_reorder(update: &Update, rules: &Vec<Rule>) -> Option<Update> {
- let filtered_rules = filter_rules(rules, update);
- let sorted_rules = sort_rules(&filtered_rules);
- let mut result: Update = vec![];
- let mut pages: HashSet<Page> = update.iter().cloned().collect();
- for Rule { before, .. } in sorted_rules.iter() {
- if pages.contains(before) {
- result.push(*before);
- pages.remove(before);
- }
- }
- // Add unrestricted pages at the end
- for &p in pages.iter() {
- result.push(p);
- }
- if is_update_valid(&result, &sorted_rules) {
- Some(result)
- } else {
- None
- }
-}
-
-fn sum_reordered_updates(Input { rules, updates }: &Input) -> u32 {
- updates
- .iter()
- .filter(|u| !is_update_valid(u, &rules)) // drop valid updates
- .filter_map(|u| update_reorder(u, &rules)) // reorder updates
- .map(|u| middle_page(&u))
- .sum()
-}
-
-pub fn p2(input: &str) -> String {
- let input = Input::from_str(input).unwrap();
- sum_reordered_updates(&input).to_string()
-}