1defmodule CollatzConjecture do
2 @moduledoc """
3 Documentation for `CollatzConjecture`.
4 """
5
6 require Integer
7
8 @doc """
9 Returns the next collatz term of the given `n`.
10
11 If `n` is even, return `n` divided by 2.
12 Otherwise, return 3 multiplied by `n`, plus 1.
13 """
14 @spec collatz(integer) :: integer
15 def collatz(n) when Integer.is_even(n) do
16 div(n, 2)
17 end
18
19 def collatz(n) do
20 3 * n + 1
21 end
22
23 @doc """
24 Returns a string containing the sequence of Collatz terms starting
25 from `n`.
26
27 During the :first iteration, there will be result in `n: ...`.
28 However, :continuing iterations will result in `n, ...`.
29 If `n` is 1 during :continuing iterations, the result will be
30 "1".
31 """
32 @spec collatz_sequence(integer, :first | :continuing) :: String.t()
33 def collatz_sequence(n, :first) do
34 "#{n}: " <> collatz_sequence(collatz(n), :continuing)
35 end
36
37 def collatz_sequence(n, :continuing) when n == 1 do
38 "1"
39 end
40
41 def collatz_sequence(n, :continuing) do
42 "#{n}, " <> collatz_sequence(collatz(n), :continuing)
43 end
44
45 @doc """
46 Returns a string containing the sequence of Collatz terms starting
47 from `n`.
48
49 This is an abstraction for collatz_sequence/2 which always starts
50 with `:first`.
51 """
52 @spec collatz_sequence(integer) :: String.t()
53 def collatz_sequence(n) do
54 collatz_sequence(n, :first)
55 end
56end