Skip to content

Instantly share code, notes, and snippets.

@sasa1977
Last active December 16, 2017 11:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sasa1977/5f59e07c9624c279144fc93eb7004fd2 to your computer and use it in GitHub Desktop.
Save sasa1977/5f59e07c9624c279144fc93eb7004fd2 to your computer and use it in GitHub Desktop.
defmodule Day16 do
def part1(), do:
new_group() |> dance(instructions()) |> programs() |> Enum.join()
def part2(), do:
dances(1_000_000_000, instructions())
defp dances(num_dances, instructions) do
{found_orders, cycle_start_pos, cycle_length} = search_cycle(instructions)
desired_pos = rem(num_dances - cycle_start_pos, cycle_length)
{order, _} = Enum.find(found_orders, &match?({_order, ^desired_pos}, &1))
order
end
defp search_cycle(instructions, group \\ new_group(), found_orders \\ %{}, pos \\ 0) do
programs = Enum.join(programs(group))
case Map.fetch(found_orders, programs) do
:error ->
next = dance(group, instructions)
search_cycle(instructions, next, Map.put(found_orders, programs, pos), pos + 1)
{:ok, cycle_start_pos} ->
{found_orders, cycle_start_pos, pos - cycle_start_pos}
end
end
defp instructions(), do:
"input.txt"
|> File.read!()
|> String.trim()
|> String.split(",")
|> Enum.map(&decode_instruction/1)
defp decode_instruction(<<?s, spin::binary>>), do:
{:spin, String.to_integer(spin)}
defp decode_instruction(<<?x, positions::binary>>), do:
{:exchange_by_pos, [_, _] = positions |> String.split("/") |> Enum.map(&String.to_integer/1)}
defp decode_instruction(<<?p, positions::binary>>), do:
{:exchange_by_name, [_, _] = positions |> String.split("/") |> Enum.map(&String.to_atom/1)}
defp dance(group, instructions), do:
Enum.reduce(instructions, group, &apply_instruction(&2, &1))
defp new_group() do
{prog_to_pos, pos_to_prog} =
?a..?p
|> Enum.map(&:"#{[&1]}")
|> Stream.with_index()
|> Stream.map(fn {prog, pos} -> {{prog, pos}, {pos, prog}} end)
|> Enum.unzip()
%{prog_to_pos: Map.new(prog_to_pos), pos_to_prog: Map.new(pos_to_prog)}
end
defp programs(group), do:
group.pos_to_prog
|> Enum.sort()
|> Enum.map(fn {_pos, prog} -> prog end)
defp apply_instruction(group, {:spin, amount}), do:
group.prog_to_pos
|> Stream.map(fn {prog, pos} -> {prog, rem(pos + amount, 16)} end)
|> Enum.reduce(group, fn {prog, pos}, group -> update(group, prog, pos) end)
defp apply_instruction(group, {:exchange_by_pos, [pos1, pos2]}) do
%{pos_to_prog: %{^pos1 => prog1, ^pos2 => prog2}} = group
group
|> update(prog1, pos2)
|> update(prog2, pos1)
end
defp apply_instruction(group, {:exchange_by_name, [prog1, prog2]}) do
%{prog_to_pos: %{^prog1 => pos1, ^prog2 => pos2}} = group
group
|> update(prog1, pos2)
|> update(prog2, pos1)
end
defp update(group, prog, pos), do:
%{group |
prog_to_pos: %{group.prog_to_pos | prog => pos},
pos_to_prog: %{group.pos_to_prog | pos => prog},
}
end
Day16.part1() |> IO.puts
Day16.part2() |> IO.puts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment