Snippet

advent_of_code/2024_4.rb
Code:
# Advent of Code 2024, Day 4: Ceres Search

# https://adventofcode.com/2024/day/4

require_relative './helpers.rb'

def part_one(d)
  c = 0
  d.size.times { |y|
    d[0].size.times { |x|
      next unless d[y][x] == 'X'
      # Bounds
      t, b, l, r =  y - 3 >= 0, y + 3 < d.size, x - 3 >= 0, x + 3 < d[0].size
      # Horizontal
      c += ((0..3).map { |m| d[y][x - m] }.join == 'XMAS' ? 1 : 0) if l
      c += ((0..3).map { |m| d[y][x + m] }.join == 'XMAS' ? 1 : 0) if r
      # Vertical
      c += ((0..3).map { |m| d[y - m][x] }.join == 'XMAS' ? 1 : 0) if t
      c += ((0..3).map { |m| d[y + m][x] }.join == 'XMAS' ? 1 : 0) if b
      # Diagonal
      c += ((0..3).map { |m| d[y + m][x + m] }.join == 'XMAS' ? 1 : 0) if b & r
      c += ((0..3).map { |m| d[y + m][x - m] }.join == 'XMAS' ? 1 : 0) if b & l
      c += ((0..3).map { |m| d[y - m][x + m] }.join == 'XMAS' ? 1 : 0) if t & r
      c += ((0..3).map { |m| d[y - m][x - m] }.join == 'XMAS' ? 1 : 0) if t & l
    }
  }
  return c
end

def part_two(d)
  c = 0
  d.size.times { |y|
    d[0].size.times { |x|
      # Skip edges
      next if (y == 0) | (x == 0) | (y == d.size - 1) | (x == d[0].size - 1)
      # Skip words without A in center
      next unless d[y][x] == 'A'
      # Get vertices
      v = [d[y - 1][x - 1], d[y - 1][x + 1], d[y + 1][x - 1], d[y + 1][x + 1]]
      # Skip matching vertices like 'MAM' and 'SAS'
      next if (v[0] == v[3]) | (v[1] == v[2])
      # Increment
      c += 1 if v.sort.join == 'MMSS'
    }
  }
  return c
end

def solve(data)
  data.map!(&:chars)
  [part_one(data), part_two(data)]
end

puts solve(get_dataset(year: 2024, day: 4, type: 'example'))
puts solve(get_dataset(year: 2024, day: 4, type: 'example_2'))
puts solve(get_dataset(year: 2024, day: 4, type: 'input'))
Output:
18
9
0
0
2397
1824