• 0 Posts
  • 28 Comments
Joined 2 years ago
cake
Cake day: July 5th, 2023

help-circle

  • I did run your code as-is in an ipython REPL to check. These were the results:

    REPL session
    # With unmodified `main` function & `import string` not shown
    In [4]: with open("inputs/day13.txt", "r") as f:
       ...:     input_data = f.read().strip().replace(',', '').split('\n\n')
       ...:
    
    In [5]: part_one, part_two = main(input_data)
    
    In [6]: part_one
    Out[6]: 39748
    
    In [7]: part_two
    Out[7]: 74926346266863
    
    # Then I modified the function to check if x is fractional
    In [8]: def main(input_data):
       ...:     part1_total_cost = 0
       ...:     part2_total_cost = 0
       ...:     for machine in input_data:
       ...:         Ax,Ay,Bx,By,Px,Py = [ int(l[2:]) for l in machine.split() if l[-1] in string.digits ]
       ...:         y,r = divmod((Ay * Px - Ax * Py), (Ay * Bx - Ax * By))
       ...:         if r == 0:
       ...:             x = (Px - Bx * y) / Ax
       ...:             if x % 1 == 0:
       ...:                 part1_total_cost += 3*x + y
       ...:         y,r = divmod((Ay * (Px+10000000000000) - Ax * (Py+10000000000000)), (Ay * Bx - Ax * By))
       ...:         if r == 0:
       ...:             x = ((Px+10000000000000) - Bx * y) / Ax
       ...:             if x % 1 == 0:
       ...:                 part2_total_cost += 3*x + y
       ...:
       ...:     return part1_total_cost,part2_total_cost
       ...:
    
    In [9]: part_one, part_two = main(input_data)
    
    In [10]: part_one
    Out[10]: 39748.0
    
    In [11]: part_two
    Out[11]: 74478585072604.0  # Correct answer for pt 2 of my input
    

    If you’re curious to check against my puzzle input, it’s here

    Thank you again for the back & forth, and for sharing your solution!





  • Rust

    Real thinker. Messed around with a couple solutions before this one. The gist is to take all the pairwise comparisons given and record them for easy access in a ranking matrix.

    For the sample input, this grid would look like this (I left out all the non-present integers, but it would be a 98 x 98 grid where all the empty spaces are filled with Ordering::Equal):

       13 29 47 53 61 75 97
    13  =  >  >  >  >  >  >
    29  <  =  >  >  >  >  >
    47  <  <  =  <  <  >  >
    53  <  <  >  =  >  >  >
    61  <  <  >  <  =  >  >
    75  <  <  <  <  <  =  >
    97  <  <  <  <  <  <  =
    

    I discovered this can’t be used for a total order on the actual puzzle input because there were cycles in the pairs given (see how rust changed sort implementations as of 1.81). I used usize for convenience (I did it with u8 for all the pair values originally, but kept having to cast over and over as usize). Didn’t notice a performance difference, but I’m sure uses a bit more memory.

    Also I Liked the simple_grid crate a little better than the grid one. Will have to refactor that out at some point.

    solution
    use std::{cmp::Ordering, fs::read_to_string};
    
    use simple_grid::Grid;
    
    type Idx = (usize, usize);
    type Matrix = Grid<Ordering>;
    type Page = Vec<usize>;
    
    fn parse_input(input: &str) -> (Vec<Idx>, Vec<Page>) {
        let split: Vec<&str> = input.split("\n\n").collect();
        let (pair_str, page_str) = (split[0], split[1]);
        let pairs = parse_pairs(pair_str);
        let pages = parse_pages(page_str);
        (pairs, pages)
    }
    
    fn parse_pairs(input: &str) -> Vec<Idx> {
        input
            .lines()
            .map(|l| {
                let (a, b) = l.split_once('|').unwrap();
                (a.parse().unwrap(), b.parse().unwrap())
            })
            .collect()
    }
    
    fn parse_pages(input: &str) -> Vec<Page> {
        input
            .lines()
            .map(|l| -> Page {
                l.split(",")
                    .map(|d| d.parse::<usize>().expect("invalid digit"))
                    .collect()
            })
            .collect()
    }
    
    fn create_matrix(pairs: &[Idx]) -> Matrix {
        let max = *pairs
            .iter()
            .flat_map(|(a, b)| [a, b])
            .max()
            .expect("iterator is non-empty")
            + 1;
        let mut matrix = Grid::new(max, max, vec![Ordering::Equal; max * max]);
        for (a, b) in pairs {
            matrix.replace_cell((*a, *b), Ordering::Less);
            matrix.replace_cell((*b, *a), Ordering::Greater);
        }
        matrix
    }
    
    fn valid_pages(pages: &[Page], matrix: &Matrix) -> usize {
        pages
            .iter()
            .filter_map(|p| {
                if check_order(p, matrix) {
                    Some(p[p.len() / 2])
                } else {
                    None
                }
            })
            .sum()
    }
    
    fn fix_invalid_pages(pages: &mut [Page], matrix: &Matrix) -> usize {
        pages
            .iter_mut()
            .filter(|p| !check_order(p, matrix))
            .map(|v| {
                v.sort_by(|a, b| *matrix.get((*a, *b)).unwrap());
                v[v.len() / 2]
            })
            .sum()
    }
    
    fn check_order(page: &[usize], matrix: &Matrix) -> bool {
        page.is_sorted_by(|a, b| *matrix.get((*a, *b)).unwrap() == Ordering::Less)
    }
    
    pub fn solve() {
        let input = read_to_string("inputs/day05.txt").expect("read file");
        let (pairs, mut pages) = parse_input(&input);
        let matrix = create_matrix(&pairs);
        println!("Part 1: {}", valid_pages(&pages, &matrix));
        println!("Part 2: {}", fix_invalid_pages(&mut pages, &matrix));
    }
    

    On github

    *Edit: I did try switching to just using std::collections::HashMap, but it was 0.1 ms slower on average than using the simple_grid::GridVec[idx] access is faster maybe?


  • Rust

    Ugh. Spent way too long on today’s. Should have just used my own grid structure from last year. I will likely refactor to use that. Even though it’s likely a super slow implementation, the convenience of dealing with it is better than shoehorning in the grid::Grid<T> from that crate.

    solution (no supporting code)
    use grid::Grid;
    
    use crate::shared::{
        grid2d::{iter_diag_nesw, iter_diag_nwse, Point},
        util::read_lines,
    };
    
    fn parse_grid(input: &[String]) -> Grid<u8> {
        let cols = input.first().unwrap().len();
        Grid::from_vec(
            input
                .iter()
                .flat_map(|row| row.chars().map(|c| c as u8).collect::<Vec<u8>>())
                .collect(),
            cols,
        )
    }
    
    fn part1(grid: &Grid<u8>) -> usize {
        let mut xmas_count = 0;
        let rows = grid
            .iter_rows()
            .map(|d| String::from_utf8(d.copied().collect()).unwrap());
        let cols = grid
            .iter_cols()
            .map(|d| String::from_utf8(d.copied().collect()).unwrap());
        for diag in iter_diag_nesw(grid)
            .chain(iter_diag_nwse(grid))
            .filter_map(|d| {
                if d.len() >= 4 {
                    Some(String::from_utf8(d.clone()).unwrap())
                } else {
                    None
                }
            })
            .chain(rows)
            .chain(cols)
        {
            xmas_count += diag.matches("XMAS").count() + diag.matches("SAMX").count()
        }
        xmas_count
    }
    
    fn part2(grid: &Grid<u8>) -> usize {
        let mut xmas_count = 0;
        let valid = [
            [b'M', b'M', b'S', b'S'],
            [b'M', b'S', b'S', b'M'],
            [b'S', b'M', b'M', b'S'],
            [b'S', b'S', b'M', b'M'],
        ];
        for x in 1..grid.cols() - 1 {
            for y in 1..grid.rows() - 1 {
                if grid.get(y, x) == Some(&b'A')
                    && valid.contains(
                        &(Point::new(x as isize, y as isize)
                            .diagonal_neighbors(grid)
                            .map(|i| i.unwrap_or(0))),
                    )
                {
                    xmas_count += 1;
                }
            }
        }
        xmas_count
    }
    
    pub fn solve() {
        let input = read_lines("inputs/day04.txt");
        let grid = parse_grid(&input);
        println!("Part 1: {}", part1(&grid));
        println!("Part 2: {}", part2(&grid));
    }
    

    And here’s a link to the Github if you care to see the gross supporting code :D


  • Rust

    Didn’t do anything crazy here – ended up using regex like a bunch of other folks.

    solution
    use regex::Regex;
    
    use crate::shared::util::read_lines;
    
    fn parse_mul(input: &[String]) -> (u32, u32) {
        // Lazy, but rejoin after having removed `\n`ewlines.
        let joined = input.concat();
        let re = Regex::new(r"mul\((\d+,\d+)\)|(do\(\))|(don't\(\))").expect("invalid regex");
    
        // part1
        let mut total1 = 0u32;
        // part2 -- adds `do()`s and `don't()`s
        let mut total2 = 0u32;
        let mut enabled = 1u32;
    
        re.captures_iter(&joined).for_each(|c| {
            let (_, [m]) = c.extract();
            match m {
                "do()" => enabled = 1,
                "don't()" => enabled = 0,
                _ => {
                    let product: u32 = m.split(",").map(|s| s.parse::<u32>().unwrap()).product();
                    total1 += product;
                    total2 += product * enabled;
                }
            }
        });
        (total1, total2)
    }
    
    pub fn solve() {
        let input = read_lines("inputs/day03.txt");
        let (part1_res, part2_res) = parse_mul(&input);
        println!("Part 1: {}", part1_res);
        println!("Part 2: {}", part2_res);
    }
    
    #[cfg(test)]
    mod test {
        use super::*;
    
        #[test]
        fn test_solution() {
            let test_input = vec![
                "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))".to_string(),
            ];
            let (p1, p2) = parse_mul(&test_input);
            eprintln!("P1: {p1}, P2: {p2}");
            assert_eq!(161, p1);
            assert_eq!(48, p2);
        }
    }
    
    

    Solution on my github (Made it public now)






  • Neovim Is a highly customizable, modal text editor program. Probably no what you’re looking for as far as terninal emulators go, but I use it daily as a near-IDE on desktop. Look into LazyVim for an easy way to get started.

    I can second KDE connect–use it between my phone and Manjaro. Can’t speak to the other applications because I don’t have a use-case for many of their functions on a smart phone myself.


  • Am I one of the few who just doesn’t use AI at all? I don’t have to generate tons of code for work at the moment and brand new projects that I’ve been given are small–meaning I wouldn’t necessarily use it to generate starter boilerplate. I have coworkers that love copilot or spend much longer prompting ChatGPT than they would if they wrote code themselves. A majority of my time is spent modelling the problem, gathering rejuirements, researching others’ solutions online (likely this step could be better AI-assisted?), not actually implementing a solution in code.

    Anyway, I’m not super anti-AI in software development, and I see where it could be useful. Maybe it just isn’t for me yet. The current hype around it as well as the attitude of big-tech exceptionalism (“AI can salve all our problems”) feels a bit like a bubble, at least regarding the current generation of LLMs and ML