Skip to content

Instantly share code, notes, and snippets.

@jmikkola
Created December 4, 2024 18:09
Show Gist options
  • Save jmikkola/f606ef85ad7e3900d45cd7583aa89fc1 to your computer and use it in GitHub Desktop.
Save jmikkola/f606ef85ad7e3900d45cd7583aa89fc1 to your computer and use it in GitHub Desktop.
use std::env;
use std::fs;
fn get_arg() -> String {
let opt_filename = env::args().nth(1);
match opt_filename {
Some(f) => f,
None => "example".into(),
}
}
fn get_content(filename: String) -> String {
fs::read_to_string(filename)
.unwrap()
.trim()
.to_string()
}
fn split_lines(s: String) -> Vec<Vec<char>> {
s.split('\n')
.map(|line| line.chars().collect())
.collect()
}
#[derive(Debug, Clone, Copy)]
enum Direction {
NW,
N,
NE,
E,
SE,
S,
SW,
W
}
const DIRECTIONS: [Direction; 8] = [
Direction::NW,
Direction::N,
Direction::NE,
Direction::E,
Direction::SE,
Direction::S,
Direction::SW,
Direction::W,
];
fn part1(lines: &[Vec<char>]) -> i64 {
let mut total = 0;
for start_y in 0..lines.len() {
for start_x in 0..lines[0].len() {
let point: Point = (start_x as i32, start_y as i32);
for direction in DIRECTIONS.iter() {
total += search(lines, point, *direction, 0);
}
}
}
total
}
fn search(lines: &[Vec<char>], point: Point, direction: Direction, chars_seen: usize) -> i64 {
if !in_bounds(point, lines) {
return 0;
}
let current_char = lines[point.1 as usize][point.0 as usize];
let expected_char: char = "XMAS".chars().nth(chars_seen).unwrap();
if current_char != expected_char {
return 0;
}
if current_char == 'S' {
return 1;
}
search(lines, step(point, direction), direction, chars_seen + 1)
}
type Point = (i32, i32);
fn in_bounds(p: Point, lines: &[Vec<char>]) -> bool {
let (x, y) = p;
if x < 0 || y < 0 {
return false;
}
if y as usize >= lines.len() {
return false;
}
if x as usize >= lines[0].len() {
return false;
}
true
}
fn step(p: Point, direction: Direction) -> Point {
use Direction::*;
let y_offset = match direction {
NW | N | NE => -1,
W | E => 0,
SW | S | SE => 1,
};
let x_offset = match direction {
NW | W | SW => -1,
N | S => 0,
NE | E | SE => 1,
};
let (x, y) = p;
(x + x_offset, y + y_offset)
}
fn part2(lines: &[Vec<char>]) -> i64 {
use Direction::*;
let mut total = 0;
for start_y in 0..lines.len() {
for start_x in 0..lines[0].len() {
if lines[start_y][start_x] != 'A' {
continue;
}
let point: Point = (start_x as i32, start_y as i32);
if has_mas(lines, point, [NW, SE]) && has_mas(lines, point, [NE, SW]) {
total += 1;
}
}
}
total
}
fn has_mas(lines: &[Vec<char>], point: Point, directions: [Direction; 2]) -> bool {
let p1 = step(point, directions[0]);
let p2 = step(point, directions[1]);
if !in_bounds(p1, lines) || !in_bounds(p2, lines) {
return false;
}
let c1 = lines[p1.1 as usize][p1.0 as usize];
let c2 = lines[p2.1 as usize][p2.0 as usize];
(c1 == 'M' && c2 == 'S') || (c1 == 'S' && c2 == 'M')
}
fn main() {
let lines = split_lines(get_content(get_arg()));
println!("part 1: {}", part1(&lines));
println!("part 2: {}", part2(&lines));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment