🏡 index : ~doyle/aoc.git

author Jordan Doyle <jordan@doyle.la> 2024-12-07 17:14:56.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2024-12-07 17:14:56.0 +00:00:00
commit
8f51f3914effb85f9928b7d7b2349e07a104baf5 [patch]
tree
da620c24625f6dc83d9d1bb20b70908936fa8c56
parent
f3d5fcd51eb78cdb508868d829ef41741a3f8bcc
download
8f51f3914effb85f9928b7d7b2349e07a104baf5.tar.gz

Add 2024 day 4



Diff

 Cargo.toml |   4 ++++
 README     |   4 ++--
 2024/01.rs |   1 +
 2024/04.rs | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 116 insertions(+), 2 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 246299a..173c6d7 100644
--- a/Cargo.toml
+++ a/Cargo.toml
@@ -30,6 +30,10 @@
name = "aoc2024-01"
path = "2024/01.rs"

[[bin]]
name = "aoc2024-04"
path = "2024/04.rs"

[profile.release]
overflow-checks = true

diff --git a/README b/README
index 5d29f89..17ee834 100644
--- a/README
+++ a/README
@@ -17,8 +17,8 @@
|        1 | Rust     | |        1 | Haskell  | |        1 | Fortran  |
|        2 | OCaml    | |        2 | Haskell  | |        2 | Nix      |
|        3 | Perl     | |        3 | Haskell  | |        3 | Clojure  |
+---------------------+ |        4 | Haskell  | |        4 | Jsonnet  |
                        |        5 | Rust     | |        5 | HCL/TF   |
|        4 | Rust     | |        4 | Haskell  | |        4 | Jsonnet  |
+---------------------+ |        5 | Rust     | |        5 | HCL/TF   |
                        |        6 | Haskell  | |        6 | Apache2  |
                        |        7 | Haskell  | +---------------------+
                        |        8 | Haskell  |
diff --git a/2024/01.rs b/2024/01.rs
index 36325c2..e1bd931 100644
--- a/2024/01.rs
+++ a/2024/01.rs
@@ -1,4 +1,5 @@
#![feature(binary_heap_into_iter_sorted)]
#![allow(clippy::cast_possible_truncation)]
use std::{cmp::Reverse, collections::BinaryHeap, io::Read};

use itertools::Itertools;
diff --git a/2024/04.rs b/2024/04.rs
new file mode 100644
index 0000000..2509859 100644
--- /dev/null
+++ a/2024/04.rs
@@ -1,0 +1,109 @@
#![allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]

use std::io::Read;

use itertools::Itertools;

fn main() {
    let mut input = String::new();
    std::io::stdin().read_to_string(&mut input).unwrap();
    let input = input.trim();

    let rows = input.lines().count();
    let cols = input.split_once('\n').unwrap().0.len();

    let input = input.replace('\n', "");

    part1(&input, rows, cols);
    part2(&input, cols);
}

fn part1(input: &str, rows: usize, cols: usize) {
    const VARIANTS: &[[(isize, isize); 3]] = &[
        // forward
        [(1, 0), (2, 0), (3, 0)],
        // backwards
        [(-1, 0), (-2, 0), (-3, 0)],
        // downwards
        [(0, 1), (0, 2), (0, 3)],
        // upwards
        [(0, -1), (0, -2), (0, -3)],
        // diag up left
        [(-1, -1), (-2, -2), (-3, -3)],
        // diag up right
        [(1, -1), (2, -2), (3, -3)],
        // diag down right
        [(1, 1), (2, 2), (3, 3)],
        // diag down left
        [(-1, 1), (-2, 2), (-3, 3)],
    ];

    let char_at_pos = |n| &input[n..=n];
    let mut found = 0;

    let indicies = input
        .char_indices()
        .filter(|(_, c)| *c == 'X')
        .collect_vec();

    for (pos, _) in indicies {
        let curr_char_row = pos / cols;

        let get_at_offset = |&(x, y): &(isize, isize)| {
            char_at_pos((pos as isize + (cols as isize * y) + x) as usize)
        };

        for [v1, v2, v3] in VARIANTS {
            let (max_x, max_y) = v3;

            // if max_x will overflow the row, or if the max_y will take us outside of the grid,
            // skip
            if (pos as isize + max_x) / cols as isize != curr_char_row as isize
                || curr_char_row as isize + max_y < 0
                || curr_char_row as isize + max_y >= rows as isize
            {
                continue;
            }

            if get_at_offset(v1) == "M" && get_at_offset(v2) == "A" && get_at_offset(v3) == "S" {
                found += 1;
            }
        }
    }

    eprintln!("{found}");
}

fn part2(input: &str, cols: usize) {
    let char_at_pos = |n| &input[n..=n];
    let mut found = 0;

    let indicies = input
        .char_indices()
        .filter(|(_, c)| *c == 'A')
        .collect_vec();

    for (pos, _) in indicies {
        let get_at_offset =
            |(x, y): (isize, isize)| char_at_pos((pos as isize + (cols as isize * y) + x) as usize);

        if pos < cols || pos % cols < 1 || pos + cols > input.len() {
            continue;
        }

        let top_left = get_at_offset((-1, -1));
        let top_right = get_at_offset((1, -1));
        let bottom_left = get_at_offset((-1, 1));
        let bottom_right = get_at_offset((1, 1));

        match (top_left, top_right, bottom_left, bottom_right) {
            ("M", "S", "M", "S")
            | ("S", "M", "S", "M")
            | ("M", "M", "S", "S")
            | ("S", "S", "M", "M") => found += 1,
            _ => {}
        }
    }

    eprintln!("{found}");
}