use std::{ fs::File, io::{BufRead, BufReader}, }; use regex::Regex; const MAX_RED_CUBES: i32 = 12; const MAX_GREEN_CUBES: i32 = 13; const MAX_BLUE_CUBES: i32 = 14; /// Returns ([red], [green], [blue]) fn get_subset_values(subset: String) -> (i32, i32, i32) { let regexp = Regex::new(r"(\d* [a-z]{0,6})*").unwrap(); let mut strings = regexp .find_iter(&subset) .map(|m| m.as_str().trim()) .collect::>(); let red = strings .iter() .find(|s| s.ends_with("red")) .unwrap_or(&"0 red") .split(" ") .nth(0) .unwrap() .parse::() .unwrap_or(0); let green = strings .iter() .find(|s| s.ends_with("green")) .unwrap_or(&"0 green") .split(" ") .nth(0) .unwrap() .parse::() .unwrap_or(0); let blue = strings .iter() .find(|s| s.ends_with("blue")) .unwrap_or(&"0 blue") .split(" ") .nth(0) .unwrap() .parse::() .unwrap_or(0); (red, green, blue) } /// Returns (Some([id]), [lowest cubes]) if OK fn validate_game(game_results: String) -> (Option, (i32, i32, i32)) { let regexp = Regex::new(r"Game (\d*): (.*)").unwrap(); let result = regexp.captures(&game_results).unwrap(); let id: i32 = result.get(1).unwrap().as_str().parse().unwrap(); let subsets: Vec<(i32, i32, i32)> = result .get(2) .unwrap() .as_str() .split(";") .map(|s| get_subset_values(s.to_string())) .collect(); let mut lowest = (0, 0, 0); for subset in &subsets { if subset.0 > lowest.0 { lowest.0 = subset.0 } if subset.1 > lowest.1 { lowest.1 = subset.1 } if subset.2 > lowest.2 { lowest.2 = subset.2 } } for subset in &subsets { if subset.0 > MAX_RED_CUBES { return (None, lowest); } if subset.1 > MAX_GREEN_CUBES { return (None, lowest); } if subset.2 > MAX_BLUE_CUBES { return (None, lowest); } } (Some(id), lowest) } fn main() { let input_file = File::open("input.txt").unwrap(); let reader = BufReader::new(input_file); let mut sum = 0; let mut sum2 = 0; for line in reader.lines() { if let Ok(line) = line { if let (id, lowest) = validate_game(line) { if let Some(id) = id { sum += id; } sum2 += lowest.0 * lowest.1 * lowest.2; } } } println!("ids: {sum}, powers: {sum2}"); }