2024-12-04

— 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?

Get files

Ruby:

# 
#   3   3   3
#    2  2  2
#     1 1 1
# 3 2 1 X 1 2 3
#     1 1 1
#    2  2  2
#   3   3   3

sum = 0

class Node
  attr_accessor :x, :y, :value

  def initialize(x,y,value)
    self.x = x
    self.y = y
    self.value = value
  end

  def to_s
    self.value
  end
end


def up(nodes, x,y)
  return "" if y < 3
  nodes[y - 1][x].to_s + nodes[y - 2][x].to_s + nodes[y - 3][x].to_s
end

def down(nodes, x,y)
  return "" if y >= nodes.size - 3
  nodes[y + 1][x].to_s + nodes[y + 2][x].to_s + nodes[y + 3][x].to_s
end

def left(nodes, x,y)
  return "" if x < 3
  nodes[y][x - 1].to_s + nodes[y][x - 2].to_s + nodes[y][x - 3].to_s
end

def right(nodes, x,y)
  return "" if x >= nodes[0].size - 3
  nodes[y][x + 1].to_s + nodes[y][x + 2].to_s + nodes[y][x + 3].to_s
end

def top_left(nodes, x,y)
  return "" if y < 3 || x < 3
  nodes[y - 1][x - 1].to_s + nodes[y - 2][x - 2].to_s + nodes[y - 3][x - 3].to_s
end

def top_right(nodes, x,y)
  return "" if x >= nodes[0].size - 3 || y < 3
  nodes[y - 1][x + 1].to_s + nodes[y - 2][x + 2].to_s + nodes[y - 3][x + 3].to_s
end

def bottom_right(nodes, x,y)
  return "" if x >= nodes[0].size - 3 || y >= nodes.size - 3
  nodes[y + 1][x + 1].to_s + nodes[y + 2][x + 2].to_s + nodes[y + 3][x + 3].to_s
end

def bottom_left(nodes, x,y)
  return "" if x < 3 || y >= nodes.size - 3
  nodes[y + 1][x - 1].to_s + nodes[y + 2][x - 2].to_s + nodes[y + 3][x - 3].to_s
end

nodes = []
x_nodes = []
y = 0
File.readlines("input.txt").each do |line|
  tmp = []
  line.chop.split("").each_with_index do |val, i|
    new_node = Node.new(i, y, val)
    x_nodes << new_node if new_node.value == "X"
    tmp <<  new_node
  end
  nodes << tmp
  y += 1
end

p x_nodes

x_nodes.each do |x|
  sum += 1 if up(nodes, x.x, x.y) == "MAS"
  sum += 1 if down(nodes, x.x, x.y) == "MAS"
  sum += 1 if left(nodes, x.x, x.y) == "MAS"
  sum += 1 if right(nodes, x.x, x.y) == "MAS"
  sum += 1 if top_left(nodes, x.x, x.y) == "MAS"
  sum += 1 if top_right(nodes, x.x, x.y) == "MAS"
  sum += 1 if bottom_left(nodes, x.x, x.y) == "MAS"
  sum += 1 if bottom_right(nodes, x.x, x.y) == "MAS"
end

p sum

— Part Two —

The Elf looks quizzically at you. Did you misunderstand the assignment?

Looking for the instructions, you flip over the word search to find that this isn't actually an XMAS puzzle; it's an X-MAS puzzle in which you're supposed to find two MAS in the shape of an X. One way to achieve that is like this:

M.S
.A.
M.S

Irrelevant characters have again been replaced with . in the above diagram. Within the X, each MAS can be written forwards or backwards.

Here's the same example from before, but this time all of the X-MASes have been kept instead:

.M.S......
..A..MSMS.
.M.S.MAA..
..A.ASMSM.
.M.S.M....
..........
S.S.S.S.S.
.A.A.A.A..
M.M.M.M.M.
..........

In this example, an X-MAS appears 9 times.

Flip the word search from the instructions back over to the word search side and try again. How many times does an X-MAS appear?

sum = 0

class Node
  attr_accessor :x, :y, :value

  def initialize(x,y,value)
    self.x = x
    self.y = y
    self.value = value
  end

  def to_s
    self.value
  end
end


def top_left(nodes, x,y)
  return "" if y < 1 || x < 1
  nodes[y - 1][x - 1].to_s
end

def top_right(nodes, x,y)
  return "" if x >= nodes[0].size - 1 || y < 1
  nodes[y - 1][x + 1].to_s
end

def bottom_right(nodes, x,y)
  return "" if x >= nodes[0].size - 1 || y >= nodes.size - 1
  nodes[y + 1][x + 1].to_s
end

def bottom_left(nodes, x,y)
  return "" if x < 1 || y >= nodes.size - 1
  nodes[y + 1][x - 1].to_s
end

nodes = []
a_nodes = []
y = 0
File.readlines("input.txt").each do |line|
  tmp = []
  line.chop.split("").each_with_index do |val, i|
    new_node = Node.new(i, y, val)
    a_nodes << new_node if new_node.value == "A"
    tmp <<  new_node
  end
  nodes << tmp
  y += 1
end

p a_nodes

a_nodes.each do |x|
  d1 = false
  d2 = false

  tmp = ""
  tmp += top_left(nodes, x.x, x.y)
  tmp += "A"
  tmp += bottom_right(nodes, x.x, x.y) 

  d1 = (tmp == "MAS" or tmp == "SAM")

  tmp = ""
  tmp += top_right(nodes, x.x, x.y) 
  tmp += "A"
  tmp += bottom_left(nodes, x.x, x.y) 

  d2 = (tmp == "MAS" or tmp == "SAM")

  sum += 1 if d1 && d2
end

p sum

Date: 2024-12-04 Wed 00:00

Author: Terry Fung

Created: 2025-03-02 Sun 22:47

Emacs 29.4 (Org mode 9.6.15)

Validate