Gobbel2000

joined 1 year ago
[โ€“] Gobbel2000 2 points 5 months ago

Yes, please put tracks everywhere.

[โ€“] Gobbel2000 1 points 5 months ago

Rust

One of those with running through tricky grid indices. The vector types from the euclid crate helped in dealing with positions.

Code

use euclid::{vec2, default::*};

fn count_xmas(grid: &[&[u8]], pos: (usize, usize)) -> u32 {
    if grid[pos.1][pos.0] != b'X' {
        return 0
    }

    let bounds = Rect::new(Point2D::origin(), Size2D::new(grid[0].len() as i32, grid.len() as i32));
    const DIRS: [Vector2D<i32>; 8] = [
        vec2(1, 0), vec2(-1, 0), vec2(0, 1), vec2(0, -1),
        vec2(1, 1), vec2(1, -1), vec2(-1, 1), vec2(-1, -1),
    ];
    let mut count = 0;
    for dir in DIRS {
        let mut cur = Point2D::from(pos).to_i32();
        let mut found = true;
        for letter in [b'M', b'A', b'S'] {
            cur += dir;
            if !bounds.contains(cur) || grid[cur.y as usize][cur.x as usize] != letter {
                found = false;
                break
            }
        }
        if found {
            count += 1;
        }
    }
    count
}

fn part1(input: String) {
    let grid = input.lines().map(|l| l.as_bytes()).collect::<Vec<_>>();    
    let count = (0..grid.len()).map(|y| {
            (0..grid[y].len()).map(|x| count_xmas(&grid, (x, y))).sum::<u32>()
        })
        .sum::<u32>();
    println!("{count}");
}

fn is_x_mas(grid: &[&[u8]], pos: (usize, usize)) -> bool {
    if grid[pos.1][pos.0] != b'A' {
        return false
    }

    const DIRS: [Vector2D<i32>; 4] = [vec2(1, -1), vec2(1, 1), vec2(-1, 1), vec2(-1, -1)];
    let pos = Point2D::from(pos).to_i32();
    (0..4).any(|d| {
        let m_pos = [pos + DIRS[d], pos + DIRS[(d + 1) % 4]]; // 2 adjacent positions of M
        let s_pos = [pos + DIRS[(d + 2) % 4], pos + DIRS[(d + 3) % 4]]; // others S
        m_pos.iter().all(|p| grid[p.y as usize][p.x as usize] == b'M') &&
        s_pos.iter().all(|p| grid[p.y as usize][p.x as usize] == b'S')
    })
}

fn part2(input: String) {
    let grid = input.lines().map(|l| l.as_bytes()).collect::<Vec<_>>();    
    let count = (1..grid.len() - 1).map(|y| {
            (1..grid[y].len() - 1).filter(|&x| is_x_mas(&grid, (x, y))).count()
        })
        .sum::<usize>();
    println!("{count}");
}

util::aoc_main!();

(also on github)

[โ€“] Gobbel2000 2 points 5 months ago

