Break each day out into a module.

This commit is contained in:
Drew Galbraith 2023-12-04 13:41:42 -08:00
parent 3ec015ab70
commit 9e63330189
5 changed files with 342 additions and 336 deletions

98
src/day1.rs Normal file
View File

@ -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<u32> = 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<usize> = 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
}

55
src/day2.rs Normal file
View File

@ -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)
}

127
src/day3.rs Normal file
View File

@ -0,0 +1,127 @@
use std::collections::HashMap;
use std::io;
fn record_gear(num: u32, gear: usize, gears: &mut HashMap<usize, Vec<u32>>) {
match gears.get_mut(&gear) {
None => {
let mut vec: Vec<u32> = 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<String>,
n: u32,
mut gears: &mut HashMap<usize, Vec<u32>>,
) -> 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<char> = &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<char> = &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<char> = &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<String> = 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)
}

50
src/day4.rs Normal file
View File

@ -0,0 +1,50 @@
use std::{collections::HashSet, io};
fn parse_num_list(num_str: &str) -> HashSet<u32> {
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<u32> = 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())
}

View File

@ -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<u32> = 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<usize> = 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<usize, Vec<u32>>) {
println!("Gear {}", gear);
match gears.get_mut(&gear) {
None => {
let mut vec: Vec<u32> = 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<String>,
n: u32,
mut gears: &mut HashMap<usize, Vec<u32>>,
) -> 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<char> = &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<char> = &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<char> = &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<String> = 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<u32> {
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<u32> = 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<String> = 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]),
}
}