# Day 4: Ceres Search
```elixir
Mix.install([
{:kino_aoc, "~> 0.1.7"}
])
```
## Part One
"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](https://adventofcode.com/2019/day/10)!
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?_
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI0Iiwic2Vzc2lvbl9zZWNyZXQiOiJBT0MyMDI0X1NFU1NJT04iLCJ5ZWFyIjoiMjAyNCJ9","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
```elixir
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2024", "4", System.fetch_env!("LB_AOC2024_SESSION"))
```
```elixir
defmodule EnumUtil do
def transpose(list_of_lists) do
Enum.zip_with(list_of_lists, &Function.identity/1)
end
def rotate(list, n) do
{a, b} = Enum.split(list, n)
b ++ a
end
end
word_search = String.split(puzzle_input)
diag_grids =
word_search
|> Enum.map(&String.pad_trailing(&1, length(word_search) + String.length(&1)))
|> Enum.map(&to_charlist/1)
|> Enum.with_index(&EnumUtil.rotate/2)
|> EnumUtil.transpose()
|> Enum.chunk_every(2)
|> EnumUtil.transpose()
|> Enum.map(fn diagRows -> Enum.with_index(diagRows, &EnumUtil.rotate(&1, -&2)) |> EnumUtil.rotate(div(length(word_search), 2)) end)
word_search_grid =
Enum.map(word_search, &String.to_charlist/1)
grids = [word_search_grid | diag_grids]
grids
|> Enum.flat_map(&[&1, EnumUtil.transpose(&1)])
|> Enum.concat()
|> Enum.join("\n")
|> then(&Regex.scan(~r/X(?=MAS)|S(?=AMX)/, &1))
|> Enum.count()
```
## Part 2
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 <span title="This part originally involved searching for something else, but this joke was too dumb to pass up."><code><em>X-MAS</em></code></span> 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-MAS`es 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?_
```elixir
diag_grids
|> Enum.flat_map(fn grid ->
for {row, rowIdx} <- Enum.with_index(grid) |> Enum.drop(1),
{slice, colIdx} <- Enum.chunk_every(row, 3, 1, :discard) |> Enum.with_index(1),
slice in [~c/SAM/, ~c/MAS/],
Enum.map([-1, +1], &Enum.at(Enum.at(grid, rowIdx + &1, []), colIdx)) in [~c/SM/, ~c/MS/] do
{rowIdx, colIdx}
end
end)
|> Enum.count()
```
<!-- livebook:{"offset":4182,"stamp":{"token":"XCP.3KcHMfvZRwnXfzRym_G77w1d-wvbpjOn8N1EPXrvj3HQSmh9aFmsEcp-4auB9d--5TlNj9CWojQVMIN0Vaq11Anz8bOV2uguCB5la5fBLrIThrRRHvg-Csix","version":2}} -->