Skip to content

Commit f1f4dd1

Browse files
committed
Refactor Aja based solutions
1 parent 14b8747 commit f1f4dd1

3 files changed

Lines changed: 115 additions & 96 deletions

File tree

lib/2017/day_17.ex

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,37 @@ defmodule AdventOfCode.Y2017.Day17 do
33
--- Day 17: Spinlock ---
44
Problem Link: https://adventofcode.com/2017/day/17
55
Difficulty: m
6-
Tags: vector random-access
6+
Tags: circular-buffer simulation
77
"""
8-
alias Aja.Vector
9-
108
def input, do: 394
119

1210
def run, do: {run_1(), run_2()}
1311

14-
@target 2017
12+
@target_1 2017
1513
defp run_1 do
16-
Vector.new([0])
17-
|> insert_nth(0, 0)
18-
|> then(fn buffer ->
19-
Vector.at(buffer, Aja.Enum.find_index(buffer, &(&1 == 2017)) + 1)
20-
end)
21-
end
22-
23-
defp insert_nth(buffer, _, @target), do: buffer
14+
step = input()
2415

25-
defp insert_nth(buffer, position, idx) do
26-
idx = idx + 1
27-
position = rem(position + input(), idx) + 1
28-
{left, right} = {Vector.take(buffer, position), Vector.drop(buffer, position)}
29-
buffer = left |> Vector.concat(Vector.new([idx])) |> Vector.concat(right)
16+
{buffer, _} =
17+
Enum.reduce(1..@target_1, {[0], 0}, fn i, {buf, pos} ->
18+
new_pos = rem(pos + step, i) + 1
19+
{List.insert_at(buf, new_pos, i), new_pos}
20+
end)
3021

31-
insert_nth(buffer, position, idx)
22+
idx = Enum.find_index(buffer, &(&1 == @target_1))
23+
Enum.at(buffer, rem(idx + 1, length(buffer)))
3224
end
3325

34-
@target 50_000_000
35-
defp run_2, do: find_idx_1_after(0, 0, 0)
26+
@target_2 50_000_000
27+
defp run_2 do
28+
step = input()
3629

37-
defp find_idx_1_after(_, @target, first), do: first
30+
{_, after_zero} =
31+
Enum.reduce(1..@target_2, {0, 0}, fn i, {pos, first} ->
32+
new_pos = rem(pos + step, i) + 1
33+
new_first = if new_pos == 1, do: i, else: first
34+
{new_pos, new_first}
35+
end)
3836

39-
defp find_idx_1_after(position, idx, first) do
40-
idx = idx + 1
41-
position = rem(position + input(), idx) + 1
42-
first = (position == 1 && idx) || first
43-
find_idx_1_after(position, idx, first)
37+
after_zero
4438
end
4539
end

lib/2023/day_12.ex

Lines changed: 73 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,78 +3,100 @@ defmodule AdventOfCode.Y2023.Day12 do
33
--- Day 12: Hot Springs ---
44
Problem Link: https://adventofcode.com/2023/day/12
55
Difficulty: xl
6-
Tags: memoization vector
6+
Tags: memoization
77
"""
88
alias AdventOfCode.Helpers.{InputReader, Transformers}
9-
alias Aja.Vector
109

1110
def input, do: InputReader.read_from_file(2023, 12)
1211

1312
def run(input \\ input()) do
14-
input = parse(input)
15-
16-
{total_arrangements(input, fn {spring, groups} ->
17-
arrangements({as_vector(spring), groups})
18-
end),
19-
total_arrangements(input, fn {spring, groups} ->
20-
arrangements(
21-
{[spring] |> List.duplicate(5) |> Enum.join("?") |> as_vector(),
22-
groups |> Vector.duplicate(5) |> Vector.flat_map(& &1)}
23-
)
24-
end)}
13+
parsed = parse(input)
14+
15+
res1 = compute(parsed, 1)
16+
res2 = compute(parsed, 5)
17+
18+
{res1, res2}
2519
end
2620

27-
defp total_arrangements(input, fun) do
28-
for {:ok, count} <- Task.async_stream(input, fun), reduce: 0 do
29-
acc -> acc + count
30-
end
21+
defp compute(parsed, multiplier) do
22+
parsed
23+
|> Task.async_stream(
24+
fn {springs, groups} ->
25+
unfolded_springs = List.duplicate(springs, multiplier) |> Enum.join("?")
26+
unfolded_groups = List.duplicate(groups, multiplier) |> List.flatten() |> List.to_tuple()
27+
28+
Process.get_keys() |> Enum.each(&Process.delete/1)
29+
do_count(unfolded_springs, unfolded_groups, 0, 0, 0)
30+
end,
31+
timeout: :infinity
32+
)
33+
|> Enum.reduce(0, fn {:ok, count}, acc -> acc + count end)
3134
end
3235

33-
def parse(data \\ input()) do
36+
def parse(data) do
3437
for line <- Transformers.lines(data) do
35-
[springs, data] = String.split(line, " ")
36-
{springs, Vector.new(Transformers.int_words(data, ","))}
38+
[springs, groups] = String.split(line, " ")
39+
{springs, Transformers.int_words(groups, ",")}
3740
end
3841
end
3942

40-
defp memoize(input, counts), do: Process.put(input, counts)
41-
defp memoized({_, _, _, _, _} = input), do: memoized(input, Process.get(input))
42-
defp memoized(input, nil), do: tap(arrangements(input), &memoize(input, &1))
43-
defp memoized(_, counts), do: counts
44-
defp as_vector(springs), do: Vector.new(String.graphemes(springs <> "."))
45-
defp arrangements({springs, groups}), do: arrangements({springs, groups, 0, 0, 0})
46-
47-
defp arrangements({springs, groups, current, current_count, processed} = input) do
48-
case {Vector.at(springs, current), Vector.size(springs), Vector.size(groups)} do
49-
{_, ^current, ^processed} -> tap(1, &memoize(input, &1))
50-
{_, ^current, _} -> tap(0, &memoize(input, &1))
51-
{"#", _, _} -> memoized({springs, groups, current + 1, current_count + 1, processed})
52-
{".", _, _} -> arrangements(input, :operational)
53-
{_, _, ^processed} -> arrangements(input, :operational)
54-
_ -> arrangements(input, :unknown)
43+
defp do_count(springs, groups, s_idx, g_idx, current_count) do
44+
key = {s_idx, g_idx, current_count}
45+
46+
case Process.get(key) do
47+
nil ->
48+
res = calc(springs, groups, s_idx, g_idx, current_count)
49+
Process.put(key, res)
50+
res
51+
52+
val ->
53+
val
5554
end
5655
end
5756

58-
defp arrangements({springs, groups, current, current_count, processed} = input, :operational) do
59-
groups_processed = Vector.at(groups, processed)
57+
defp calc(springs, groups, s_idx, g_idx, current_count) do
58+
if s_idx == byte_size(springs) do
59+
cond do
60+
g_idx == tuple_size(groups) and current_count == 0 -> 1
61+
g_idx == tuple_size(groups) - 1 and current_count == elem(groups, g_idx) -> 1
62+
true -> 0
63+
end
64+
else
65+
char = :binary.at(springs, s_idx)
6066

61-
case {processed < Vector.size(groups), current_count} do
62-
{true, ^groups_processed} -> memoized({springs, groups, current + 1, 0, processed + 1})
63-
{_, 0} -> memoized({springs, groups, current + 1, 0, processed})
64-
_ -> tap(0, fn zero -> memoize(input, zero) end)
67+
case char do
68+
?# ->
69+
handle_hash(springs, groups, s_idx, g_idx, current_count)
70+
71+
?. ->
72+
handle_dot(springs, groups, s_idx, g_idx, current_count)
73+
74+
?? ->
75+
handle_dot(springs, groups, s_idx, g_idx, current_count) +
76+
handle_hash(springs, groups, s_idx, g_idx, current_count)
77+
end
6578
end
6679
end
6780

68-
defp arrangements({springs, groups, current, current_count, processed} = input, :unknown) do
69-
groups_processed = Vector.at(groups, processed)
81+
defp handle_hash(springs, groups, s_idx, g_idx, current_count) do
82+
if g_idx < tuple_size(groups) and current_count < elem(groups, g_idx) do
83+
do_count(springs, groups, s_idx + 1, g_idx, current_count + 1)
84+
else
85+
0
86+
end
87+
end
7088

