-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathday_16.ex
78 lines (61 loc) · 2.12 KB
/
day_16.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
defmodule AdventOfCode.Y2017.Day16 do
@moduledoc """
--- Day 16: Permutation Promenade ---
Problem Link: https://adventofcode.com/2017/day/16
Difficulty: m
Tags: op-code count
"""
alias AdventOfCode.Helpers.{InputReader, Transformers}
@dancers to_string(Enum.take(?a..?z, 16))
def input, do: InputReader.read_from_file(2017, 16)
def run(input \\ input()) do
moves = parse(input)
{dance(@dancers, moves), perform_billionth(@dancers, moves)}
end
defp perform_billionth(dancers, moves) do
count = rem(1_000_000_000, repeats_after(dancers, moves))
Enum.reduce(1..count, dancers, fn _, dancers -> dance(dancers, moves) end)
end
def parse(data \\ input()) do
for m <- Transformers.words(data, ","), do: parse_move(m)
end
@re ~r"^(.+)\/(.+)$"
defp parse_move("s" <> size), do: {:spin, String.to_integer(size)}
defp parse_move("p" <> rest),
do: {:partner, Enum.sort(Regex.run(@re, rest, capture: :all_but_first))}
defp parse_move("x" <> rest) do
{:exchange,
@re
|> Regex.run(rest, capture: :all_but_first)
|> then(&Enum.sort(Enum.map(&1, fn i -> String.to_integer(i) end)))}
end
defp dance(dancers, []), do: dancers
defp dance(dancers, [move | moves]) do
# So many repeating words :D
dance(dance(dancers, move), moves)
end
defp dance(dancers, {:exchange, [a, b]}) do
Enum.join([
String.slice(dancers, 0, a),
String.at(dancers, b),
String.slice(dancers, a + 1, b - a - 1),
String.at(dancers, a),
String.slice(dancers, (b + 1)..-1//1)
])
end
defp dance(dancers, {:spin, a}) do
String.slice(dancers, -a..-1//1) <> String.slice(dancers, 0..(-a - 1)//1)
end
defp dance(dancers, {:partner, [a, b]}) do
dancers
|> String.replace(a, "_")
|> String.replace(b, a)
|> String.replace("_", b)
end
defp repeats_after(dancers, moves), do: repeats_after(dancers, moves, 0, MapSet.new())
defp repeats_after(dancers, moves, count, done) do
dancers = dance(dancers, moves)
(MapSet.member?(done, dancers) && count) ||
repeats_after(dancers, moves, count + 1, MapSet.put(done, dancers))
end
end