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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
defmodule Day09 do
def part1(data) do
values = data
|> String.split("\n", trim: true)
|> hd()
|> String.codepoints()
|> Enum.map(& String.to_integer/1)
files = values
|> Enum.take_every(2)
|> Enum.with_index()
|> Enum.flat_map(fn {v, i} -> Stream.cycle([i]) |> Enum.take(v) end)
revfiles = files
|> Enum.reverse()
v2 = values
|> Enum.with_index()
|> Enum.flat_map(fn {v, i} -> Stream.cycle([i]) |> Enum.take(v) end)
|> Enum.with_index()
c1 = v2
|> Enum.filter(fn {i, _} -> rem(i, 2) == 0 end)
|> Enum.zip(files)
c2 = v2
|> Enum.filter(fn {i, _} -> rem(i, 2) == 1 end)
|> Enum.zip(revfiles)
(c1 ++ c2)
|> Enum.sort_by(fn {{_, i}, _} -> i end)
|> Enum.take(Enum.count(files))
|> Enum.map(fn {{_, i}, v} -> i*v end)
|> Enum.sum()
end
def part2(data) do
values = data
|> String.split("\n", trim: true)
|> hd()
|> String.codepoints()
|> Enum.map(& String.to_integer/1)
|> Enum.scan({0, 0}, fn v, {o, i} -> {v, o+i} end)
spaces = values
|> tl()
|> Enum.take_every(2)
values
|> Enum.take_every(2)
|> Enum.with_index()
|> Enum.reverse()
|> locations(spaces)
|> Enum.map(fn {a, b, i} -> i*Enum.sum(b..b+a-1) end)
|> Enum.sum()
end
defp locations(acc \\ [], revfiles, spaces)
# a (block size), b (block position), i (block index)
# c (space size), d (space position)
# IMPROVE ME: since there are at most 9 sizes, we could keep the
# locations of the spaces in a tree for each size, and achieve
# better performance, might do it later..
defp locations(acc, [{{a, b}, i} | t], spaces) do
spaces = Enum.filter(spaces, fn {_, d} -> d < b end)
s = spaces
|> Enum.filter(fn {c, _} -> c >= a end)
|> Enum.min_by(fn {_, d} -> d end, &<=/2, fn -> nil end)
if s == nil do
locations([{a, b, i} | acc], t, spaces)
else
spaces = List.delete(spaces, s)
{c, d} = s
spaces =
if c == a do
spaces
else
[{c-a, d+a} | spaces]
end
locations([{a, d, i} | acc], t, spaces)
end
end
defp locations(acc, [], _) do
acc
end
end
data = IO.read(:stdio, :eof)
{time1 , ans1} = :timer.tc(fn -> Day09.part1(data) end)
IO.puts("Time : #{time1 / 1000000}")
IO.puts("Answer: #{ans1}")
{time2 , ans2} = :timer.tc(fn -> Day09.part2(data) end)
IO.puts("Time : #{time2 / 1000000}")
IO.puts("Answer: #{ans2}")
|