--- Day 4: Ceres Search ---

"Looks like the Chief's not here. Next!" One of The Historians pulls out a device and pushes the only button on it. After a brief flash, you recognize the interior of the Ceres monitoring station!

As the search for the Chief continues, a small Elf who lives on the station tugs on your shirt; she'd like to know if you could help her with her word search (your puzzle input). She only has to find one word: XMAS.

This word search allows words to be horizontal, vertical, diagonal, written backwards, or even overlapping other words. It's a little unusual, though, as you don't merely need to find one instance of XMAS - you need to find all of them. Here are a few ways XMAS might appear, where irrelevant characters have been replaced with .:

..X...
.SAMX.
.A..A.
XMAS.S
.X....
The actual word search will be full of letters instead. For example:

MMMSXXMASM
MSAMXMSMSA
AMXSXMAAMM
MSAMASMSMX
XMASAMXAMM
XXAMMXXAMA
SMSMSASXSS
SAXAMASAAA
MAMMMXMMMM
MXMXAXMASX
In this word search, XMAS occurs a total of 18 times; here's the same word search again, but where letters not involved in any XMAS have been replaced with .:

....XXMAS.
.SAMXMS...
...S..A...
..A.A.MS.X
XMASAMX.MM
X.....XA.A
S.S.S.S.SS
.A.A.A.A.A
..M.M.M.MM
.X.X.XMASX
Take a look at the little Elf's word search. How many times does XMAS appear?
#!/usr/bin/env ruby
# frozen_string_literal: true

input = File.readlines('./input.txt').map(&:chomp)

grid = []

input.each do |line|
  grid << line.split('')
end

matches = 0

# Brute force search
grid.each_index do |row_index|
  grid[row_index].each_index do |col_index|
    next unless grid[row_index][col_index] == 'X'

    if row_index - 3 >= 0
      # Upper diagonal to the left
      if col_index - 3 >= 0 &&
         grid[row_index - 1][col_index - 1] == 'M' &&
         grid[row_index - 2][col_index - 2] == 'A' &&
         grid[row_index - 3][col_index - 3] == 'S'
        matches += 1
      end

      # Straight up
      if grid[row_index - 1][col_index] == 'M' &&
         grid[row_index - 2][col_index] == 'A' &&
         grid[row_index - 3][col_index] == 'S'
        matches += 1
      end

      # Upper diagonal to the right
      if col_index + 3 < grid[row_index].size &&
         grid[row_index - 1][col_index + 1] == 'M' &&
         grid[row_index - 2][col_index + 2] == 'A' &&
         grid[row_index - 3][col_index + 3] == 'S'
        matches += 1
      end
    end

    if row_index + 3 < grid.size
      # Down diagonal to the left
      if col_index - 3 >= 0 &&
         grid[row_index + 1][col_index - 1] == 'M' &&
         grid[row_index + 2][col_index - 2] == 'A' &&
         grid[row_index + 3][col_index - 3] == 'S'
        matches += 1
      end

      # Straight down
      if grid[row_index + 1][col_index] == 'M' &&
         grid[row_index + 2][col_index] == 'A' &&
         grid[row_index + 3][col_index] == 'S'
        matches += 1
      end

      # Down diagonal to the right
      if col_index + 3 < grid[row_index].size &&
         grid[row_index + 1][col_index + 1] == 'M' &&
         grid[row_index + 2][col_index + 2] == 'A' &&
         grid[row_index + 3][col_index + 3] == 'S'
        matches += 1
      end
    end

    # Search to the left
    if col_index - 3 >= 0 &&
       grid[row_index][col_index - 1] == 'M' &&
       grid[row_index][col_index - 2] == 'A' &&
       grid[row_index][col_index - 3] == 'S'
      matches += 1
    end

    # Search to the right
    if col_index + 3 < grid[row_index].size &&
       grid[row_index][col_index + 1] == 'M' &&
       grid[row_index][col_index + 2] == 'A' &&
       grid[row_index][col_index + 3] == 'S'
      matches += 1
    end
  end
end

puts "Matches: #{matches}"