From 94e2a83fd6862848aacd8ca02a9260917e4577c5 Mon Sep 17 00:00:00 2001 From: StNicolay Date: Thu, 5 Dec 2024 19:47:50 +0300 Subject: [PATCH] Cleanup --- src/day1.rs | 32 ++++++ src/day2.rs | 49 +++++++++ src/day3.rs | 34 +++++++ src/day4.rs | 62 ++++++++++++ src/day5.rs | 79 +++++++++++++++ src/main.rs | 285 ++-------------------------------------------------- 6 files changed, 264 insertions(+), 277 deletions(-) create mode 100644 src/day1.rs create mode 100644 src/day2.rs create mode 100644 src/day3.rs create mode 100644 src/day4.rs create mode 100644 src/day5.rs diff --git a/src/day1.rs b/src/day1.rs new file mode 100644 index 0000000..7f6b28f --- /dev/null +++ b/src/day1.rs @@ -0,0 +1,32 @@ + +use std::collections::HashMap; + +use crate::get_lines; + +#[allow(dead_code)] +pub fn task1() { + let mut a = Vec::::new(); + let mut b = Vec::::new(); + for line in get_lines("input.txt") { + let (a1, b1) = line.trim_end().split_once(" ").unwrap(); + a.push(a1.parse().unwrap()); + b.push(b1.parse().unwrap()); + } + a.sort_unstable(); + b.sort_unstable(); + let result: i32 = a.into_iter().zip(b).map(|(a, b)| (a - b).abs()).sum(); + println!("{result}"); +} + +#[allow(dead_code)] +pub fn task2() { + let mut a = Vec::::new(); + let mut b = HashMap::::new(); + for line in get_lines("input.txt") { + let (a1, b1) = line.trim_end().split_once(" ").unwrap(); + a.push(a1.parse().unwrap()); + *b.entry(b1.parse().unwrap()).or_insert(0) += 1; + } + let result: u32 = a.into_iter().map(|a| a * *b.get(&a).unwrap_or(&0)).sum(); + println!("{result}"); +} diff --git a/src/day2.rs b/src/day2.rs new file mode 100644 index 0000000..1a29445 --- /dev/null +++ b/src/day2.rs @@ -0,0 +1,49 @@ +use itertools::Itertools; + +use crate::{get_lines, parse_line}; + +fn safe(iter: impl Iterator) -> bool { + let mut order = None; + for (a, b) in iter.tuple_windows() { + if !(1..4).contains(&(a - b).abs()) { + return false; + } + if order.is_none() { + order = Some(a.cmp(&b)); + } else if order != Some(a.cmp(&b)) { + return false; + } + } + true +} + +#[allow(dead_code)] +pub fn task1() { + let result = get_lines("input.txt") + .filter(|line| safe(parse_line(line, ' '))) + .count(); + println!("{result}"); +} + +#[allow(dead_code)] +pub fn task2() { + let result = get_lines("input.txt") + .filter(|line| { + let numbers = parse_line(line, ' ').collect_vec(); + if safe(numbers.iter().copied()) { + return true; + } + let mut test = Vec::with_capacity(numbers.len() - 1); + for i in 0..numbers.len() { + test.extend_from_slice(&numbers[..i]); + test.extend_from_slice(&numbers[i + 1..]); + if safe(test.iter().copied()) { + return true; + } + test.clear(); + } + false + }) + .count(); + println!("{result}"); +} diff --git a/src/day3.rs b/src/day3.rs new file mode 100644 index 0000000..e31fdd2 --- /dev/null +++ b/src/day3.rs @@ -0,0 +1,34 @@ +use std::fs::read_to_string; + +use regex::Regex; + +#[allow(dead_code)] +pub fn task1() { + let rx = Regex::new(r"mul\((\d{1,3}),(\d{1,3})\)").unwrap(); + let mut result: i64 = 0; + for c in rx.captures_iter(&read_to_string("input.txt").unwrap()) { + let (_, [a, b]) = c.extract(); + result += a.parse::().unwrap() * b.parse::().unwrap(); + } + println!("{result}"); +} + +#[allow(dead_code)] +pub fn task2() { + let rx = Regex::new(r"(mul)\((\d{1,3}),(\d{1,3})\)|do()()()\(\)|do(n't)()()\(\)").unwrap(); + let mut enabled = true; + let mut result: i64 = 0; + for c in rx.captures_iter(&read_to_string("input.txt").unwrap()) { + let (_, [op, a, b]) = c.extract(); + match op { + "" => enabled = true, + "n't" => enabled = false, + "mul" if enabled => { + result += a.parse::().unwrap() * b.parse::().unwrap(); + } + "mul" => {} + _ => unreachable!("{op}"), + } + } + println!("{result}"); +} diff --git a/src/day4.rs b/src/day4.rs new file mode 100644 index 0000000..e90c9fb --- /dev/null +++ b/src/day4.rs @@ -0,0 +1,62 @@ +use itertools::Itertools; + +#[allow(dead_code)] +pub fn task1() { + fn check(vals: &[u8]) -> usize { + (vals == b"XMAS" || vals == b"SAMX").into() + } + + let data = std::fs::read_to_string("input.txt").unwrap(); + let mut lines = Vec::new(); + let mut count = 0; + for line in data.lines() { + count += line.matches("XMAS").count(); + count += line.matches("SAMX").count(); + lines.push(line.as_bytes()); + } + for (i, &line) in lines[0..lines.len() - 3].iter().enumerate() { + for j in 0..line.len() { + count += check(&[ + lines[i][j], + lines[i + 1][j], + lines[i + 2][j], + lines[i + 3][j], + ]); + if j + 3 < line.len() { + count += check(&[ + lines[i][j], + lines[i + 1][j + 1], + lines[i + 2][j + 2], + lines[i + 3][j + 3], + ]); + } + if j > 2 { + count += check(&[ + lines[i][j], + lines[i + 1][j - 1], + lines[i + 2][j - 2], + lines[i + 3][j - 3], + ]); + } + } + } + println!("{count}"); +} + +#[allow(dead_code)] +pub fn task2() { + fn check(vals: &[u8]) -> usize { + (vals == b"MAS" || vals == b"SAM").into() + } + + let data = std::fs::read_to_string("input.txt").unwrap(); + let lines = data.lines().map(str::as_bytes).collect_vec(); + let mut count: usize = 0; + for i in 0..lines[..lines.len() - 2].len() { + for j in 0..lines[i].len() - 2 { + count += check(&[lines[i][j], lines[i + 1][j + 1], lines[i + 2][j + 2]]) + * check(&[lines[i][j + 2], lines[i + 1][j + 1], lines[i + 2][j]]); + } + } + println!("{count}"); +} diff --git a/src/day5.rs b/src/day5.rs new file mode 100644 index 0000000..b83135b --- /dev/null +++ b/src/day5.rs @@ -0,0 +1,79 @@ +use std::{ + cmp::Ordering, + collections::{HashMap, HashSet}, +}; + +use itertools::Itertools; + +use crate::parse_line; + +type Rules = HashMap>; + +fn parse_rules<'a>(lines: &mut impl Iterator) -> Rules { + let mut rules: Rules = HashMap::new(); + for rule in lines.by_ref().take_while(|s| !s.is_empty()) { + let vals = rule.split_once('|').unwrap(); + let (before, after) = (vals.0.parse().unwrap(), vals.1.parse().unwrap()); + rules.entry(before).or_default().insert(after); + } + rules +} + +fn parse_updates<'a>( + lines: impl Iterator + 'a, +) -> impl Iterator> + 'a { + lines.map(|line| parse_line(line, ',').collect_vec()) +} + +fn check_update(update: &[i32], rules: &Rules) -> bool { + for (i, val) in update.iter().enumerate() { + let Some(local_rules) = rules.get(val) else { + continue; + }; + if update[..i].iter().any(|elem| local_rules.contains(elem)) { + return false; + } + } + true +} + +#[allow(dead_code)] +pub fn task1() { + let data = std::fs::read_to_string("input.txt").unwrap(); + let mut lines = data.lines(); + let rules = parse_rules(&mut lines); + let result: i32 = parse_updates(lines) + .filter(|u| check_update(u, &rules)) + .map(|u| u[u.len() / 2]) + .sum(); + println!("{result}"); +} + +fn compare(a: i32, b: i32, rules: &Rules) -> Ordering { + if let Some(rule) = rules.get(&a) { + if rule.contains(&b) { + return Ordering::Less; + } + } + if let Some(rule) = rules.get(&b) { + if rule.contains(&a) { + return Ordering::Greater; + } + } + Ordering::Equal +} + +#[allow(dead_code)] +pub fn task2() { + let data = std::fs::read_to_string("input.txt").unwrap(); + let mut lines = data.lines(); + let rules = parse_rules(&mut lines); + let result: i32 = parse_updates(lines) + .filter(|u| !check_update(u, &rules)) + .map(|mut u| { + u.sort_unstable_by(|a, b| compare(*a, *b, &rules)); + u[u.len() / 2] + }) + .sum(); + println!("{result}"); +} diff --git a/src/main.rs b/src/main.rs index 35d09bd..7c92b89 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,9 @@ +mod day1; +mod day2; +mod day3; +mod day4; +mod day5; + use std::{ fs::File, io::{BufRead as _, BufReader}, @@ -9,283 +15,8 @@ fn get_lines(name: &str) -> impl Iterator { .map(|line| line.unwrap()) } -mod day1 { - use std::collections::HashMap; - - use crate::get_lines; - - #[allow(dead_code)] - pub fn task1() { - let mut a = Vec::::new(); - let mut b = Vec::::new(); - for line in get_lines("input.txt") { - let (a1, b1) = line.trim_end().split_once(" ").unwrap(); - a.push(a1.parse().unwrap()); - b.push(b1.parse().unwrap()); - } - a.sort_unstable(); - b.sort_unstable(); - let result: i32 = a.into_iter().zip(b).map(|(a, b)| (a - b).abs()).sum(); - println!("{result}"); - } - - #[allow(dead_code)] - pub fn task2() { - let mut a = Vec::::new(); - let mut b = HashMap::::new(); - for line in get_lines("input.txt") { - let (a1, b1) = line.trim_end().split_once(" ").unwrap(); - a.push(a1.parse().unwrap()); - *b.entry(b1.parse().unwrap()).or_insert(0) += 1; - } - let result: u32 = a.into_iter().map(|a| a * *b.get(&a).unwrap_or(&0)).sum(); - println!("{result}"); - } -} - -mod day2 { - use itertools::Itertools; - - use crate::get_lines; - - fn safe(iter: impl Iterator) -> bool { - let mut order = None; - for (a, b) in iter.tuple_windows() { - if !(1..4).contains(&(a - b).abs()) { - return false; - } - if order.is_none() { - order = Some(a.cmp(&b)); - } else if order != Some(a.cmp(&b)) { - return false; - } - } - true - } - - fn parse_line(line: &str) -> impl Iterator + '_ { - line.trim() - .split(' ') - .map(|num| num.parse::().unwrap()) - } - - #[allow(dead_code)] - pub fn task1() { - let result = get_lines("input.txt") - .filter(|line| safe(parse_line(line))) - .count(); - println!("{result}"); - } - - #[allow(dead_code)] - pub fn task2() { - let result = get_lines("input.txt") - .filter(|line| { - let numbers = parse_line(line).collect_vec(); - if safe(numbers.iter().copied()) { - return true; - } - let mut test = Vec::with_capacity(numbers.len() - 1); - for i in 0..numbers.len() { - test.extend_from_slice(&numbers[..i]); - test.extend_from_slice(&numbers[i + 1..]); - if safe(test.iter().copied()) { - return true; - } - test.clear(); - } - false - }) - .count(); - println!("{result}"); - } -} - -mod day3 { - use std::fs::read_to_string; - - use regex::Regex; - - #[allow(dead_code)] - pub fn task1() { - let rx = Regex::new(r"mul\((\d{1,3}),(\d{1,3})\)").unwrap(); - let mut result: i64 = 0; - for c in rx.captures_iter(&read_to_string("input.txt").unwrap()) { - let (_, [a, b]) = c.extract(); - result += a.parse::().unwrap() * b.parse::().unwrap(); - } - println!("{result}"); - } - - #[allow(dead_code)] - pub fn task2() { - let rx = Regex::new(r"(mul)\((\d{1,3}),(\d{1,3})\)|do()()()\(\)|do(n't)()()\(\)").unwrap(); - let mut enabled = true; - let mut result: i64 = 0; - for c in rx.captures_iter(&read_to_string("input.txt").unwrap()) { - let (_, [op, a, b]) = c.extract(); - match op { - "" => enabled = true, - "n't" => enabled = false, - "mul" if enabled => { - result += a.parse::().unwrap() * b.parse::().unwrap(); - } - "mul" => {} - _ => unreachable!("{op}"), - } - } - println!("{result}"); - } -} - -mod day4 { - use itertools::Itertools; - - #[allow(dead_code)] - pub fn task1() { - fn check(vals: &[u8]) -> usize { - (vals == b"XMAS" || vals == b"SAMX").into() - } - - let data = std::fs::read_to_string("input.txt").unwrap(); - let mut lines = Vec::new(); - let mut count = 0; - for line in data.lines() { - count += line.matches("XMAS").count(); - count += line.matches("SAMX").count(); - lines.push(line.as_bytes()); - } - for (i, &line) in lines[0..lines.len() - 3].iter().enumerate() { - for j in 0..line.len() { - count += check(&[ - lines[i][j], - lines[i + 1][j], - lines[i + 2][j], - lines[i + 3][j], - ]); - if j + 3 < line.len() { - count += check(&[ - lines[i][j], - lines[i + 1][j + 1], - lines[i + 2][j + 2], - lines[i + 3][j + 3], - ]); - } - if j > 2 { - count += check(&[ - lines[i][j], - lines[i + 1][j - 1], - lines[i + 2][j - 2], - lines[i + 3][j - 3], - ]); - } - } - } - println!("{count}"); - } - - #[allow(dead_code)] - pub fn task2() { - fn check(vals: &[u8]) -> usize { - (vals == b"MAS" || vals == b"SAM").into() - } - - let data = std::fs::read_to_string("input.txt").unwrap(); - let lines = data.lines().map(str::as_bytes).collect_vec(); - let mut count: usize = 0; - for i in 0..lines[..lines.len() - 2].len() { - for j in 0..lines[i].len() - 2 { - count += check(&[lines[i][j], lines[i + 1][j + 1], lines[i + 2][j + 2]]) - * check(&[lines[i][j + 2], lines[i + 1][j + 1], lines[i + 2][j]]); - } - } - println!("{count}"); - } -} - -mod day5 { - use std::{ - cmp::Ordering, - collections::{HashMap, HashSet}, - }; - - use itertools::Itertools; - - type Rules = HashMap>; - - fn parse_rules<'a>(lines: &mut impl Iterator) -> Rules { - let mut rules: Rules = HashMap::new(); - for rule in lines.by_ref().take_while(|s| !s.is_empty()) { - let vals = rule.split_once('|').unwrap(); - let (before, after) = (vals.0.parse().unwrap(), vals.1.parse().unwrap()); - rules.entry(before).or_default().insert(after); - } - rules - } - - fn parse_updates<'a>( - lines: impl Iterator + 'a, - ) -> impl Iterator> + 'a { - lines.map(|line| { - line.trim() - .split(',') - .map(|num| num.parse::().unwrap()) - .collect_vec() - }) - } - - fn check_update(update: &[i32], rules: &Rules) -> bool { - for (i, val) in update.iter().enumerate() { - let Some(local_rules) = rules.get(val) else { - continue; - }; - if update[..i].iter().any(|elem| local_rules.contains(elem)) { - return false; - } - } - true - } - - #[allow(dead_code)] - pub fn task1() { - let data = std::fs::read_to_string("input.txt").unwrap(); - let mut lines = data.lines(); - let rules = parse_rules(&mut lines); - let result: i32 = parse_updates(lines) - .filter(|u| check_update(u, &rules)) - .map(|u| u[u.len() / 2]) - .sum(); - println!("{result}"); - } - - fn compare(a: i32, b: i32, rules: &Rules) -> Ordering { - if let Some(rule) = rules.get(&a) { - if rule.contains(&b) { - return Ordering::Less; - } - } - if let Some(rule) = rules.get(&b) { - if rule.contains(&a) { - return Ordering::Greater; - } - } - Ordering::Equal - } - - #[allow(dead_code)] - pub fn task2() { - let data = std::fs::read_to_string("input.txt").unwrap(); - let mut lines = data.lines(); - let rules = parse_rules(&mut lines); - let result: i32 = parse_updates(lines) - .filter(|u| !check_update(u, &rules)) - .map(|mut u| { - u.sort_unstable_by(|a, b| compare(*a, *b, &rules)); - u[u.len() / 2] - }) - .sum(); - println!("{result}"); - } +fn parse_line(line: &str, pattern: char) -> impl Iterator + '_ { + line.trim().split(pattern).map(|num| num.parse().unwrap()) } fn main() {