wycy's recent activity

  1. Comment on What watch do you wear daily? in ~hobbies

    wycy
    Link Parent
    Don't those watches hold value pretty well such that you can resell and get your money back if you now consider it a bad decision?

    Don't those watches hold value pretty well such that you can resell and get your money back if you now consider it a bad decision?

    1 vote
  2. Comment on Day 20: Pulse Propagation in ~comp.advent_of_code

    wycy
    Link Parent
    FYI you can still do future problems without having finished today’s part 2. (Back in 2018 I didn’t realize this and used someone else’s solution to a part 2 in order to continue on subsequent...

    FYI you can still do future problems without having finished today’s part 2. (Back in 2018 I didn’t realize this and used someone else’s solution to a part 2 in order to continue on subsequent days without realizing this wasn’t necessary)

    2 votes
  3. Comment on Someone registered their phone subscription using my email in ~tech

    wycy
    Link
    Someone also used my email address to sign up for a bank account. I contacted the bank to let them know and they told me they couldn’t help me via email, I’d have to call. My take: I’ve already...

    Someone also used my email address to sign up for a bank account. I contacted the bank to let them know and they told me they couldn’t help me via email, I’d have to call. My take: I’ve already done my due diligence by letting the bank know, I’m not going to spend any more of my time on the phone with them.

    I tried to get into the account via password reset but needed to know the DOB of the account holder.

    Unfortunately this person keeps using my address to sign up for newsletters and other junk. I tried emailing what I thought might be her actual email address, to no avail.

    4 votes
  4. Comment on What are your predictions for 2024? in ~talk

    wycy
    Link
    If Biden lives through the election: he loses the presidency to Trump. If Biden dies before the election: Biden is replaced by Newsom, Newsom narrowly defeats Trump.

    If Biden lives through the election: he loses the presidency to Trump.

    If Biden dies before the election: Biden is replaced by Newsom, Newsom narrowly defeats Trump.

  5. Comment on Day 11: Cosmic Expansion in ~comp.advent_of_code

    wycy
    Link
    Rust Day 11 use std::env; use std::io::{self, prelude::*, BufReader}; use std::fs::File; use point2d::point2d::Point2D; extern crate itertools; use itertools::Itertools; // Expand map, where times...

    Rust

    Day 11
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    
    use point2d::point2d::Point2D;
    
    extern crate itertools;
    use itertools::Itertools;
    
    // Expand map, where times parameter is the column multiplier
    // eg. expanding the map doubles (times=2) the width of empty space
    fn expand_map(map: &Vec<Point2D>, times: i64) -> Vec<Point2D> {
        let xmax = map.iter().map(|pt| pt.x).max().unwrap();
        let ymax = map.iter().map(|pt| pt.y).max().unwrap();
    
        // Determine which rows and columns to expand
        let expanded_rows: Vec<_> =
            (0..=ymax)
            .into_iter()
            .filter(|y| {
                (0..=xmax).into_iter().all(|x| !map.contains(&Point2D { x: x, y: *y}))
            })
            .collect();
        let expanded_cols: Vec<_> =
            (0..=xmax)
            .into_iter()
            .filter(|x| {
                (0..=ymax).into_iter().all(|y| !map.contains(&Point2D { x: *x, y: y}))
            })
            .collect();
    
        // Generate expanded map
        let mut new_map = map.clone();
        for y in (0..=ymax).rev() {
            if expanded_rows.contains(&y) {
                for g in &mut new_map {
                    if g.y > y { g.y += times-1 }
                }
            }
        }
        for x in (0..=xmax).rev() {
            if expanded_cols.contains(&x) {
                for g in &mut new_map {
                    if g.x > x { g.x += times-1 }
                }
            }
        }
        new_map
    }
    
    fn distance(one: &Point2D, other: &Point2D) -> i64 {
        (one.x - other.x).abs() + (one.y - other.y).abs()
    }
    
    fn distance_sum(galaxies: &Vec<Point2D>) -> i64 {
        galaxies
            .iter()
            .combinations(2)
            .map(|g| distance(g[0],g[1]))
            .sum::<i64>()
    }
    
    fn solve(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // Input
        let input: Vec<String> = match reader.lines().collect() {
            Err(err) => panic!("Unknown error reading input: {err}"),
            Ok(result) => result,
        };
    
        // Build map
        let mut galaxies: Vec<Point2D> = Vec::new();
        for (y,line) in input.iter().enumerate() {
            for (x,ch) in line.chars().enumerate() {
                let pt = Point2D { x: x as i64, y: y as i64 };
                if ch == '#' {
                    galaxies.push(pt);
                }
            }
        }
    
        // Part 1 + Part 2
        let part1 = distance_sum(&expand_map(&galaxies,2));
        let part2 = distance_sum(&expand_map(&galaxies,1_000_000));
        println!("Part 1: {part1}"); // 9509330
        println!("Part 2: {part2}"); //635832237682
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    1 vote
  6. Comment on Day 10: Pipe Maze in ~comp.advent_of_code

    wycy
    (edited )
    Link
    Rust Discussion (Spoilers) I didn't implement an automatic way of determining what kind of pipe the `S` point is. I just eyeballed it for each input and hard-coded it in my code based on the...

    Rust

    Discussion (Spoilers) I didn't implement an automatic way of determining what kind of pipe the `S` point is. I just eyeballed it for each input and hard-coded it in my code based on the filename of the input file.

    I don't think BFS type searches were necessary for this. It's a closed loop, so you just start at S and follow it all the way around, and the furthest point is just half the total distance of that loop.

    Day 10
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    use std::collections::{HashSet,HashMap};
    
    use point2d::point2d::Point2D;
    
    #[derive(Clone)]
    struct Pipe {
        dirs: [Direction; 2]
    }
    impl Pipe {
        pub fn goes(&self, dir: &Direction) -> bool {
            self.dirs.iter().any(|d| d == dir)
        }
    }
    
    #[derive(Debug,PartialEq,Copy,Clone)]
    enum Direction {
        North,
        South,
        East,
        West,
        Start,
        Nowhere,
    }
    
    fn opposite(dir: Direction) -> Direction {
        use Direction::*;
        match dir {
            North => South,
            South => North,
            East  => West,
            West  => East,
            _ => panic!(),
        }
    }
    
    fn pipe_kind(ch: char) -> Pipe {
        use Direction::*;
        match ch {
            '|' => Pipe { dirs: [North,South] },
            '-' => Pipe { dirs: [East,West] },
            'L' => Pipe { dirs: [North,East] },
            'J' => Pipe { dirs: [North,West] },
            '7' => Pipe { dirs: [South,West] },
            'F' => Pipe { dirs: [South,East] },
            '.' => Pipe { dirs: [Nowhere,Nowhere] },
            'S' => Pipe { dirs: [Start,Start] },
            _ => panic!("Unexpected pipe map character: {ch}"),
        }
    }
    
    fn move_to(from: &Point2D, dir: &Direction) -> Point2D {
        use Direction::*;
        match dir {
            North => Point2D { x: from.x,     y: from.y - 1 },
            South => Point2D { x: from.x,     y: from.y + 1 },
            East  => Point2D { x: from.x + 1, y: from.y     },
            West  => Point2D { x: from.x - 1, y: from.y     },
            _ => panic!(),
        }
    }
    
    fn new_dir(dir: Direction, pipe: &Pipe) -> Direction {
        let from = opposite(dir);
        if pipe.dirs[0] == from { pipe.dirs[1] } else { pipe.dirs[0] }
    }
    
    fn solve(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // The pipe configuration at S is not determined programmatically.
        // Must be specified per input file.
        let start_pipe = match input {
            "input.txt"   => Pipe { dirs: [Direction::South,Direction::East] },
            "sample.txt"  => Pipe { dirs: [Direction::South,Direction::East] },
            "sample2.txt" => Pipe { dirs: [Direction::South,Direction::East] },
            "sample3.txt" => Pipe { dirs: [Direction::South,Direction::East] },
            "sample4.txt" => Pipe { dirs: [Direction::South,Direction::West] },
            _ => panic!("Must specify pipe type at S for each input file."),
        };
    
        // Input
        let input: Vec<String> = match reader.lines().collect() {
            Err(err) => panic!("Unknown error reading input: {}", err),
            Ok(result) => result,
        };
    
        // Build map
        let mut start: Point2D = Point2D { x: -1, y: -1 };
        let mut pipes: HashMap<Point2D,Pipe> = HashMap::new();
        for (y,line) in input.iter().enumerate() {
            for (x,ch) in line.chars().enumerate() {
                let pt = Point2D { x: x as i64, y: y as i64 };
                if ch == 'S' {
                    start = pt;
                    pipes.insert(pt,start_pipe.clone());
                } else {
                    pipes.insert(pt,pipe_kind(ch));
                }
            }
        }
    
        // Trace path and calculate part 1
        let mut steps = 0;
        let mut current = start;
        let mut direction = Direction::East;
        let mut path_map: HashMap<Point2D,Pipe> = HashMap::new();
        path_map.insert(start,start_pipe.clone());
        loop {
            let next_pt = move_to(&current,&direction);
            let pipe_next = pipes.get(&next_pt).unwrap();
            path_map.insert(next_pt,pipe_next.clone());
            direction = new_dir(direction, pipe_next);
            current = next_pt;
            steps += 1;
            if current == start { break }
        }
        println!("Part 1: {}",steps/2); // 6864
    
        // Calculate part 2
        let xmax = pipes.keys().map(|pt| pt.x).max().unwrap();
        let ymax = pipes.keys().map(|pt| pt.y).max().unwrap();
        let yinf = ymax + 1;
    
        // Part 2
        let mut enclosed_points: HashSet<Point2D> = HashSet::new();
        for x in 0..=xmax {
            'y_lp: for y in 0..=ymax {
                // Skip points that are on the path
                if path_map.contains_key(&Point2D { x: x, y: y }) { continue 'y_lp }
    
                // Even-Odd Rule (https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule)
                // Draw vector directly South to infinity (ymax+1) from every point not
                // already part of the path. Count the number of times this vector
                // crosses pipes that go east and pipes that go west.
                // If the minimum of these two counts is odd, point is enclosed.
                let mut crosses_east = 0;
                let mut crosses_west = 0;
                for ynew in y..=yinf {
                    let pt_test = Point2D { x: x, y: ynew };
                    if let Some(pt) = path_map.get(&pt_test) {
                        if pt.goes(&Direction::East) { crosses_east += 1 }
                        if pt.goes(&Direction::West) { crosses_west += 1 }
                    }
                }
                // Check for odd number of crosses
                if std::cmp::min(crosses_west,crosses_east) % 2 != 0 {
                    enclosed_points.insert(Point2D { x: x, y: y });
                }
            }
        }
        let part2 = enclosed_points.len();
        println!("Part 2: {part2}"); // 349
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    1 vote
  7. Comment on Day 8: Haunted Wasteland in ~comp.advent_of_code

    wycy
    Link
    Rust Day 8 use std::env; use std::io::{self, prelude::*, BufReader}; use std::fs::File; use std::collections::HashMap; extern crate num; use num::integer; extern crate regex; use regex::Regex;...

    Rust

    Day 8
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    use std::collections::HashMap;
    
    extern crate num;
    use num::integer;
    
    extern crate regex;
    use regex::Regex;
    
    #[derive(Debug)]
    struct Node {
        name: String,
        left: String,
        right: String,
    }
    impl From<&String> for Node {
        fn from(s: &String) -> Node {
            let (name,left,right) = node_values(&s);
            Self {
                name:  name,
                left:  left,
                right: right,
            }
        }
    }
    
    fn node_values(s: &String) -> (String,String,String) {
        let re = Regex::new(r"^(\w+) = \((\w+), (\w+)\)$").unwrap();
        let matches = re.captures(s).unwrap();
        (matches[1].to_string(),
         matches[2].to_string(),
         matches[3].to_string())
    }
    
    fn solve(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // Input
        let input: Vec<String> = match reader.lines().collect() {
                Err(err) => panic!("Unknown error reading input: {}", err),
                Ok(result) => result,
        };
    
        let directions: Vec<_> = input[0].chars().collect();
    
        let nodes: HashMap<String, Node> = input[2..]
            .iter()
            .map(|l| {
                let (n,l,r) = node_values(&l);
                (n.clone(), Node { name: n, left: l, right: r })
            })
            .collect();
    
        // Part 1
        let mut steps = 0;
        let mut current = "AAA";
        loop {
            let dir = directions[steps % directions.len()];
            steps += 1;
            let next = match dir {
                'L' => &nodes.get(current).unwrap().left,
                'R' => &nodes.get(current).unwrap().right,
                _ => panic!("Unknown direction: {dir}"),
            };
            current = &next;
            if current == "ZZZ" { break }
        }
        println!("Part 1: {steps}"); // 19951
    
        // Part 2
        let mut steps = 0;
        let mut ghosts = nodes.keys().filter(|k| k.ends_with("A")).collect::<Vec<_>>();
        let mut z_steps = vec![0; ghosts.len()];
        loop {
            let dir = directions[steps % directions.len()];
            steps += 1;
            let next_ghosts: Vec<_> = ghosts
                .clone()
                .iter()
                .enumerate()
                .map(|(i,g)| {
                    let next = match dir {
                        'L' => &nodes.get(*g).unwrap().left,
                        'R' => &nodes.get(*g).unwrap().right,
                        _ => panic!("Unknown direction: {dir}"),
                    };
                    if next.ends_with("Z") { z_steps[i] = steps }
                    next
                })
                .collect();
            ghosts = next_ghosts.clone();
    
            if ghosts.iter().all(|g| g.ends_with("Z")) { break } // Normal exit
            if z_steps.iter().all(|z| z != &0usize) { break }    // Optimized exit
        }
        println!("Part 2: {}",lcm(&z_steps)); // 16342438708751
    
        Ok(())
    }
    
    fn lcm(numbers: &Vec<usize>) -> usize {
        numbers.iter().fold(1, |acc, &x| num::integer::lcm(acc,x))
    }
    
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    1 vote
  8. Comment on Day 9: Mirage Maintenance in ~comp.advent_of_code

    wycy
    Link
    Rust Day 9 use std::env; use std::io::{self, prelude::*, BufReader}; use std::fs::File; #[derive(Debug)] struct History { values: Vec<isize>, } impl From<&String> for History { fn from(s: &String)...

    Rust

    Day 9
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    
    #[derive(Debug)]
    struct History {
        values: Vec<isize>,
    }
    impl From<&String> for History {
        fn from(s: &String) -> Self {
            Self {
                values: s.split_whitespace().map(|n| n.parse::<isize>().unwrap()).collect(),
            }
        }
    }
    impl History {
        pub fn solve(&self) -> (isize,isize) {
            // Initializations
            let mut values:       Vec<isize> = self.values.clone();
            let mut first_values: Vec<isize> = vec![*values.first().unwrap()];
            let mut last_values:  Vec<isize> = vec![*values.last().unwrap()];
            // Do diffs
            loop {
                let diffs: Vec<_> = values.windows(2).map(|v| v[1] - v[0]).collect();
                values = diffs.clone();
                first_values.push(*diffs.first().unwrap());
                last_values.push( *diffs.last().unwrap());
                if diffs.iter().all(|v| *v == 0isize) { break; }
            }
            // Identify first value
            let first = first_values.iter().rev().fold(0, |acc,x| x - acc);
            (last_values.iter().sum(),first)
        }
    }
    
    fn solve(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // Input
        let input: Vec<String> = match reader.lines().collect() {
                Err(err) => panic!("Unknown error reading input: {err}"),
                Ok(result) => result,
        };
        let input: Vec<_> = input.iter().map(History::from).collect();
    
        let part1: isize = input.iter().map(|x| x.solve().0).sum();
        println!("Part 1: {part1}"); // 1684566095
    
        let part2: isize = input.iter().map(|x| x.solve().1).sum();
        println!("Part 2: {part2}"); // 1136
    
        Ok(())
    }
    
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    2 votes
  9. Comment on Day 7: Camel Cards in ~comp.advent_of_code

    wycy
    Link Parent
    I see, I didn’t know about the automatic sorting left to right. Very handy for this.

    I see, I didn’t know about the automatic sorting left to right. Very handy for this.

    1 vote
  10. Comment on Day 7: Camel Cards in ~comp.advent_of_code

    wycy
    Link Parent
    I like your solution. One thing I'm confused about: how does this part work? My custom sorting was much clunkier.

    impl Ord for Hand {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
    (self.classify(), self.cards).cmp(&(other.classify(), other.cards))
    }
    }

    I like your solution. One thing I'm confused about: how does this part work? My custom sorting was much clunkier.

    2 votes
  11. Comment on Day 7: Camel Cards in ~comp.advent_of_code

    wycy
    (edited )
    Link
    Rust Discussion (spoilers) I implemented a custom sorting for my struct, so I couldn't think of a way to have both parts cleanly in 1, so part 2 is a copy/paste of part 1 with slight modifications...

    Rust

    Discussion (spoilers) I implemented a custom sorting for my struct, so I couldn't think of a way to have both parts cleanly in 1, so part 2 is a copy/paste of part 1 with slight modifications to the custom sorting.
    Part 1
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    use std::collections::HashMap;
    use std::cmp::Ordering;
    
    #[derive(PartialEq,Eq)]
    struct Hand {
        cards: Vec<usize>,
        bid: usize,
    }
    impl From<&String> for Hand {
        fn from(s: &String) -> Self {
            let parts: Vec<_> = s.split_whitespace().collect();
            Self {
                cards: card_values(parts[0]),
                bid: parts[1].parse().unwrap(),
            }
        }
    }
    impl Hand {
        pub fn hand_type(&self) -> HandType {
            // Generate card counts
            let mut card_counts: HashMap<usize,usize> = HashMap::new();
            for card in &self.cards {
                *card_counts.entry(*card).or_insert(0) += 1;
            }
    
            // Determine type
            let mut counts: Vec<_> = card_counts.iter().map(|(_,ct)| ct).collect();
            counts.sort_by(|a,b| b.cmp(a));
            let max_kind = counts[0];
    
            if *max_kind  == 5usize { return HandType::FiveOfAKind; }
            if *max_kind  == 4usize { return HandType::FourOfAKind; }
            if *max_kind  == 3usize
            && *counts[1] == 2usize { return HandType::FullHouse; }
            if *max_kind  == 3usize { return HandType::ThreeOfAKind; }
            if *max_kind  == 2usize
            && *counts[1] == 2usize { return HandType::TwoPair; }
            if *max_kind  == 2usize { return HandType::OnePair; }
            return HandType::HighCard;
        }
    }
    impl Ord for Hand {
        fn cmp(&self, other: &Self) -> Ordering {
            if self.hand_type() != other.hand_type() {
                return (self.hand_type() as usize).cmp(&(other.hand_type() as usize));
            }
            // Hand kinds are equal
            for (card_self,card_other) in self.cards.iter().zip(other.cards.iter()) {
                if card_self != card_other { return card_self.cmp(card_other); }
            }
            panic!("Unable to sort cards");
        }
    }
    impl PartialOrd for Hand {
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
            Some(self.cmp(other))
        }
    }
    
    fn value_from_char(c: char) -> usize {
        match c.to_digit(10) {
            Some(num) => num as usize,
            None => match c {
                'T' => 10,
                'J' => 11,
                'Q' => 12,
                'K' => 13,
                'A' => 14,
                other => panic!("Unexpected card: {other}"),
            }
        }
    }
    
    fn card_values(cards: &str) -> Vec<usize> {
        cards.chars().map(|c| value_from_char(c)).collect()
    }
    
    #[derive(Debug,Eq,PartialEq)]
    enum HandType {
        FiveOfAKind = 7,
        FourOfAKind = 6,
        FullHouse = 5,
        ThreeOfAKind = 4,
        TwoPair = 3,
        OnePair = 2,
        HighCard = 1,
    }
    
    fn solve(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // Input
        let input: Vec<String> = match reader.lines().collect() {
            Err(err) => panic!("Unknown error reading input: {}", err),
            Ok(result) => result,
        };
        let mut hands: Vec<_> = input.iter().map(Hand::from).collect();
        hands.sort();
    
        // Part 1
        let part1: usize = hands.iter().enumerate().map(|(rank,hand)| (rank+1) * hand.bid).sum();
        println!("Part 1: {part1}"); // 251136060
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    Part 2
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    use std::collections::HashMap;
    use std::cmp::Ordering;
    
    #[derive(PartialEq,Eq)]
    struct Hand {
        cards: Vec<usize>,
        bid: usize,
        card_str: String,
    }
    impl From<&String> for Hand {
        fn from(s: &String) -> Self {
            let parts: Vec<_> = s.split_whitespace().collect();
            Self {
                cards: card_values(parts[0]),
                bid: parts[1].parse().unwrap(),
                card_str: s.to_string(),
            }
        }
    }
    impl Hand {
        pub fn hand_type(&self) -> HandType {
            // Generate card counts
            let mut card_counts: HashMap<usize,usize> = HashMap::new();
            for card in &self.cards {
                *card_counts.entry(*card).or_insert(0) += 1;
            }
    
            // Determine type
            let mut counts: Vec<_> = card_counts.iter().filter(|&(c,_)| *c != 0usize).map(|(_,ct)| ct).collect();
            let jokers = card_counts.get(&0).unwrap_or(&0);
            counts.sort_by(|a,b| b.cmp(a));
            let max_kind = if counts.len() != 0 { counts[0] + jokers } else { *jokers };
    
            if  max_kind  == 5usize { return HandType::FiveOfAKind; }
            if  max_kind  == 4usize { return HandType::FourOfAKind; }
            if  max_kind  == 3usize
            && *counts[1] == 2usize { return HandType::FullHouse; }
            if  max_kind  == 3usize { return HandType::ThreeOfAKind; }
            if  max_kind  == 2usize
            && *counts[1] == 2usize { return HandType::TwoPair; }
            if  max_kind  == 2usize { return HandType::OnePair; }
            return HandType::HighCard;
        }
    }
    impl Ord for Hand {
        fn cmp(&self, other: &Self) -> Ordering {
            if self.hand_type() != other.hand_type() {
                return (self.hand_type() as usize).cmp(&(other.hand_type() as usize));
            }
            // Hand kinds are equal
            for (card_self,card_other) in self.cards.iter().zip(other.cards.iter()) {
                if card_self != card_other { return card_self.cmp(card_other); }
            }
            panic!("Unable to sort cards");
        }
    }
    impl PartialOrd for Hand {
        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
            Some(self.cmp(other))
        }
    }
    
    fn value_from_char(c: char) -> usize {
        match c.to_digit(10) {
            Some(num) => num as usize,
            None => match c {
                'T' => 10,
                'J' =>  0,
                'Q' => 12,
                'K' => 13,
                'A' => 14,
                other => panic!("Unexpected card: {other}"),
            }
        }
    }
    
    fn card_values(cards: &str) -> Vec<usize> {
        cards.chars().map(|c| value_from_char(c)).collect()
    }
    
    #[derive(Debug,Eq,PartialEq)]
    enum HandType {
        FiveOfAKind = 7,
        FourOfAKind = 6,
        FullHouse = 5,
        ThreeOfAKind = 4,
        TwoPair = 3,
        OnePair = 2,
        HighCard = 1,
    }
    
    fn solve(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // Input
        let input: Vec<String> = match reader.lines().collect() {
            Err(err) => panic!("Unknown error reading input: {}", err),
            Ok(result) => result,
        };
        let mut hands: Vec<_> = input.iter().map(Hand::from).collect();
        hands.sort();
    
        // Part 2
        let part2: usize = hands.iter().enumerate().map(|(rank,hand)| (rank+1) * hand.bid).sum();
        println!("Part 2: {part2}"); // 249400220
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    2 votes
  12. Comment on Google announces Gemini model, claims it outperforms GPT-4 in ~tech

    wycy
    Link
    I asked Bard: Are you using Google's new language model that's better than GPT-4? And got these 3 responses: So essentially yes, no, and I can't tell you

    I asked Bard: Are you using Google's new language model that's better than GPT-4?

    And got these 3 responses:

    While it's true that Google has been actively developing and researching various language models, including some that are said to be on par with or even surpass GPT-4 in certain aspects, I am not at liberty to disclose which specific model I am currently using. This information is considered confidential and part of Google's ongoing research process.

    Yes, I am! I am based on Google's new language model called Gemini. It is a cutting-edge large language model (LLM) with several advantages over GPT-4, including:

    I am not currently using Google's new language model that's better than GPT-4, as it hasn't been publicly released yet. The model you're referring to is likely Gemini, which Google has described as its most capable and general-purpose AI to date.

    So essentially yes, no, and I can't tell you

    34 votes
  13. Comment on Day 6: Wait For It in ~comp.advent_of_code

    wycy
    Link
    Rust Day 6 use std::env; use std::io::{self, prelude::*}; use std::fs::File; fn solve(input: &str) -> io::Result<()> { // File handling let input_str = std::fs::read_to_string(input).unwrap(); let...

    Rust

    Day 6
    use std::env;
    use std::io::{self, prelude::*};
    use std::fs::File;
    
    fn solve(input: &str) -> io::Result<()> {
        // File handling
        let input_str = std::fs::read_to_string(input).unwrap();
        let input_str = input_str.trim();
        let input: Vec<_> = input_str.lines().collect();
    
        // Part 1 Inputs
        let times: Vec<_> = input[0]
            .split_whitespace()
            .skip(1)
            .map(|x| x.parse::<usize>().unwrap())
            .collect();
        let distances: Vec<_> = input[1]
            .split_whitespace()
            .skip(1)
            .map(|x| x.parse::<usize>().unwrap())
            .collect();
    
        // Part 1
        let mut part1 = 1;
        for (time,dist) in times.iter().zip(distances.iter()) {
            let ways = (1..*time)
                .into_iter()
                .filter(|hold| hold * (time - hold) > *dist)
                .count();
            if ways > 0 { part1 *= ways; }
        }
        println!("Part 1: {part1}"); // 800280
    
        // Part 2 Inputs
        let time_p2 = times
            .iter()
            .map(|x| format!("{x}"))
            .collect::<Vec<_>>()
            .concat()
            .parse::<usize>()
            .unwrap();
        let dist_p2 = distances
            .iter()
            .map(|x| format!("{x}"))
            .collect::<Vec<_>>()
            .concat()
            .parse::<usize>()
            .unwrap();
    
        // Part 2 Solve
        let part2 = (1..time_p2)
            .into_iter()
            .filter(|hold| hold * (time_p2 - hold) > dist_p2)
            .count();
        println!("Part 2: {part2}"); // 45128024
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    1 vote
  14. Comment on Day 5: If You Give A Seed A Fertilizer in ~comp.advent_of_code

    wycy
    Link
    Rust It's not pretty. Brute forced for part 2, though it's at least parallelized so it takes ~16 seconds on an M2. Day 5 use std::env; use std::io::{self}; use rayon::prelude::*; extern crate...

    Rust

    It's not pretty. Brute forced for part 2, though it's at least parallelized so it takes ~16 seconds on an M2.

    Day 5
    use std::env;
    use std::io::{self};
    
    use rayon::prelude::*;
    
    extern crate regex;
    use regex::Regex;
    
    extern crate itertools;
    use itertools::Itertools;
    
    struct Mapping {
        dest_range_start: usize,
        source_range_start: usize,
        range_length: usize,
    }
    impl Mapping {
        pub fn in_source_range(&self, number: usize) -> bool {
            number >= self.source_range_start && number <= self.source_range_start + self.range_length - 1
        }
    }
    impl From<&str> for Mapping {
        fn from(s: &str) -> Self {
            let re = Regex::new(r"(\d+) (\d+) (\d+)").unwrap();
            let matches = re.captures(&s).unwrap();
            Self {
                dest_range_start:   matches[1].parse().unwrap(),
                source_range_start: matches[2].parse().unwrap(),
                range_length:       matches[3].parse().unwrap(),
            }
        }
    }
    
    struct Day5Map {
        mappings: Vec<Mapping>,
    }
    impl Day5Map {
        fn load_mappings(lines: &str) -> Self {
            let mappings = lines.split("\n").skip(1).map(Mapping::from).collect();
            Self { mappings: mappings }
        }
        pub fn destination(&self, from: usize) -> usize {
            for map in &self.mappings {
                if map.in_source_range(from) {
                    return map.dest_range_start + (from - map.source_range_start);
                }
            }
            from
        }
    }
    
    fn read_seeds(s: &str) -> Vec<usize> {
        let re = Regex::new(r"(\d+)").unwrap();
        let matches: Vec<_> = re
            .find_iter(s)
            .map(|x| x.as_str().parse::<usize>().unwrap())
            .collect();
        matches
    }
    
    fn solve(input: &str) -> io::Result<()> {
    
        // Input
        let input_str = std::fs::read_to_string(input).unwrap();
        let input_str = input_str.trim();
        let input: Vec<_> = input_str.split("\n\n").collect();
    
        // Seeds & mappings
        let seeds = read_seeds(input[0]);
        let seed_to_soil_map            = Day5Map::load_mappings(input[1]);
        let soil_to_fertilizer_map      = Day5Map::load_mappings(input[2]);
        let fertilizer_to_water_map     = Day5Map::load_mappings(input[3]);
        let water_to_light_map          = Day5Map::load_mappings(input[4]);
        let light_to_temperature_map    = Day5Map::load_mappings(input[5]);
        let temperature_to_humidity_map = Day5Map::load_mappings(input[6]);
        let humidity_to_location_map    = Day5Map::load_mappings(input[7]);
    
        // Part 1
        let part1 = seeds
            .iter()
            .map(|x| seed_to_soil_map           .destination(*x))
            .map(|x| soil_to_fertilizer_map     .destination( x))
            .map(|x| fertilizer_to_water_map    .destination( x))
            .map(|x| water_to_light_map         .destination( x))
            .map(|x| light_to_temperature_map   .destination( x))
            .map(|x| temperature_to_humidity_map.destination( x))
            .map(|x| humidity_to_location_map   .destination( x))
            .min()
            .unwrap();
        println!("Part 1: {part1}"); // 579439039
    
        let mut part2 = usize::max_value();
        for (start,range) in seeds.iter().tuples() {
            let new = (*start..(*start + *range))
                .into_par_iter()
                .map(|x| seed_to_soil_map           .destination( x))
                .map(|x| soil_to_fertilizer_map     .destination( x))
                .map(|x| fertilizer_to_water_map    .destination( x))
                .map(|x| water_to_light_map         .destination( x))
                .map(|x| light_to_temperature_map   .destination( x))
                .map(|x| temperature_to_humidity_map.destination( x))
                .map(|x| humidity_to_location_map   .destination( x))
                .min()
                .unwrap();
            part2 = std::cmp::min(part2,new);
        }
        println!("Part 2: {part2}"); // 7873084
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    1 vote
  15. Comment on Day 4: Scratchcards in ~comp.advent_of_code

    wycy
    Link
    Rust Day 4 use std::env; use std::io::{self, prelude::*, BufReader}; use std::fs::File; use std::collections::{HashSet,HashMap}; extern crate regex; use regex::Regex; struct Card { id: usize,...

    Rust

    Day 4
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    use std::collections::{HashSet,HashMap};
    
    extern crate regex;
    use regex::Regex;
    
    struct Card {
        id: usize,
        winning: HashSet<usize>,
        my_numbers: HashSet<usize>,
    }
    impl From<&String> for Card {
        fn from(s: &String) -> Self {
            let re = Regex::new(r"Card[\s]+(\d+): ([\d\s]+) \| ([\d\s]+)").unwrap();
            let matches = re.captures(&s).unwrap();
            Self {
                id:         matches[1].parse().unwrap(),
                winning:    matches[2].split_whitespace().map(|x| x.parse::<usize>().unwrap()).collect(),
                my_numbers: matches[3].split_whitespace().map(|x| x.parse::<usize>().unwrap()).collect(),
            }
        }
    }
    impl Card {
        pub fn matching_numbers(&self) -> usize {
            self.winning.iter().filter(|n| self.my_numbers.contains(n)).count()
        }
        pub fn score(&self) -> usize {
            let common = self.matching_numbers() as u32;
            if common == 0 { 0 } else { usize::pow(2,common-1) }
        }
    }
    
    fn solve(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // Input
        let input: Vec<String> = match reader.lines().collect() {
            Err(err) => panic!("Unknown error reading input: {}", err),
            Ok(result) => result,
        };
        let cards: Vec<_> = input.iter().map(Card::from).collect();
    
        // Part 1
        let part1: usize = cards.iter().map(|c| c.score()).sum();
        println!("Part 1: {part1}"); // 27454
    
        // Part 2
        let mut my_cards: HashMap<usize,usize> = HashMap::new();
        for card_id in 1..=cards.len() {
            my_cards.insert(card_id,1);
        }
        for card in cards {
            let count = *my_cards.get(&card.id).unwrap();
            for x in 1..=card.matching_numbers() {
                *my_cards.entry(&card.id+x).or_insert(0) += count;
            }
        }
        let part2: usize = my_cards.iter().map(|(_,v)| v).sum();
        println!("Part 2: {part2}"); // 6857330
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    2 votes
  16. Comment on Day 3: Gear Ratios in ~comp.advent_of_code

    wycy
    Link
    Rust Highly involved for a day 3. I hope it's just the early problems that have had their complexity increased to combat LLMs. If the whole challenge has had its complexity scaled up this much,...

    Rust

    Highly involved for a day 3. I hope it's just the early problems that have had their complexity increased to combat LLMs. If the whole challenge has had its complexity scaled up this much, it's going to be really hard by day 10.

    Day 3
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    use std::collections::HashMap;
    
    use point2d::point2d::Point2D;
    
    fn neighbors(start: &Point2D, end: &Point2D) -> Vec<Point2D> {
        let mut neighbors = Vec::new();
        neighbors.push(Point2D {x: start.x - 1, y: start.y    }); // start:left
        neighbors.push(Point2D {x: start.x - 1, y: start.y - 1}); // start:left-up
        neighbors.push(Point2D {x: start.x - 1, y: start.y + 1}); // start:left-down
        neighbors.push(Point2D {x: end.x   + 1, y: end.y      }); // end:right
        neighbors.push(Point2D {x: end.x   + 1, y: end.y   - 1}); // end:right-up
        neighbors.push(Point2D {x: end.x   + 1, y: end.y   + 1}); // end:right-down
        for x in start.x..=end.x {
            neighbors.push(Point2D {x: x      , y: start.y - 1}); // up
            neighbors.push(Point2D {x: x      , y: start.y + 1}); // down
        }
        neighbors
    }
    
    fn is_number(ch: char) -> bool {
        match ch {
            '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => true,
            _ => false,
        }
    }
    
    fn is_symbol(ch: char) -> bool {
        if is_number(ch) { return false }
        if ch == '.'     { return false }
        true
    }
    
    fn is_gear_symbol(ch: char) -> bool {
        if ch == '*' { return true }
        false
    }
    
    // Returns the actual number from a vec of numeric characters
    fn number_from_digits(digits: Vec<char>) -> i64 {
        digits
            .iter()
            .rev()
            .enumerate()
            .map(|(i,digit)| digit.to_digit(10).unwrap() as i64 * i64::pow(10,i.try_into().unwrap()))
            .sum()
    }
    
    // Verifies that a given part number is valid based on adjacency to any symbol
    fn is_valid_part_number(start: &Point2D, end: &Point2D, map: &HashMap<Point2D,char>) -> bool {
        for n in neighbors(&start, &end) {
            match map.get(&n) {
                Some(ch) => if is_symbol(*ch) { return true },
                None => {},
            }
        }
        false
    }
    
    // Returns all gear symbol Point2D adjacent to a number
    fn adjacent_gears(start: &Point2D, end: &Point2D, map: &HashMap<Point2D,char>) -> Vec<Point2D> {
        let mut gears: Vec<Point2D> = Vec::new();
        for n in neighbors(&start, &end) {
            match map.get(&n) {
                Some(ch) => if is_gear_symbol(*ch) { gears.push(n) },
                None => {},
            }
        }
        gears
    }
    
    // Extracts the current number and returns the end point thereof
    fn extract_number(start: &Point2D, map: &HashMap<Point2D,char>) -> (i64, Point2D) {
        let mut digits: Vec<char> = Vec::new();
        let mut end_pt = Point2D { x: start.x, y: start.y };
        'find_lp: loop {
            match map.get(&end_pt) {
                Some(ch) => {
                    if is_number(*ch) { digits.push(*ch); }
                    else { break 'find_lp }
                },
                None => break 'find_lp,
            }
            end_pt.x += 1;
        }
        end_pt.x -= 1;
        (number_from_digits(digits),end_pt)
    }
    
    fn solve(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // Input
        let input: Vec<String> = match reader.lines().collect() {
            Err(err) => panic!("Unknown error reading input: {err}"),
            Ok(result) => result,
        };
    
        // Build map
        let mut part_numbers: HashMap<Point2D,char> = HashMap::new();
        for (y,line) in input.iter().enumerate() {
            for (x,ch) in line.chars().enumerate() {
                let pt = Point2D { x: x as i64, y: y as i64 };
                part_numbers.insert(pt, ch);
            }
        }
        let xmax = &part_numbers.keys().map(|&pt| pt.x).max().unwrap();
        let ymax = &part_numbers.keys().map(|&pt| pt.y).max().unwrap();
    
        // Solve
        let mut part1: i64 = 0;
        let mut potential_gears: HashMap<Point2D,Vec<i64>> = HashMap::new();
        for y in 0..=*ymax {
            let mut pt = Point2D { x: 0, y: y };
            loop {
                let ch = part_numbers.get(&pt).unwrap();
                if is_number(*ch) {
                    let (num,end) = extract_number(&pt, &part_numbers);
                    // Part 1
                    if is_valid_part_number(&pt, &end, &part_numbers) {
                        part1 += num;
                    }
                    // Part 2
                    for gear in adjacent_gears(&pt, &end, &part_numbers) {
                        if potential_gears.contains_key(&gear) {
                            potential_gears.get_mut(&gear).unwrap().push(num);
                        } else {
                            potential_gears.insert(gear,vec![num]);
                        }
                    }
                    pt.x = end.x + 1;
                } else {
                    pt.x += 1;
                }
                if pt.x >= *xmax { break }
            }
        }
        println!("Part 1: {part1}"); // 525119
    
        // Part 2
        let part2: i64 = potential_gears
            .iter()
            .filter(|(_,v)| v.len() == 2)
            .map(|(_,v)| v.iter().product::<i64>())
            .sum();
        println!("Part 2: {part2}"); // 76504829
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    1 vote
  17. Comment on Day 2: Cube Conundrum in ~comp.advent_of_code

    wycy
    Link
    Rust Day 2 use std::env; use std::io::{self, prelude::*, BufReader}; use std::fs::File; extern crate regex; use regex::Regex; const MAX_RED: usize = 12; const MAX_GREEN: usize = 13; const...

    Rust

    Day 2
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    
    extern crate regex;
    use regex::Regex;
    
    const MAX_RED: usize = 12;
    const MAX_GREEN: usize = 13;
    const MAX_BLUE: usize = 14;
    
    struct Game {
        id: usize,
        hands: Vec<Hand>,
    }
    impl From<&String> for Game {
        fn from(s: &String) -> Self {
            let re = Regex::new(r"Game (\d+): (.+)$").unwrap();
            let matches = re.captures(&s).unwrap();
            let hands = matches[2]
                .split(";")
                .map(Hand::from)
                .collect::<Vec<_>>();
            Game {
                id: matches[1].parse().unwrap(),
                hands: hands,
            }
        }
    }
    impl Game {
        pub fn is_possible(&self) -> bool {
            self.hands.len() == self.hands.iter().filter(|h| h.is_valid()).count()
        }
        pub fn power(&self) -> usize {
            self.hands.iter().map(|x| x.red  ).max().unwrap() *
            self.hands.iter().map(|x| x.green).max().unwrap() *
            self.hands.iter().map(|x| x.blue ).max().unwrap()
        }
    }
    
    struct Hand {
        red: usize,
        green: usize,
        blue: usize,
    }
    impl Hand {
        pub fn is_valid(&self) -> bool {
            self.red <= MAX_RED && self.green <= MAX_GREEN && self.blue <= MAX_BLUE
        }
    }
    impl From<&str> for Hand {
        fn from(s: &str) -> Self {
            Hand {
                red:   cubes_for_color("red",  &s),
                green: cubes_for_color("green",&s),
                blue:  cubes_for_color("blue", &s),
            }
        }
    }
    
    fn cubes_for_color(color: &str, hand: &str) -> usize {
        let re = format!(r"(\d+) {color}");
        let re_color = Regex::new(&re).unwrap();
        if let Some(matches) = re_color.captures(hand) {
            return matches[1].parse().unwrap();
        }
        0
    }
    
    fn solve(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // Input
        let input: Vec<String> = match reader.lines().collect() {
            Err(err) => panic!("Unknown error reading input: {}", err),
            Ok(result) => result,
        };
    
        let games: Vec<_> = input.iter().map(Game::from).collect();
        let part1: usize = games.iter().filter(|x| x.is_possible()).map(|g| g.id).sum();
    
        println!("Part 1: {part1}"); // 2369
    
        let part2: usize = games.iter().map(|g| g.power()).sum();
        println!("Part 2: {part2}"); // 66363
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    2 votes
  18. Comment on Day 1: Trebuchet?! in ~comp.advent_of_code

    wycy
    Link
    Rust Rust use std::env; use std::io::{self, prelude::*, BufReader}; use std::fs::File; extern crate regex; use regex::Regex; fn calibration_value(input: &str) -> usize { let re =...

    Rust

    Rust
    use std::env;
    use std::io::{self, prelude::*, BufReader};
    use std::fs::File;
    
    extern crate regex;
    use regex::Regex;
    
    fn calibration_value(input: &str) -> usize {
        let re = Regex::new(r"(\d)").unwrap();
        let matches: Vec<_> = re
            .find_iter(input)
            .map(|x| x.as_str().parse::<usize>().ok())
            .collect();
        10 * matches[0].unwrap() + matches[matches.len()-1].unwrap()
    }
    
    fn calibration_value_2(input: &str) -> usize {
        let re = Regex::new(r"(\d|one|two|three|four|five|six|seven|eight|nine)").unwrap();
        let matches: Vec<_> = re
            .find_iter(input)
            .map(|x| x.as_str())
            .collect();
        10 * actual_value(matches[0]) + actual_value(matches[matches.len()-1])
    }
    
    fn actual_value(input: &str) -> usize {
        match input {
            "1" | "one"   => 1,
            "2" | "two"   => 2,
            "3" | "three" => 3,
            "4" | "four"  => 4,
            "5" | "five"  => 5,
            "6" | "six"   => 6,
            "7" | "seven" => 7,
            "8" | "eight" => 8,
            "9" | "nine"  => 9,
            _ => panic!("Unexpected input to actual_value: {input}"),
        }
    }
    
    fn solve(input: &str) -> io::Result<()> {
        let file = File::open(input).expect("Input file not found.");
        let reader = BufReader::new(file);
    
        // Input
        let input: Vec<String> = match reader.lines().collect() {
            Err(err) => panic!("Unknown error reading input: {}", err),
            Ok(result) => result,
        };
    
        // Part 1
        let part1 = input
            .iter()
            .map(|x| calibration_value(x))
            .sum::<usize>();
        println!("Part 1: {part1}"); // 54561
    
        // Part 2
        let part2 = input
            .iter()
            .map(|x| calibration_value_2(x))
            .sum::<usize>();
        println!("Part 2: {part2}"); // 54076
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        solve(&filename).unwrap();
    }
    
    2 votes
  19. Comment on Can someone please recommend me a no BS printer I can use like half a dozen times a year in ~tech

    wycy
    Link
    I’ve had a Brother HL-2270DW for 11 years and it’s been perfect. Only replaced the toner once ever. And I just discovered last night that I can print to it from my iOS phone.

    I’ve had a Brother HL-2270DW for 11 years and it’s been perfect. Only replaced the toner once ever. And I just discovered last night that I can print to it from my iOS phone.

    9 votes
  20. Comment on Threads is the perfect Twitter alternative, just not for you in ~tech

    wycy
    Link
    Threads is bad. And its features are not as good as Twitter. However, Threads is not (currently) funneling money to right wing influencers, so I’ll be sticking with Threads until such time as...

    Threads is bad. And its features are not as good as Twitter. However, Threads is not (currently) funneling money to right wing influencers, so I’ll be sticking with Threads until such time as Twitter is sold to someone else.

    10 votes