From the Polaris easter egg hunt 2025
defmodule Tesser do
defstruct [:position, :symbols, :treasure_positions]
def new(symbol),
do: %__MODULE__{
position: {0, 0, 0, 0},
symbols: %{{0, 0, 0, 0} => symbol},
treasure_positions: []
}
def left(tesser, symbols), do: move(tesser, {-1, 0, 0, 0}, symbols)
def right(tesser, symbols), do: move(tesser, {1, 0, 0, 0}, symbols)
def up(tesser, symbols), do: move(tesser, {0, -1, 0, 0}, symbols)
def down(tesser, symbols), do: move(tesser, {0, 1, 0, 0}, symbols)
def forward(tesser, symbols), do: move(tesser, {0, 0, -1, 0}, symbols)
def back(tesser, symbols), do: move(tesser, {0, 0, 1, 0}, symbols)
def kata(tesser, symbols), do: move(tesser, {0, 0, 0, -1}, symbols)
def ana(tesser, symbols), do: move(tesser, {0, 0, 0, 1}, symbols)
defp move(tesser, offset, symbols) do
symbols
|> Enum.reduce({tesser, tesser.position}, fn symbol, {tesser, position} ->
position = translate(position, offset)
{put_symbol(tesser, position, symbol), position}
end)
|> elem(0)
|> Map.put(:position, translate(tesser.position, offset))
end
def treasure(tesser) do
Map.update!(tesser, :treasure_positions, &[tesser.position | &1])
end
def locate_treasure(tesser) do
Enum.map(tesser.treasure_positions, &tesser.symbols[&1])
end
defp translate({a, b, c, d}, {aa, bb, cc, dd}) do
{a + aa, b + bb, c + cc, d + dd}
end
defp put_symbol(tesser, _position, nil), do: tesser
defp put_symbol(tesser, position, symbol) do
%{tesser | symbols: Map.put(tesser.symbols, position, symbol)}
end
endTesser.new(:rocket)
|> Tesser.forward([:sun, :cup, :probe, :fan])
|> Tesser.right([:helmet, :clock, :head, :flag])
|> Tesser.up([:comet, :bag, :pole, :rock])
|> Tesser.left([:plank, :magnet, :constellation, :shark])
|> Tesser.down([nil, :ship, :pie, :lamp])
|> Tesser.treasure()
|> Tesser.kata([:board, :man, :dice, :sword])
|> Tesser.left([:crown, :arrow, :galaxy, :camera])
|> Tesser.ana([:anchor, :book, :hourglass, :meteor])
|> Tesser.ana([:book, :hourglass, :meteor, :compass])
|> Tesser.right([:poop, :cloud, :globe, :pen])
|> Tesser.kata([])
|> Tesser.down([])
|> Tesser.treasure()
|> Tesser.locate_treasure()