-
-
Notifications
You must be signed in to change notification settings - Fork 409
Expand file tree
/
Copy pathexample.ex
More file actions
44 lines (36 loc) · 1.28 KB
/
example.ex
File metadata and controls
44 lines (36 loc) · 1.28 KB
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
defmodule Prism do
@doc """
Finds the sequence of prisms that the laser will hit.
"""
@type start :: %{angle: number(), x: number(), y: number()}
@type prism :: %{id: integer(), angle: number(), x: number(), y: number()}
@spec find_sequence(prisms :: [prism()], start :: start()) :: [integer()]
def find_sequence(prisms, start) do
find_next_prism(start, prisms, [])
end
@precision 0.01
defp find_next_prism(start, prisms, sequence) do
next_prism =
prisms
|> Enum.filter(fn %{x: x, y: y} ->
different_prism? = x != start.x or y != start.y
angle_to_prism = :math.atan2(y - start.y, x - start.x) / :math.pi() * 180
angle_difference = abs(:math.fmod(angle_to_prism - start.angle, 360))
pointing_to_prism? =
angle_difference < @precision or 360 - angle_difference < @precision
different_prism? and pointing_to_prism?
end)
|> Enum.min_by(
fn %{x: x, y: y} -> (x - start.x) ** 2 + (y - start.y) ** 2 end,
&<=/2,
fn -> nil end
)
case next_prism do
nil ->
Enum.reverse(sequence)
%{id: id, angle: angle, x: x, y: y} ->
next_start = %{angle: start.angle + angle, x: x, y: y}
find_next_prism(next_start, prisms, [id | sequence])
end
end
end