• 21 Posts
  • 276 Comments
Joined 1 year ago
cake
Cake day: June 18th, 2023

help-circle
  • Rust

    Hardest part was parsing the input, i somehow forgot how regexes work and wasted hours.

    Learning how to do matrix stuff in rust was a nice detour as well.

    #[cfg(test)]
    mod tests {
        use nalgebra::{Matrix2, Vector2};
        use regex::Regex;
    
        fn play_game(ax: i128, ay: i128, bx: i128, by: i128, gx: i128, gy: i128) -> i128 {
            for a_press in 0..100 {
                let rx = gx - ax * a_press;
                let ry = gy - ay * a_press;
                if rx % bx == 0 && ry % by == 0 && rx / bx == ry / by {
                    return a_press * 3 + ry / by;
                }
            }
            0
        }
    
        fn play_game2(ax: i128, ay: i128, bx: i128, by: i128, gx: i128, gy: i128) -> i128 {
            // m * p = g
            // p = m' * g
            // |ax bx|.|a_press| = |gx|
            // |ay by| |b_press|   |gy|
            let m = Matrix2::new(ax as f64, bx as f64, ay as f64, by as f64);
            match m.try_inverse() {
                None => return 0,
                Some(m_inv) => {
                    let g = Vector2::new(gx as f64, gy as f64);
                    let p = m_inv * g;
                    let pa = p[0].round() as i128;
                    let pb = p[1].round() as i128;
                    if pa * ax + pb * bx == gx && pa * ay + pb * by == gy {
                        return pa * 3 + pb;
                    }
                }
            };
            0
        }
    
        #[test]
        fn day13_part1_test() {
            let input = std::fs::read_to_string("src/input/day_13.txt").unwrap();
            let re = Regex::new(r"[0-9]+").unwrap();
    
            let games = input
                .trim()
                .split("\n\n")
                .map(|line| {
                    re.captures_iter(line)
                        .map(|x| {
                            let first = x.get(0).unwrap().as_str();
                            first.parse::<i128>().unwrap()
                        })
                        .collect::<Vec<i128>>()
                })
                .collect::<Vec<Vec<i128>>>();
    
            let mut total = 0;
            for game in games {
                let cost = play_game2(game[0], game[1], game[2], game[3], game[4], game[5]);
                total += cost;
            }
            // 36870
            println!("{}", total);
        }
    
        #[test]
        fn day12_part2_test() {
            let input = std::fs::read_to_string("src/input/day_13.txt").unwrap();
            let re = Regex::new(r"[0-9]+").unwrap();
    
            let games = input
                .trim()
                .split("\n\n")
                .map(|line| {
                    re.captures_iter(line)
                        .map(|x| {
                            let first = x.get(0).unwrap().as_str();
                            first.parse::<i128>().unwrap()
                        })
                        .collect::<Vec<i128>>()
                })
                .collect::<Vec<Vec<i128>>>();
    
            let mut total = 0;
            for game in games {
                let cost = play_game2(
                    game[0],
                    game[1],
                    game[2],
                    game[3],
                    game[4] + 10000000000000,
                    game[5] + 10000000000000,
                );
                total += cost;
            }
            println!("{}", total);
        }
    }
    






  • CameronDev@programming.devtoSelfhosted@lemmy.worldMy thoughts on docker
    link
    fedilink
    English
    arrow-up
    9
    arrow-down
    1
    ·
    1 day ago

    Are you using docker compose scripts? Backup should be easy, you have your compose scripts to configure the containers, then the scripts can easily be commited somewhere or backed up.

    Data should be volume mounted into the container, and then the host disk can be backed up.

    The only app that I’ve had to fight docker on is Seafile, and even that works quite well now.











  • Rust

    Definitely a nice and easy one, I accidentally solved part 2 first, because I skimmed the challenge and missed the unique part.

    #[cfg(test)]
    mod tests {
    
        const DIR_ORDER: [(i8, i8); 4] = [(-1, 0), (0, 1), (1, 0), (0, -1)];
    
        fn walk_trail(board: &Vec<Vec<i8>>, level: i8, i: i8, j: i8) -> Vec<(i8, i8)> {
            let mut paths = vec![];
            if i < 0 || j < 0 {
                return paths;
            }
            let actual_level = match board.get(i as usize) {
                None => return paths,
                Some(line) => match line.get(j as usize) {
                    None => return paths,
                    Some(c) => c,
                },
            };
            if *actual_level != level {
                return paths;
            }
            if *actual_level == 9 {
                return vec![(i, j)];
            }
    
            for dir in DIR_ORDER.iter() {
                paths.extend(walk_trail(board, level + 1, i + dir.0, j + dir.1));
            }
            paths
        }
    
        fn count_unique(p0: &Vec<(i8, i8)>) -> u32 {
            let mut dedup = vec![];
            for p in p0.iter() {
                if !dedup.contains(p) {
                    dedup.push(*p);
                }
            }
            dedup.len() as u32
        }
    
        #[test]
        fn day10_part1_test() {
            let input = std::fs::read_to_string("src/input/day_10.txt").unwrap();
    
            let board = input
                .trim()
                .split('\n')
                .map(|line| {
                    line.chars()
                        .map(|c| {
                            if c == '.' {
                                -1
                            } else {
                                c.to_digit(10).unwrap() as i8
                            }
                        })
                        .collect::<Vec<i8>>()
                })
                .collect::<Vec<Vec<i8>>>();
    
            let mut total = 0;
    
            for (i, row) in board.iter().enumerate() {
                for (j, pos) in row.iter().enumerate() {
                    if *pos == 0 {
                        let all_trails = walk_trail(&board, 0, i as i8, j as i8);
                        total += count_unique(&all_trails);
                    }
                }
            }
    
            println!("{}", total);
        }
        #[test]
        fn day10_part2_test() {
            let input = std::fs::read_to_string("src/input/day_10.txt").unwrap();
    
            let board = input
                .trim()
                .split('\n')
                .map(|line| {
                    line.chars()
                        .map(|c| {
                            if c == '.' {
                                -1
                            } else {
                                c.to_digit(10).unwrap() as i8
                            }
                        })
                        .collect::<Vec<i8>>()
                })
                .collect::<Vec<Vec<i8>>>();
    
            let mut total = 0;
    
            for (i, row) in board.iter().enumerate() {
                for (j, pos) in row.iter().enumerate() {
                    if *pos == 0 {
                        total += walk_trail(&board, 0, i as i8, j as i8).len();
                    }
                }
            }
    
            println!("{}", total);
        }
    }
    




  • Found a cheaty way to get sub 1s:

        fn defrag2(p0: &mut [i64]) {
            let mut i = *p0.last().unwrap();
            while i > 3000 {  // Stop defragging here, probably cant find free spots after this point
                let (old_pos, size) = find_file(p0, i);
                if let Some(new_pos) = find_slot(p0, size, old_pos) {
                    move_file(p0, i, size, old_pos, new_pos);
                }
                i -= 1;
            }
        }
    

    Might be possible to correctly do this in the find_slot code, so that if it fails to find a slot, it never searches for that size again.

    edit:

    fn defrag2(p0: &mut [i64]) {
            let mut i = *p0.last().unwrap();
            let mut max_size = 10;
            while i > 0 {
                let (old_pos, size) = find_file(p0, i);
                if size <= max_size {
                    if let Some(new_pos) = find_slot(p0, size, old_pos) {
                        move_file(p0, i, size, old_pos, new_pos);
                    } else {
                        max_size = size - 1;
                    }
                }
                if max_size == 0 {
                    return;
                }
                i -= 1;
            }
        }
    

    500ms, I can go to sleep now.


  • Rust

    Pretty poor performance on part 2, was initially 10s, got down to 2.5s, but still seems pretty poor.

    #[cfg(test)]
    mod tests {
        fn checksum(p0: &[i64]) -> i64 {
            let mut csum = 0;
            for (i, val) in p0.iter().enumerate() {
                if *val == -1 {
                    continue;
                }
                csum += *val * (i as i64);
            }
            csum
        }
    
        fn defrag(p0: &[i64]) -> Vec<i64> {
            let mut start = 0;
            let mut end = p0.len() - 1;
    
            let mut defragged = vec![];
    
            while start != end + 1 {
                if p0[start] != -1 {
                    defragged.push(p0[start]);
                    start += 1;
                    continue;
                }
                if p0[start] == -1 {
                    defragged.push(p0[end]);
                    start += 1;
                    end -= 1;
                    while p0[end] == -1 {
                        end -= 1;
                    }
                }
            }
            defragged
        }
    
        fn expand_disk(p0: &str) -> Vec<i64> {
            let mut disk = vec![];
            let mut file_index = 0;
            let mut is_file = true;
            for char in p0.chars() {
                let val = char.to_digit(10).unwrap();
                if is_file {
                    for _ in 0..val {
                        disk.push(file_index)
                    }
                    file_index += 1;
                } else {
                    for _ in 0..val {
                        disk.push(-1)
                    }
                }
                is_file = !is_file;
            }
            disk
        }
        #[test]
        fn day9_part1_test() {
            let input: String = std::fs::read_to_string("src/input/day_9.txt")
                .unwrap()
                .trim()
                .into();
    
            let disk: Vec<i64> = expand_disk(&input);
    
            let defraged = defrag(&disk);
    
            let checksum = checksum(&defraged);
    
            println!("{}", checksum);
        }
    
        fn find_file(p0: &[i64], file: i64) -> (usize, usize) {
            let mut count = 0;
            let mut i = p0.len() - 1;
            while i > 0 && p0[i] != file {
                i -= 1;
            }
            // At end of file
            while i > 0 && p0[i] == file {
                count += 1;
                i -= 1;
            }
            (i + 1, count)
        }
    
        fn find_slot(p0: &[i64], size: usize, end: usize) -> Option<usize> {
            let mut i = 0;
            while i < end {
                while p0[i] != -1 && i < end {
                    i += 1;
                }
                let mut count = 0;
                while p0[i] == -1 && i < end {
                    i += 1;
                    count += 1;
                    if count == size {
                        return Some(i - count);
                    }
                }
            }
            None
        }
    
        fn move_file(p0: &mut [i64], file: i64, size: usize, old_pos: usize, new_pos: usize) {
            for i in 0..size {
                p0[old_pos + i] = -1;
                p0[new_pos + i] = file;
            }
        }
    
        fn defrag2(p0: &mut [i64]) {
            let mut i = *p0.last().unwrap();
            while i > 0 {
                let (old_pos, size) = find_file(p0, i);
                match find_slot(p0, size, old_pos) {
                    None => {}
                    Some(new_pos) => {
                        if new_pos < old_pos {
                            move_file(p0, i, size, old_pos, new_pos);
                        }
                    }
                }
                i -= 1;
            }
        }
    
        #[test]
        fn day9_part2_test() {
            let input: String = std::fs::read_to_string("src/input/day_9.txt")
                .unwrap()
                .trim()
                .into();
    
            let mut disk: Vec<i64> = expand_disk(&input);
    
            defrag2(&mut disk);
    
            let checksum = checksum(&disk);
    
            println!("{}", checksum);
        }
    }
    
    


  • Rust

    For the first time, I can post my solution, because I actually solved it on the day :D Probably not the cleanest or optimal solution, but it does solve the problem.

    Very long, looking forward to someone solving it in 5 lines of unicode :D

    #[cfg(test)]
    mod tests {
    
        fn get_frequences(input: &str) -> Vec<char> {
            let mut freq = vec![];
            for char in input.chars() {
                if char == '.' {
                    continue;
                }
                if !freq.contains(&char) {
                    freq.push(char);
                }
            }
            freq
        }
    
        fn find_antennas(board: &Vec<Vec<char>>, freq: char) -> Vec<(isize, isize)> {
            let mut antennas = vec![];
            for (i, line) in board.iter().enumerate() {
                for (j, char) in line.iter().enumerate() {
                    if *char == freq {
                        antennas.push((i as isize, j as isize));
                    }
                }
            }
            antennas
        }
    
        fn calc_antinodes(first: &(isize, isize), second: &(isize, isize)) -> Vec<(isize, isize)> {
            let deltax = second.0 - first.0;
            let deltay = second.1 - first.1;
    
            if deltax == 0 && deltay == 0 {
                return vec![];
            }
    
            vec![
                (first.0 - deltax, first.1 - deltay),
                (second.0 + deltax, second.1 + deltay),
            ]
        }
    
        #[test]
        fn test_calc_antinodes() {
            let expected = vec![(0, -1), (0, 2)];
            let actual = calc_antinodes(&(0, 0), &(0, 1));
            for i in &expected {
                assert!(actual.contains(i));
            }
            let actual = calc_antinodes(&(0, 1), &(0, 0));
            for i in &expected {
                assert!(actual.contains(i));
            }
        }
    
        fn calc_all_antinodes(board: &Vec<Vec<char>>, freq: char) -> Vec<(isize, isize)> {
            let antennas = find_antennas(&board, freq);
    
            let mut antinodes = vec![];
    
            for (i, first) in antennas.iter().enumerate() {
                for second in antennas[i..].iter() {
                    antinodes.extend(calc_antinodes(first, second));
                }
            }
    
            antinodes
        }
    
        fn prune_nodes(
            nodes: &Vec<(isize, isize)>,
            height: isize,
            width: isize,
        ) -> Vec<(isize, isize)> {
            let mut pruned = vec![];
            for node in nodes {
                if pruned.contains(node) {
                    continue;
                }
                if node.0 < 0 || node.0 >= height {
                    continue;
                }
                if node.1 < 0 || node.1 >= width {
                    continue;
                }
                pruned.push(node.clone());
            }
            pruned
        }
    
        fn print_board(board: &Vec<Vec<char>>, pruned: &Vec<(isize, isize)>) {
            for (i, line) in board.iter().enumerate() {
                for (j, char) in line.iter().enumerate() {
                    if pruned.contains(&(i as isize, j as isize)) {
                        print!("#");
                    } else {
                        print!("{char}");
                    }
                }
                println!();
            }
        }
    
        #[test]
        fn day8_part1_test() {
            let input: String = std::fs::read_to_string("src/input/day_8.txt").unwrap();
    
            let frequencies = get_frequences(&input);
    
            let board = input
                .trim()
                .split('\n')
                .map(|line| line.chars().collect::<Vec<char>>())
                .collect::<Vec<Vec<char>>>();
    
            let mut all_nodes = vec![];
            for freq in frequencies {
                let nodes = calc_all_antinodes(&board, freq);
                all_nodes.extend(nodes);
            }
    
            let height = board.len() as isize;
            let width = board[0].len() as isize;
    
            let pruned = prune_nodes(&all_nodes, height, width);
    
            println!("{:?}", pruned);
    
            print_board(&board, &pruned);
    
            println!("{}", pruned.len());
    
            // 14 in test
        }
    
        fn calc_antinodes2(first: &(isize, isize), second: &(isize, isize)) -> Vec<(isize, isize)> {
            let deltax = second.0 - first.0;
            let deltay = second.1 - first.1;
    
            if deltax == 0 && deltay == 0 {
                return vec![];
            }
            let mut nodes = vec![];
            for n in 0..50 {
                nodes.push((first.0 - deltax * n, first.1 - deltay * n));
                nodes.push((second.0 + deltax * n, second.1 + deltay * n));
            }
    
            nodes
        }
    
        fn calc_all_antinodes2(board: &Vec<Vec<char>>, freq: char) -> Vec<(isize, isize)> {
            let antennas = find_antennas(&board, freq);
    
            let mut antinodes = vec![];
    
            for (i, first) in antennas.iter().enumerate() {
                for second in antennas[i..].iter() {
                    antinodes.extend(calc_antinodes2(first, second));
                }
            }
    
            antinodes
        }
    
        #[test]
        fn day8_part2_test() {
            let input: String = std::fs::read_to_string("src/input/day_8.txt").unwrap();
    
            let frequencies = get_frequences(&input);
    
            let board = input
                .trim()
                .split('\n')
                .map(|line| line.chars().collect::<Vec<char>>())
                .collect::<Vec<Vec<char>>>();
    
            let mut all_nodes = vec![];
            for freq in frequencies {
                let nodes = calc_all_antinodes2(&board, freq);
                all_nodes.extend(nodes);
            }
    
            let height = board.len() as isize;
            let width = board[0].len() as isize;
    
            let pruned = prune_nodes(&all_nodes, height, width);
    
            println!("{:?}", pruned);
    
            print_board(&board, &pruned);
    
            println!("{}", pruned.len());
        }
    }