Sleepless One

Insomniac code gorilla. I help maintain lemmy-ui and, to a lesser extent, Lemmy’s backend.

Github

  • 9 Posts
  • 75 Comments
Joined 8 months ago
cake
Cake day: April 21st, 2024

help-circle







  • KINGDOM OF CONSCIENCE

    Moralists don’t really have beliefs. Sometimes they stumble on one, like on a child’s toy left on the carpet. The toy must be put away immediately. And the child reprimanded. Centrism isn’t change – not even incremental change. It is control. Over yourself and the world. Exercise it. Look up at the sky, at the dark shapes of Coalition airships hanging there. Ask yourself: is there something sinister in moralism? And then answer: no. God is in his heaven. Everything is normal on Earth.


  • Rust

    Kinda sorta got day 5 done on time.

    use std::cmp::Ordering;
    
    use crate::utils::{bytes_to_num, read_lines};
    
    pub fn solution1() {
        let mut lines = read_input();
        let rules = parse_rules(&mut lines);
    
        let middle_rules_sum = lines
            .filter_map(|line| {
                let line_nums = rule_line_to_list(&line);
                line_nums
                    .is_sorted_by(|&a, &b| is_sorted(&rules, (a, b)))
                    .then_some(line_nums[line_nums.len() / 2])
            })
            .sum::<usize>();
    
        println!("Sum of in-order middle rules = {middle_rules_sum}");
    }
    
    pub fn solution2() {
        let mut lines = read_input();
        let rules = parse_rules(&mut lines);
    
        let middle_rules_sum = lines
            .filter_map(|line| {
                let mut line_nums = rule_line_to_list(&line);
    
                (!line_nums.is_sorted_by(|&a, &b| is_sorted(&rules, (a, b)))).then(|| {
                    line_nums.sort_by(|&a, &b| {
                        is_sorted(&rules, (a, b))
                            .then_some(Ordering::Less)
                            .unwrap_or(Ordering::Greater)
                    });
    
                    line_nums[line_nums.len() / 2]
                })
            })
            .sum::<usize>();
    
        println!("Sum of middle rules = {middle_rules_sum}");
    }
    
    fn read_input() -> impl Iterator<Item = String> {
        read_lines("src/day5/input.txt")
    }
    
    fn parse_rules(lines: &mut impl Iterator<Item = String>) -> Vec<(usize, usize)> {
        lines
            .take_while(|line| !line.is_empty())
            .fold(Vec::new(), |mut rules, line| {
                let (a, b) = line.as_bytes().split_at(2);
                let a = bytes_to_num(a);
                let b = bytes_to_num(&b[1..]);
    
                rules.push((a, b));
    
                rules
            })
    }
    
    fn rule_line_to_list(line: &str) -> Vec<usize> {
        line.split(',')
            .map(|s| bytes_to_num(s.as_bytes()))
            .collect::<Vec<_>>()
    }
    
    fn is_sorted(rules: &[(usize, usize)], tuple: (usize, usize)) -> bool {
        rules.iter().any(|&r| r == tuple)
    }
    

    Reusing my bytes_to_num function from day 3 feels nice. Pretty fun challenge.


  • Rust

    I’m a day behind on this one due to a lot of work with my job and school.

    use std::iter::zip;
    
    use crate::utils::read_lines;
    
    pub fn solution1() {
        let puzzle = read_puzzle();
    
        let horizontal_sum = puzzle
            .iter()
            .map(|line| {
                line.windows(4)
                    .filter(|window| {
                        matches!(window, [b'X', b'M', b'A', b'S'] | [b'S', b'A', b'M', b'X'])
                    })
                    .count() as u32
            })
            .sum::<u32>();
        let vertical_and_diagonal_sum = puzzle
            .windows(4)
            .map(|window| {
                count_xmas(window, (0, 0, 0, 0))
                    + count_xmas(window, (0, 1, 2, 3))
                    + count_xmas(window, (3, 2, 1, 0))
            })
            .sum::<u32>();
    
        println!(
            "XMAS count = {}",
            horizontal_sum + vertical_and_diagonal_sum
        );
    }
    
    pub fn solution2() {
        let puzzle = read_puzzle();
    
        let sum = puzzle
            .windows(3)
            .map(|window| {
                zip(
                    window[0].windows(3),
                    zip(window[1].windows(3), window[2].windows(3)),
                )
                .map(|(a, (b, c))| (a, b, c))
                .filter(|tuple| {
                    matches!(
                        tuple,
                        ([b'M', _, b'M'], [_, b'A', _], [b'S', _, b'S'])
                            | ([b'S', _, b'M'], [_, b'A', _], [b'S', _, b'M'])
                            | ([b'M', _, b'S'], [_, b'A', _], [b'M', _, b'S'])
                            | ([b'S', _, b'S'], [_, b'A', _], [b'M', _, b'M'])
                    )
                })
                .count() as u32
            })
            .sum::<u32>();
    
        println!("X-MAS count = {sum}");
    }
    
    fn count_xmas(
        window: &[Vec<u8>],
        (skip0, skip1, skip2, skip3): (usize, usize, usize, usize),
    ) -> u32 {
        zip(
            window[0].iter().skip(skip0),
            zip(
                window[1].iter().skip(skip1),
                zip(window[2].iter().skip(skip2), window[3].iter().skip(skip3)),
            ),
        )
        .map(|(a, (b, (c, d)))| (a, b, c, d))
        .filter(|tup| matches!(tup, (b'X', b'M', b'A', b'S') | (b'S', b'A', b'M', b'X')))
        .count() as u32
    }
    
    fn read_puzzle() -> Vec<Vec<u8>> {
        read_lines("src/day4/input.txt")
            .map(|line| line.into_bytes())
            .collect()
    }
    

    The standard library windows method and pattern matching have been carrying me this year so far.


  • Rust

    use crate::utils::read_lines;
    
    pub fn solution1() {
        let lines = read_lines("src/day3/input.txt");
        let sum = lines
            .map(|line| {
                let mut sum = 0;
                let mut command_bytes = Vec::new();
                for byte in line.bytes() {
                    match (byte, command_bytes.as_slice()) {
                        (b')', [.., b'0'..=b'9']) => {
                            handle_mul(&mut command_bytes, &mut sum);
                        }
                        _ if matches_mul(byte, &command_bytes) => {
                            command_bytes.push(byte);
                        }
                        _ => {
                            command_bytes.clear();
                        }
                    }
                }
    
                sum
            })
            .sum::<usize>();
    
        println!("Sum of multiplication results = {sum}");
    }
    
    pub fn solution2() {
        let lines = read_lines("src/day3/input.txt");
    
        let mut can_mul = true;
        let sum = lines
            .map(|line| {
                let mut sum = 0;
                let mut command_bytes = Vec::new();
                for byte in line.bytes() {
                    match (byte, command_bytes.as_slice()) {
                        (b')', [.., b'0'..=b'9']) if can_mul => {
                            handle_mul(&mut command_bytes, &mut sum);
                        }
                        (b')', [b'd', b'o', b'(']) => {
                            can_mul = true;
                            command_bytes.clear();
                        }
                        (b')', [.., b't', b'(']) => {
                            can_mul = false;
                            command_bytes.clear();
                        }
                        _ if matches_do_or_dont(byte, &command_bytes)
                            || matches_mul(byte, &command_bytes) =>
                        {
                            command_bytes.push(byte);
                        }
                        _ => {
                            command_bytes.clear();
                        }
                    }
                }
    
                sum
            })
            .sum::<usize>();
    
        println!("Sum of enabled multiplication results = {sum}");
    }
    
    fn matches_mul(byte: u8, command_bytes: &[u8]) -> bool {
        matches!(
            (byte, command_bytes),
            (b'm', [])
                | (b'u', [.., b'm'])
                | (b'l', [.., b'u'])
                | (b'(', [.., b'l'])
                | (b'0'..=b'9', [.., b'(' | b'0'..=b'9' | b','])
                | (b',', [.., b'0'..=b'9'])
        )
    }
    
    fn matches_do_or_dont(byte: u8, command_bytes: &[u8]) -> bool {
        matches!(
            (byte, command_bytes),
            (b'd', [])
                | (b'o', [.., b'd'])
                | (b'n', [.., b'o'])
                | (b'\'', [.., b'n'])
                | (b'(', [.., b'o' | b't'])
                | (b't', [.., b'\''])
        )
    }
    
    fn handle_mul(command_bytes: &mut Vec<u8>, sum: &mut usize) {
        let first_num_index = command_bytes
            .iter()
            .position(u8::is_ascii_digit)
            .expect("Guarunteed to be there");
        let comma_index = command_bytes
            .iter()
            .position(|&c| c == b',')
            .expect("Guarunteed to be there.");
    
        let num1 = bytes_to_num(&command_bytes[first_num_index..comma_index]);
        let num2 = bytes_to_num(&command_bytes[comma_index + 1..]);
    
        *sum += num1 * num2;
        command_bytes.clear();
    }
    
    fn bytes_to_num(bytes: &[u8]) -> usize {
        bytes
            .iter()
            .rev()
            .enumerate()
            .map(|(i, digit)| (*digit - b'0') as usize * 10usize.pow(i as u32))
            .sum::<usize>()
    }
    

    Definitely not my prettiest code ever. It would probably look nicer if I used regex or some parsing library, but I took on the self-imposed challenge of not using third party libraries. Also, this is already further than I made it last year!





  • Rust

    use crate::utils::read_lines;
    
    pub fn solution1() {
        let reports = get_reports();
        let safe_reports = reports
            .filter(|report| report.windows(3).all(window_is_valid))
            .count();
    
        println!("Number of safe reports = {safe_reports}");
    }
    
    pub fn solution2() {
        let reports = get_reports();
        let safe_reports = reports
            .filter(|report| {
                (0..report.len()).any(|i| {
                    [&report[0..i], &report[i + 1..]]
                        .concat()
                        .windows(3)
                        .all(window_is_valid)
                })
            })
            .count();
    
        println!("Number of safe reports = {safe_reports}");
    }
    
    fn window_is_valid(window: &[usize]) -> bool {
        matches!(window[0].abs_diff(window[1]), 1..=3)
            && matches!(window[1].abs_diff(window[2]), 1..=3)
            && ((window[0] > window[1] && window[1] > window[2])
                || (window[0] < window[1] && window[1] < window[2]))
    }
    
    fn get_reports() -> impl Iterator<Item = Vec<usize>> {
        read_lines("src/day2/input.txt").map(|line| {
            line.split_ascii_whitespace()
                .map(|level| {
                    level
                        .parse()
                        .expect("Reactor level is always valid integer")
                })
                .collect()
        })
    }
    

    Definitely trickier than yesterday’s. I feel like the windows solution isn’t the best, but it was what came to mind and ended up working for me.



  • Rust

    I’m doing it in Rust again this year. I stopped keeping up with it after day 3 last year, so let’s hope I last longer this time around.

    Solution Spoiler Alert
    use std::collections::HashMap;
    
    use crate::utils::read_lines;
    
    pub fn solution1() {
        let (mut id_list1, mut id_list2) = get_id_lists();
    
        id_list1.sort();
        id_list2.sort();
    
        let total_distance = id_list1
            .into_iter()
            .zip(id_list2)
            .map(|(left, right)| (left - right).abs())
            .sum::<i32>();
    
        println!("Total distance = {total_distance}");
    }
    
    pub fn solution2() {
        let (id_list1, id_list2) = get_id_lists();
    
        let id_count_map = id_list2
            .into_iter()
            .fold(HashMap::<_, i32>::new(), |mut map, id| {
                *map.entry(id).or_default() += 1i32;
    
                map
            });
    
        let similarity_score = id_list1
            .into_iter()
            .map(|id| id * id_count_map.get(&id).copied().unwrap_or_default())
            .sum::<i32>();
    
        println!("Similarity score = {similarity_score}");
    }
    
    fn get_id_lists() -> (Vec<i32>, Vec<i32>) {
        read_lines("src/day1/input.txt")
            .map(|line| {
                let mut ids = line.split_whitespace().map(|id| {
                    id.parse::<i32>()
                        .expect("Ids from input must be valid integers")
                });
    
                (
                    ids.next().expect("First Id on line must be present"),
                    ids.next().expect("Second Id on line must be present"),
                )
            })
            .unzip()
    }
    

    I’m keeping my solutions up on GitHub.




  • I’m lucky that my family doesn’t talk politics much, but I still saw the occasional brainworm. Apparently someone in my family adopted kids from somewhere in Africa and one of my uncles made a comment about how they must have such a better life in America since they don’t need to “hunt baboons” for sustenance. The conversation moved to how when I was a kid a bunch of white people they knew adopted Chinese kids and the same uncle said something to the effect that the Chinese would’ve killed all of those children.

    Another of my uncles is convinced private corporations and the government are hiding the existence of aliens who live under the ocean because of some docuseries he watched on a streaming service.