use std::{ fs::File, io::{BufRead as _, BufReader}, }; fn get_lines(name: &str) -> impl Iterator { BufReader::new(File::open(name).unwrap()) .lines() .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}"); } } fn main() { // day1::task1(); // day1::task1(); // day2::task1(); // day2::task2(); // day3::task1(); // day3::task2(); day4::task1(); day4::task2(); }