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
|
defmodule Day22 do
def part1(data, n \\ 2000) do
data
|> String.split("\n", trim: true)
|> Enum.map(&String.to_integer/1)
|> Enum.map(&(secret_numbers(&1, n)))
|> Enum.map(&hd/1)
|> Enum.sum()
end
defp secret_numbers(v, n) do
for _ <- 1..n, reduce: [v] do
v ->
[(v |> hd() |> change_value(6) |> change_value(-5) |> change_value(11)) | v]
end
end
defp change_value(v, shift) do
v
|> Bitwise.bsl(shift)
|> Bitwise.bxor(v)
|> Integer.mod(16777216)
end
def part2(data, n \\ 2000) do
data
|> String.split("\n", trim: true)
|> Enum.map(&String.to_integer/1)
|> Enum.map(&(secret_numbers(&1, n)))
|> Enum.map(&(sequences(&1, 10)))
|> Enum.reduce(%{}, fn s, acc ->
Map.merge(acc, s, fn _k, v1, v2 -> v1 + v2 end)
end)
|> Map.values()
|> Enum.max()
end
defp sequences(vs, m) do
vs
|> Enum.map(&Integer.mod(&1, m))
|> Enum.chunk_every(5, 1, :discard) # performance here could be improved
|> Enum.map(fn chunk -> {diffs(chunk), hd(chunk)} end)
|> Map.new()
end
defp diffs(vs) do
vs
|> Enum.chunk_every(2, 1, :discard)
|> Enum.map(fn [a, b] -> a - b end)
|> List.to_tuple()
end
end
data = IO.read(:stdio, :eof)
{time1, ans1} = :timer.tc(fn -> Day22.part1(data) end)
IO.puts("Time : #{time1 / 1000000}")
IO.puts("Answer: #{ans1}") # 19822877190
{time2, ans2} = :timer.tc(fn -> Day22.part2(data) end)
IO.puts("Time : #{time2 / 1000000}")
IO.puts("Answer: #{ans2}") # 2277
|