wycy's recent activity

  1. Comment on Why US Democrats won't build their own Joe Rogan in ~society

    wycy
    Link Parent
    Genuine question, can you explain more what you mean by his community sucking, especially with examples? I've never heard any serious critique of the community beyond unfounded Bernie Bro smearing...

    Much like Rogan, Bernie supporters were not super great about women. And I never felt inspired by him, still don't. He makes some good points, his supporters still suck, and I don't always agree with him either.
    I don't like the vibes of a Rogan or a Bernie and it might be because the community around him sucked

    Genuine question, can you explain more what you mean by his community sucking, especially with examples? I've never heard any serious critique of the community beyond unfounded Bernie Bro smearing from the Hillary crowd.

    22 votes
  2. Comment on Why I use KDE in ~tech

    wycy
    Link
    I miss KDE. We use RHEL 8 at work so I was forced to move to Gnome, and it is so incredibly opinionated and basic. It feels as though the project was commandeered by some developer with extremely...

    I miss KDE. We use RHEL 8 at work so I was forced to move to Gnome, and it is so incredibly opinionated and basic. It feels as though the project was commandeered by some developer with extremely strong, extremely esoteric UI opinions and bent Gnome to their weird will.

    Gnome requires all kinds of 3rd party plugins just to have the sort of taskbar or dock that we've come to expect from all OSes over the last 30 years. You have to install gnome-tweaks even just to restore the window minimize/maximize buttons (!). Utter insanity.

    I'm incredibly fortunate to work in an IT environment where IT was okay with installing all the 3rd party plugins needed to make Gnome a workable desktop enterprise OS. I shudder to think what it must be like to work in a more restrictive IT environment and have to deal with completely vanilla Gnome, never again minimizing a window.

    19 votes
  3. Comment on Share your personal dotfile treats and Unix tool recommendations in ~comp

    wycy
    Link
    nnn: a very fast and lightweight TUI file manager with vim like key bindings. I use it less for file management and more as a faster way to cd around the file system. yazi: another TUI file...
    • Exemplary

    nnn: a very fast and lightweight TUI file manager with vim like key bindings. I use it less for file management and more as a faster way to cd around the file system.

    yazi: another TUI file manager, a bit slower than nnn because it does more (previews). I tend to use yazi for actual file management.

    nnn is so critical to my workflow. Even just going up one directory is fewer keystrokes with nnn. cd ..<Enter> (6 strokes) vs n<Enter>hq (4 strokes). The strokes saved increase with more cd complexity (eg, going up and over a directory).

    8 votes
  4. Comment on What toothpaste do you use? in ~life.style

    wycy
    Link
    I have 3-4 toothpastes on my counter and randomly pick a different one each time I brush. In the rotation I have: -A regular generic Crest/Colgate/whatever fluoride toothpaste -Sensodyne with...

    I have 3-4 toothpastes on my counter and randomly pick a different one each time I brush.

    In the rotation I have:
    -A regular generic Crest/Colgate/whatever fluoride toothpaste
    -Sensodyne with novamin
    -One with nano-hydroxyapatite
    -Some other fluoride toothpaste supposedly good for gum health

    The Sensodyne with novamin isn’t normally available in the US to my knowledge, so I bought it on Amazon, but I don’t know whether or not it’s counterfeit. I don’t really like the texture of it—it has a bit of a rubbery feel. But I’m lead to believe it’s worth it.

    5 votes
  5. Comment on Has anyone stopped caring about politics? in ~humanities

    wycy
    Link
    Yep. I used to listen to about 2-3 hours of political news/analysis per day. July 2023 I stopped and really haven't paid much attention since. The US is cooked and there's nothing I can do about...

    Yep. I used to listen to about 2-3 hours of political news/analysis per day. July 2023 I stopped and really haven't paid much attention since. The US is cooked and there's nothing I can do about it. Might as well just enjoy myself while it lasts.

    5 votes
  6. Comment on Is Emacs or VIM worth learning in today's day and age? in ~comp

    wycy
    Link
    I learned vim maybe a year or two ago, and for me it was absolutely worth it. It was a complete game-changer in terms of the way I program and even just use the computer in general. Switching to...

    I learned vim maybe a year or two ago, and for me it was absolutely worth it. It was a complete game-changer in terms of the way I program and even just use the computer in general. Switching to it made me appreciate the terminal a lot more, and now I do almost all of my work with a full-screen terminal with vim+tmux.

    3 votes
  7. 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
  8. 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
  9. 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
  10. 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.

  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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