From 9e633301891adb56b0c1dfcc0f6cb67abc62ce23 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Mon, 4 Dec 2023 13:41:42 -0800 Subject: [PATCH] Break each day out into a module. --- src/day1.rs | 98 +++++++++++++++ src/day2.rs | 55 +++++++++ src/day3.rs | 127 +++++++++++++++++++ src/day4.rs | 50 ++++++++ src/main.rs | 348 ++-------------------------------------------------- 5 files changed, 342 insertions(+), 336 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 diff --git a/src/day1.rs b/src/day1.rs new file mode 100644 index 0000000..520cf52 --- /dev/null +++ b/src/day1.rs @@ -0,0 +1,98 @@ +use std::io; + +pub fn get_calibration_digits() -> u32 { + let mut buffer = String::new(); + let mut sum = 0; + while io::stdin().read_line(&mut buffer).unwrap() > 0 { + let nums: Vec = buffer.chars().filter_map(|c| c.to_digit(10)).collect(); + sum += nums.first().unwrap() * 10 + nums.last().unwrap(); + buffer = String::new(); + } + sum +} + +const NUMBERS: [&'static str; 9] = [ + "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", +]; + +enum SearchDir { + First, + Last, +} + +fn get_digit(line: &String, dir: SearchDir) -> u32 { + let mut first: usize = 0; + let mut index: Option = None; + for n in 1..=9 { + let f = match &dir { + SearchDir::First => line.find(&n.to_string()), + SearchDir::Last => line.rfind(&n.to_string()), + }; + if f == None { + continue; + } + let found = f.unwrap(); + match index { + None => { + index = f; + first = n; + } + Some(i) => match &dir { + SearchDir::First => { + if found < i { + index = f; + first = n; + } + } + SearchDir::Last => { + if found > i { + index = f; + first = n; + } + } + }, + } + } + for (num, num_str) in NUMBERS.iter().enumerate() { + let f = match &dir { + SearchDir::First => line.find(num_str), + SearchDir::Last => line.rfind(num_str), + }; + if f == None { + continue; + } + let found = f.unwrap(); + match index { + None => { + index = f; + first = num + 1; + } + Some(i) => match &dir { + SearchDir::First => { + if found < i { + index = f; + first = num + 1; + } + } + SearchDir::Last => { + if found > i { + index = f; + first = num + 1; + } + } + }, + } + } + first.try_into().unwrap() +} + +pub fn get_calibration_digits_alnum() -> u32 { + let mut buffer = String::new(); + let mut sum = 0; + while io::stdin().read_line(&mut buffer).unwrap() > 0 { + let val = (get_digit(&buffer, SearchDir::First) * 10) + get_digit(&buffer, SearchDir::Last); + sum += val; + buffer = String::new(); + } + sum +} diff --git a/src/day2.rs b/src/day2.rs new file mode 100644 index 0000000..706b3b6 --- /dev/null +++ b/src/day2.rs @@ -0,0 +1,55 @@ +use std::io; + +pub fn get_possible_games() -> (u32, u32) { + let mut buffer = String::new(); + let mut sum = 0; + let mut power_sum = 0; + while io::stdin().read_line(&mut buffer).unwrap() > 0 { + let mut game = buffer.split(":"); + let game_num: u32 = game.next().unwrap()[5..] + .parse() + .expect("Couldn't parse game number"); + + let mut red = 0; + let mut green = 0; + let mut blue = 0; + let pulls = game.next().unwrap().split(";"); + let mut possible = true; + for pull in pulls { + let colors = pull.split(","); + for mut color in colors { + color = color.trim(); + let num: u32 = color[..color.find(" ").unwrap()] + .parse() + .expect("Coudn't parse number of marbles."); + match &color[color.find(" ").unwrap() + 1..] { + "red" => { + if num > 12 { + possible = false; + } + red = red.max(num); + } + "green" => { + if num > 13 { + possible = false; + } + green = green.max(num); + } + "blue" => { + if num > 14 { + possible = false; + } + blue = blue.max(num); + } + c => println!("Error color {}", c), + } + } + } + if possible { + sum += game_num; + } + power_sum += red * green * blue; + buffer = String::new(); + } + (sum, power_sum) +} diff --git a/src/day3.rs b/src/day3.rs new file mode 100644 index 0000000..f39003a --- /dev/null +++ b/src/day3.rs @@ -0,0 +1,127 @@ +use std::collections::HashMap; +use std::io; + +fn record_gear(num: u32, gear: usize, gears: &mut HashMap>) { + match gears.get_mut(&gear) { + None => { + let mut vec: Vec = Vec::new(); + vec.push(num); + gears.insert(gear, vec); + } + Some(v) => v.push(num), + } +} + +fn is_part_number( + r: usize, + c: usize, + s: usize, + part_table: &Vec, + n: u32, + mut gears: &mut HashMap>, +) -> bool { + let is_symbol = |c: char| c != '.' && !c.is_numeric(); + // Check above. + if r > 0 { + let mut c_: usize = if c > 0 { c - 1 } else { c }; + let row: &Vec = &part_table[r - 1].chars().collect(); + while c_ <= c + s && c_ < row.len() { + if is_symbol(row[c_]) { + if row[c_] == '*' { + let index = (r - 1) * row.len() + c_; + record_gear(n, index, &mut gears); + } + return true; + } + c_ += 1; + } + } + + // Check Adjacent. + let adj_row: &Vec = &part_table[r].chars().collect(); + if c > 0 { + if is_symbol(adj_row[c - 1]) { + if adj_row[c - 1] == '*' { + let index = r * adj_row.len() + c - 1; + record_gear(n, index, &mut gears); + } + return true; + } + } + if c + s < adj_row.len() { + if is_symbol(adj_row[c + s]) { + if adj_row[c + s] == '*' { + let index = r * adj_row.len() + c + s; + record_gear(n, index, &mut gears); + } + return true; + } + } + + // Check below. + if r + 1 < part_table.len() { + let mut c_: usize = if c > 0 { c - 1 } else { c }; + let row: &Vec = &part_table[r + 1].chars().collect(); + while c_ <= c + s && c_ < row.len() { + if is_symbol(row[c_]) { + if row[c_] == '*' { + let index = (r + 1) * row.len() + c_; + record_gear(n, index, &mut gears); + } + return true; + } + c_ += 1; + } + } + + false +} + +pub fn sum_part_numbers() -> (u32, u32) { + let mut part_table: Vec = Vec::new(); + let mut buffer: String = String::new(); + while io::stdin().read_line(&mut buffer).unwrap() > 0 { + part_table.push(buffer.trim_end().to_string()); + buffer = String::new(); + } + + let mut sum = 0; + let mut gear_table = HashMap::new(); + + for r in 0..part_table.len() { + let mut c = 0; + let mut part_rem = &part_table[r][..]; + loop { + match part_rem.find(char::is_numeric) { + None => { + break; + } + Some(ind) => { + part_rem = &part_rem[ind..]; + c += ind; + let is_non_num = |c: char| !c.is_numeric(); + let end = match part_rem.find(is_non_num) { + None => part_rem.len(), + Some(i) => i, + }; + let num: u32 = part_rem[..end].parse().expect("Couldn't parse number"); + if is_part_number(r, c, end, &part_table, num, &mut gear_table) { + sum += num; + println!("{} {}", num, gear_table.len()); + } + part_rem = &part_rem[end..]; + c += end; + } + } + } + } + + let mut gear_sum = 0; + for (_, vec) in gear_table { + if vec.len() == 2 { + gear_sum += vec[0] * vec[1]; + } + } + + (sum, gear_sum) +} diff --git a/src/day4.rs b/src/day4.rs new file mode 100644 index 0000000..371699d --- /dev/null +++ b/src/day4.rs @@ -0,0 +1,50 @@ +use std::{collections::HashSet, io}; + +fn parse_num_list(num_str: &str) -> HashSet { + num_str + .split(' ') + .filter(|s| s.len() > 0) + .map(|s| s.parse().expect("couldn't parse")) + .collect() +} + +pub fn get_card_points() -> (u32, u32) { + let mut buffer = String::new(); + let mut score = 0; + + let mut card_num = 1; + let mut card_counts: Vec = Vec::new(); + while io::stdin().read_line(&mut buffer).unwrap() > 0 { + if card_counts.len() < card_num + 1 { + card_counts.resize(card_num + 1, 0); + } + card_counts[card_num] += 1; + let colon_index = buffer.find(':').unwrap(); + let bar_index = buffer.find('|').unwrap(); + + let winners = parse_num_list(buffer[colon_index + 1..bar_index].trim()); + let mine = parse_num_list(buffer[bar_index + 1..].trim()); + + let mut count = 0; + for num in mine { + if winners.contains(&num) { + count += 1; + } + } + + if count > 0 { + score += 1 << (count - 1); + } + + if card_counts.len() < card_num + count + 1 { + card_counts.resize(card_num + count + 1, 0); + } + for i in 1..=count { + card_counts[card_num + i] += card_counts[card_num] + } + + buffer = String::new(); + card_num += 1; + } + (score, card_counts.iter().sum()) +} diff --git a/src/main.rs b/src/main.rs index 9468c32..0243528 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,333 +1,9 @@ -use std::collections::HashMap; -use std::collections::HashSet; use std::env; -use std::io; -fn get_calibration_digits() -> u32 { - let mut buffer = String::new(); - let mut sum = 0; - while io::stdin().read_line(&mut buffer).unwrap() > 0 { - let nums: Vec = buffer.chars().filter_map(|c| c.to_digit(10)).collect(); - sum += nums.first().unwrap() * 10 + nums.last().unwrap(); - buffer = String::new(); - } - sum -} - -const NUMBERS: [&'static str; 9] = [ - "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", -]; - -enum SearchDir { - First, - Last, -} - -fn get_digit(line: &String, dir: SearchDir) -> u32 { - let mut first: usize = 0; - let mut index: Option = None; - for n in 1..=9 { - let f = match &dir { - SearchDir::First => line.find(&n.to_string()), - SearchDir::Last => line.rfind(&n.to_string()), - }; - if f == None { - continue; - } - let found = f.unwrap(); - match index { - None => { - index = f; - first = n; - } - Some(i) => match &dir { - SearchDir::First => { - if found < i { - index = f; - first = n; - } - } - SearchDir::Last => { - if found > i { - index = f; - first = n; - } - } - }, - } - } - for (num, num_str) in NUMBERS.iter().enumerate() { - let f = match &dir { - SearchDir::First => line.find(num_str), - SearchDir::Last => line.rfind(num_str), - }; - if f == None { - continue; - } - let found = f.unwrap(); - match index { - None => { - index = f; - first = num + 1; - } - Some(i) => match &dir { - SearchDir::First => { - if found < i { - index = f; - first = num + 1; - } - } - SearchDir::Last => { - if found > i { - index = f; - first = num + 1; - } - } - }, - } - } - first.try_into().unwrap() -} - -fn get_calibration_digits_alnum() -> u32 { - let mut buffer = String::new(); - let mut sum = 0; - while io::stdin().read_line(&mut buffer).unwrap() > 0 { - let val = (get_digit(&buffer, SearchDir::First) * 10) + get_digit(&buffer, SearchDir::Last); - sum += val; - buffer = String::new(); - } - sum -} - -fn get_possible_games() -> (u32, u32) { - let mut buffer = String::new(); - let mut sum = 0; - let mut power_sum = 0; - while io::stdin().read_line(&mut buffer).unwrap() > 0 { - let mut game = buffer.split(":"); - let game_num: u32 = game.next().unwrap()[5..] - .parse() - .expect("Couldn't parse game number"); - - let mut red = 0; - let mut green = 0; - let mut blue = 0; - let pulls = game.next().unwrap().split(";"); - let mut possible = true; - for pull in pulls { - let colors = pull.split(","); - for mut color in colors { - color = color.trim(); - let num: u32 = color[..color.find(" ").unwrap()] - .parse() - .expect("Coudn't parse number of marbles."); - match &color[color.find(" ").unwrap() + 1..] { - "red" => { - if num > 12 { - possible = false; - } - red = red.max(num); - } - "green" => { - if num > 13 { - possible = false; - } - green = green.max(num); - } - "blue" => { - if num > 14 { - possible = false; - } - blue = blue.max(num); - } - c => println!("Error color {}", c), - } - } - } - if possible { - sum += game_num; - } - power_sum += red * green * blue; - buffer = String::new(); - } - (sum, power_sum) -} - -fn record_gear(num: u32, gear: usize, gears: &mut HashMap>) { - println!("Gear {}", gear); - match gears.get_mut(&gear) { - None => { - let mut vec: Vec = Vec::new(); - vec.push(num); - gears.insert(gear, vec); - } - Some(v) => v.push(num), - } -} - -fn is_part_number( - r: usize, - c: usize, - s: usize, - part_table: &Vec, - n: u32, - mut gears: &mut HashMap>, -) -> bool { - let is_symbol = |c: char| c != '.' && !c.is_numeric(); - // Check above. - if r > 0 { - let mut c_: usize = if c > 0 { c - 1 } else { c }; - let row: &Vec = &part_table[r - 1].chars().collect(); - while c_ <= c + s && c_ < row.len() { - if is_symbol(row[c_]) { - if row[c_] == '*' { - let index = (r - 1) * row.len() + c_; - record_gear(n, index, &mut gears); - } - return true; - } - c_ += 1; - } - } - - // Check Adjacent. - let adj_row: &Vec = &part_table[r].chars().collect(); - if c > 0 { - if is_symbol(adj_row[c - 1]) { - if adj_row[c - 1] == '*' { - let index = r * adj_row.len() + c - 1; - record_gear(n, index, &mut gears); - } - return true; - } - } - if c + s < adj_row.len() { - if is_symbol(adj_row[c + s]) { - if adj_row[c + s] == '*' { - let index = r * adj_row.len() + c + s; - record_gear(n, index, &mut gears); - } - return true; - } - } - - // Check below. - if r + 1 < part_table.len() { - let mut c_: usize = if c > 0 { c - 1 } else { c }; - let row: &Vec = &part_table[r + 1].chars().collect(); - while c_ <= c + s && c_ < row.len() { - if is_symbol(row[c_]) { - if row[c_] == '*' { - let index = (r + 1) * row.len() + c_; - record_gear(n, index, &mut gears); - } - return true; - } - c_ += 1; - } - } - - false -} - -fn sum_part_numbers() -> (u32, u32) { - let mut part_table: Vec = Vec::new(); - let mut buffer: String = String::new(); - while io::stdin().read_line(&mut buffer).unwrap() > 0 { - part_table.push(buffer.trim_end().to_string()); - buffer = String::new(); - } - - let mut sum = 0; - let mut gear_table = HashMap::new(); - - for r in 0..part_table.len() { - let mut c = 0; - let mut part_rem = &part_table[r][..]; - loop { - match part_rem.find(char::is_numeric) { - None => { - break; - } - Some(ind) => { - part_rem = &part_rem[ind..]; - c += ind; - let is_non_num = |c: char| !c.is_numeric(); - let end = match part_rem.find(is_non_num) { - None => part_rem.len(), - Some(i) => i, - }; - let num: u32 = part_rem[..end].parse().expect("Couldn't parse number"); - if is_part_number(r, c, end, &part_table, num, &mut gear_table) { - sum += num; - println!("{} {}", num, gear_table.len()); - } - part_rem = &part_rem[end..]; - c += end; - } - } - } - } - - let mut gear_sum = 0; - for (_, vec) in gear_table { - if vec.len() == 2 { - gear_sum += vec[0] * vec[1]; - } - } - - (sum, gear_sum) -} - -fn parse_num_list(num_str: &str) -> HashSet { - num_str - .split(' ') - .filter(|s| s.len() > 0) - .map(|s| s.parse().expect("couldn't parse")) - .collect() -} - -fn get_card_points() -> (u32, u32) { - let mut buffer = String::new(); - let mut score = 0; - - let mut card_num = 1; - let mut card_counts: Vec = Vec::new(); - while io::stdin().read_line(&mut buffer).unwrap() > 0 { - if card_counts.len() < card_num + 1 { - card_counts.resize(card_num + 1, 0); - } - card_counts[card_num] += 1; - let colon_index = buffer.find(':').unwrap(); - let bar_index = buffer.find('|').unwrap(); - - let winners = parse_num_list(buffer[colon_index + 1..bar_index].trim()); - let mine = parse_num_list(buffer[bar_index + 1..].trim()); - - let mut count = 0; - for num in mine { - if winners.contains(&num) { - count += 1; - } - } - - if count > 0 { - score += 1 << (count - 1); - } - - if card_counts.len() < card_num + count + 1 { - card_counts.resize(card_num + count + 1, 0); - } - for i in 1..=count { - card_counts[card_num + i] += card_counts[card_num] - } - - buffer = String::new(); - card_num += 1; - } - (score, card_counts.iter().sum()) -} +mod day1; +mod day2; +mod day3; +mod day4; fn main() { let args: Vec = env::args().collect(); @@ -336,14 +12,14 @@ fn main() { return; } match args[1].as_str() { - "day1a" => println!("Sum: {}", get_calibration_digits()), - "day1b" => println!("Sum: {}", get_calibration_digits_alnum()), - "day2a" => println!("Sum: {}", get_possible_games().0), - "day2b" => println!("Sum: {}", get_possible_games().1), - "day3a" => println!("Sum: {}", sum_part_numbers().0), - "day3b" => println!("Sum: {}", sum_part_numbers().1), - "day4a" => println!("Sum: {}", get_card_points().0), - "day4b" => println!("Sum: {}", get_card_points().1), + "day1a" => println!("Sum: {}", day1::get_calibration_digits()), + "day1b" => println!("Sum: {}", day1::get_calibration_digits_alnum()), + "day2a" => println!("Sum: {}", day2::get_possible_games().0), + "day2b" => println!("Sum: {}", day2::get_possible_games().1), + "day3a" => println!("Sum: {}", day3::sum_part_numbers().0), + "day3b" => println!("Sum: {}", day3::sum_part_numbers().1), + "day4a" => println!("Sum: {}", day4::get_card_points().0), + "day4b" => println!("Sum: {}", day4::get_card_points().1), _ => println!("Unrecognized day: {}", args[1]), } }