It really depends on what your parameter n is. If the only relevant size is the number of records (let's say that is n), then this solution takes time in O(n), because it loops over records only once at a time. This ignores the length of records by considering it constant.

If we also consider the maximum length of records (let's call it m), then your solution, and most others I've seen in this thread, has a time complexity in O(n * m^2) for part 2.

[โ€“] Gobbel2000 2 points 5 months ago (1 children)

Rust

Regex made this one pretty straightforward. The second part additionally looks for do() and don't() in the same regex, then we do a case distinction on the match.

use regex::{Regex, Captures};

fn mul_cap(cap: Captures) -> i32 {
    let a = cap.get(1).unwrap().as_str().parse::<i32>().unwrap();
    let b = cap.get(2).unwrap().as_str().parse::<i32>().unwrap();
    a * b
}

fn part1(input: String) {
    let re = Regex::new(r"mul\((\d{1,3}),(\d{1,3})\)").unwrap();
    let res = re.captures_iter(&input).map(mul_cap).sum::<i32>();
    println!("{res}");
}

fn part2(input: String) {
    let re = Regex::new(r"do\(\)|don't\(\)|mul\((\d{1,3}),(\d{1,3})\)").unwrap();
    let mut enabled = true;
    let mut res = 0;
    for cap in re.captures_iter(&input) {
        match cap.get(0).unwrap().as_str() {
            "do()" => enabled = true,
            "don't()" => enabled = false,
            _ if enabled => res += mul_cap(cap),
            _ => {}
        }
    }
    println!("{res}");
}

util::aoc_main!();
[โ€“] Gobbel2000 5 points 5 months ago (2 children)

Rust

The function is_sorted_by on Iterators turned out helpful for compactly finding if a report is safe. In part 2 I simply tried the same with each element removed, since all reports are very short.

fn parse(input: String) -> Vec<Vec<i32>> {
    input.lines()
        .map(|l| l.split_whitespace().map(|w| w.parse().unwrap()).collect())
        .collect()
}

fn is_safe(report: impl DoubleEndedIterator<Item=i32> + Clone) -> bool {
    let safety = |a: &i32, b: &i32| (1..=3).contains(&(b - a));
    report.clone().is_sorted_by(safety) || report.rev().is_sorted_by(safety)
}

fn part1(input: String) {
    let reports = parse(input);
    let safe = reports.iter().filter(|r| is_safe(r.iter().copied())).count();
    println!("{safe}");
}

fn is_safe2(report: &[i32]) -> bool {
    (0..report.len()).any(|i| {  // Try with each element removed
        is_safe(report.iter().enumerate().filter(|(j, _)| *j != i).map(|(_, n)| *n))
    })
}

fn part2(input: String) {
    let reports = parse(input);
    let safe = reports.iter().filter(|r| is_safe2(r)).count();
    println!("{safe}");
}

util::aoc_main!();
[โ€“] Gobbel2000 33 points 5 months ago (3 children)

The ruling party, recently reelected in a fraudulent election has declared that EU accession talks will be stopped until 2028. This has stoked ongoing protests over election results.

[โ€“] Gobbel2000 4 points 5 months ago

Rust

Right IDs are directly read into a hash map counter.

use std::str::FromStr;
use std::collections::HashMap;

fn part1(input: String) {
    let mut left = Vec::new();
    let mut right = Vec::new();
    for line in input.lines() {
        let mut parts = line.split_whitespace()
            .map(|p| u32::from_str(p).unwrap());
        left.push(parts.next().unwrap());
        right.push(parts.next().unwrap());
    }
    left.sort_unstable();
    right.sort_unstable();
    let diff: u32 = left.iter().zip(right)
        .map(|(l, r)| l.abs_diff(r))
        .sum();
    println!("{diff}");
}

fn part2(input: String) {
    let mut left = Vec::new();
    let mut right: HashMap<u32, u32> = HashMap::new();
    for line in input.lines() {
        let mut parts = line.split_whitespace()
            .map(|p| u32::from_str(p).unwrap());
        left.push(parts.next().unwrap());
        *right.entry(parts.next().unwrap()).or_default() += 1;
    }
    let similar: u32 = left.iter()
        .map(|n| n * right.get(n).copied().unwrap_or_default())
        .sum();
    println!("{similar}");
}

util::aoc_main!();
[โ€“] Gobbel2000 3 points 5 months ago

I have previously done it in Rust, but have toyed with the idea of taking this year as a reason for looking into OCaml.

[โ€“] Gobbel2000 5 points 5 months ago

I actually agree that I enjoyed playing the first more than the second. In the second, the story just didn't feel very gripping, progression was slow and gameplay ended up quite complicated with weird mechanics. But in the first game, the atmosphere, story and more distraction-free gameplay made up for the overall age of the game.

[โ€“] Gobbel2000 8 points 5 months ago
[โ€“] Gobbel2000 18 points 6 months ago (2 children)

I have been really happy with sway. It does all that I want it to do.

[โ€“] Gobbel2000 3 points 6 months ago

Is it a requirement for journalists now to not understand how the unit Watts works in relation to time?

view more: โ€น prev next โ€บ