71-
tap(
72-
case current_count do
73-
^groups_processed -> memoized({springs, groups, current + 1, 0, processed + 1})
74-
0 -> memoized({springs, groups, current + 1, 0, processed})
75-
_ -> 0
76-
end + memoized({springs, groups, current + 1, current_count + 1, processed}),
77-
fn counts -> memoize(input, counts) end
78-
)
89+
defp handle_dot(springs, groups, s_idx, g_idx, current_count) do
90+
case current_count do
91+
0 ->
92+
do_count(springs, groups, s_idx + 1, g_idx, 0)
93+
94+
n ->
95+
if g_idx < tuple_size(groups) and n == elem(groups, g_idx) do
96+
do_count(springs, groups, s_idx + 1, g_idx + 1, 0)
97+
else
98+
0
99+
end
100+
end
79101
end
80102
end

lib/2023/day_15.ex

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ defmodule AdventOfCode.Y2023.Day15 do
33
--- Day 15: Lens Library ---
44
Problem Link: https://adventofcode.com/2023/day/15
55
Difficulty: s
6-
Tags: hash ordered-map
6+
Tags: hash ordered-list
77
"""
88
alias AdventOfCode.Helpers.InputReader
9-
alias Aja.OrdMap
109

1110
def input, do: InputReader.read_from_file(2023, 15)
1211

@@ -21,36 +20,40 @@ defmodule AdventOfCode.Y2023.Day15 do
2120
input
2221
|> parse_2()
2322
|> Enum.reduce(%{}, fn
24-
{op, b, len}, acc ->
25-
hash = hash(b)
23+
{:add, label, len}, boxes ->
24+
h = hash(label)
2625

27-
case op do
28-
:add -> Map.update(acc, hash, OrdMap.new(%{b => len}), &OrdMap.put(&1, b, len))
29-
:remove -> Map.update(acc, hash, OrdMap.new(%{}), &OrdMap.drop(&1, [b]))
30-
end
26+
Map.update(boxes, h, [{label, len}], fn lenses ->
27+
if List.keymember?(lenses, label, 0) do
28+
List.keyreplace(lenses, label, 0, {label, len})
29+
else
30+
lenses ++ [{label, len}]
31+
end
32+
end)
33+
34+
{:remove, label}, boxes ->
35+
h = hash(label)
36+
Map.update(boxes, h, [], &List.keydelete(&1, label, 0))
3137
end)
3238
|> total_focus()
3339
end
3440

35-
defp total_focus(map) do
36-
Enum.reduce(map, 0, fn {box, boxes}, acc ->
41+
defp total_focus(boxes) do
42+
Enum.reduce(boxes, 0, fn {box_idx, lenses}, acc ->
3743
acc +
38-
(boxes
39-
|> OrdMap.to_list()
40-
|> Enum.with_index(1)
41-
|> Enum.reduce(0, &(&2 + row_focus(&1, box))))
44+
Enum.reduce(Enum.with_index(lenses, 1), 0, fn {{_, len}, slot}, inner_acc ->
45+
inner_acc + (box_idx + 1) * slot * len
46+
end)
4247
end)
4348
end
4449

45-
defp row_focus({{_, len}, slot}, box), do: (box + 1) * slot * len
46-
47-
def parse_1(input \\ input()), do: String.split(input, ",", trim: true)
50+
defp parse_1(input), do: String.split(input, ",", trim: true) |> Enum.map(&String.trim/1)
4851

49-
def parse_2(commands) do
52+
defp parse_2(commands) do
5053
Enum.map(commands, fn cmd ->
5154
case Regex.run(~r{([a-zA-Z]+)(=|-)([0-9]*)}, cmd) do
5255
[_, label, "=", len] -> {:add, label, String.to_integer(len)}
53-
[_, label, "-", ""] -> {:remove, label, 0}
56+
[_, label, "-", ""] -> {:remove, label}
5457
end
5558
end)
5659
end

0 commit comments

Comments
 (0)