Zytkowski's Thought Dumpster

Advent of Code 2023 - Day 04

I'ts that time of year again, the Advent of Code! I'm completing the challenges this year using Rust 🦀 Day 4 was really interesting!

I'll be posting them here, just to document how I'm solving each challenge, and I highly encourage you to check them out before reading my solutions!

Here's the Day 4 Challenge

BTW: Complete Part 1 to have access to Part 2 😉

Solution for Part 1

use std::fs::File;
use std::io::{BufRead, BufReader, Lines, Result};
use std::path::Path;
use std::str::FromStr;

fn main() {
    let input_file_path = "path_to_input_file";
    let mut curr_sum = 0;
    let iterator = for_each_line(input_file_path)
        .unwrap_or_else(|_| panic!("Could not find input file {}", input_file_path));
    for line in iterator.flatten() {
        if let Some((_, remainder)) = line.split_once(':') {
            if let Some((winning_numbers, elf_numbers)) = remainder.trim().split_once('|') {
                let mut score = 0;
                let winning_numbers: Vec<i32> = parse_list(winning_numbers.trim());
                let elf_numbers: Vec<i32> = parse_list(elf_numbers.trim());
                for winning_number in winning_numbers {
                    if elf_numbers.contains(&winning_number) {
                        if score == 0 {
                            score = 1;
                        } else {
                            score = score * 2;
                        }
                    }
                }
                curr_sum += score;
            }
        }
    }
    println!("Score of entire pile: {}", curr_sum);
}

fn parse_list(list_as_str: &str) -> Vec<i32> {
    return list_as_str.split(' ').filter(|str| !str.is_empty()).map(|str| {
        i32::from_str(str.trim()).unwrap_or_else(|_| panic!("{} is not a valid i32.", str))
    }).collect();
}


fn for_each_line<P: AsRef<Path>>(filename: P) -> Result<Lines<BufReader<File>>> {
    let file = File::open(filename)?;
    Ok(BufReader::new(file).lines())
}

Solution for Part 2

use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader, Lines, Result};
use std::path::Path;
use std::str::FromStr;

fn main() {
    let input_file_path = "path_to_your_input_file";
    let mut curr_sum = 0;
    let iterator = for_each_line(input_file_path)
        .unwrap_or_else(|_| panic!("Could not find input file {}", input_file_path));
    let mut map_of_scratchcards: HashMap<i32, i32> = HashMap::new();

    for line in iterator.flatten() {
        let (card_id, remainder) = line.split_once(':').unwrap();
        let (_, card_id) = card_id.split_once(' ').unwrap();
        let card_id = i32::from_str(card_id.trim())
            .unwrap_or_else(|_| panic!("{} is not a valid i32 for card name", card_id));
        map_of_scratchcards.entry(card_id).or_insert(1);
        let (winning_numbers, elf_numbers) = remainder.trim()
            .split_once('|').unwrap();
        let mut matching_numbers = 0;
        let winning_numbers: Vec<i32> = parse_list(winning_numbers.trim());
        let elf_numbers: Vec<i32> = parse_list(elf_numbers.trim());
        for winning_number in winning_numbers {
            if elf_numbers.contains(&winning_number) {
                matching_numbers += 1;
            }
        }
        let current_cards = *map_of_scratchcards.entry(card_id).or_insert(1);
        for _ in (0..current_cards).rev() {
            for future_card in card_id+1..=card_id+matching_numbers {
                map_of_scratchcards.entry(future_card).or_insert(1);
                let curr_card_amount = map_of_scratchcards.get(&future_card).unwrap();
                map_of_scratchcards.insert(future_card, curr_card_amount + 1);
            }
            curr_sum += 1;
        }
    }
    println!("Sum of all winning cards: {}", curr_sum);
}

fn parse_list(list_as_str: &str) -> Vec<i32> {
    return list_as_str.split(' ').filter(|str| !str.is_empty()).map(|str| {
        i32::from_str(str.trim()).unwrap_or_else(|_| panic!("{} is not a valid i32.", str))
    }).collect();
}


fn for_each_line<P: AsRef<Path>>(filename: P) -> Result<Lines<BufReader<File>>> {
    let file = File::open(filename)?;
    Ok(BufReader::new(file).lines())
}