ðŸŽ‰ Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io ðŸŽ‰

# angelikatyborska's solution

## to Pythagorean Triplet in the Elixir Track

Published at May 01 2021 · 0 comments
Instructions
Test suite
Solution

#### Note:

This exercise has changed since this solution was written.

A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for which,

a**2 + b**2 = c**2

For example,

3**2 + 4**2 = 9 + 16 = 25 = 5**2.

There exists exactly one Pythagorean triplet for which a + b + c = 1000.

Find the product a * b * c.

## Running tests

Execute the tests with:

\$ elixir pythagorean_triplet_test.exs

### Pending tests

In the test suites, all but the first test have been skipped.

Once you get a test passing, you can unskip the next one by commenting out the relevant @tag :pending with a # symbol.

For example:

# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end

Or, you can enable all the tests by commenting out the ExUnit.configure line in the test suite.

# ExUnit.configure exclude: :pending, trace: true

For more detailed information about the Elixir track, please see the help page.

## Source

Problem 9 at Project Euler http://projecteuler.net/problem=9

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### pythagorean_triplet_test.exs

if !System.get_env("EXERCISM_TEST_EXAMPLES") do
end

ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)

defmodule PythagoreanTripletTest do
use ExUnit.Case

# @tag :pending
test "sum" do
triplet = [3, 4, 5]
assert Triplet.sum(triplet) == 12
end

@tag :pending
test "product" do
triplet = [3, 4, 5]
assert Triplet.product(triplet) == 60
end

@tag :pending
test "pythagorean" do
triplet = [3, 4, 5]
assert Triplet.pythagorean?(triplet)
end

@tag :pending
test "not pythagorean" do
triplet = [5, 6, 7]
refute Triplet.pythagorean?(triplet)
end

@tag :pending
test "triplets up to 10" do
triplets = Triplet.generate(1, 10)
assert Enum.map(triplets, &Triplet.product/1) == [60, 480]
end

@tag :pending
test "triplets from 11 up to 20" do
triplets = Triplet.generate(11, 20)
assert Enum.map(triplets, &Triplet.product/1) == [3840]
end

@tag :pending
test "triplets where sum is 180 and max factor is 100" do
triplets = Triplet.generate(1, 100, 180)
assert Enum.map(triplets, &Triplet.product/1) == [118_080, 168_480, 202_500]
end
end
defmodule Triplet do
@doc """
Calculates sum of a given triplet of integers.
"""
@spec sum([non_neg_integer]) :: non_neg_integer
def sum(triplet) do
triplet
|> Enum.reduce(0, &Kernel.+/2)
end

@doc """
Calculates product of a given triplet of integers.
"""
@spec product([non_neg_integer]) :: non_neg_integer
def product(triplet) do
triplet
|> Enum.reduce(1, &Kernel.*/2)
end

@doc """
Determines if a given triplet is pythagorean. That is, do the squares of a and b add up to the square of c?
"""
@spec pythagorean?([non_neg_integer]) :: boolean
def pythagorean?([a, b, c]) do
:math.pow(a, 2) + :math.pow(b, 2) == :math.pow(c, 2)
end

@doc """
Generates a list of pythagorean triplets from a given min (or 1 if no min) to a given max.
"""
@spec generate(non_neg_integer, non_neg_integer) :: [list(non_neg_integer)]
def generate(min, max) do
max..min
|> Enum.reduce(
[],
fn a, acc ->
max..a
|> Enum.reduce(
acc,
fn b, acc2 ->
c = find_c(a, b)

if c <= max do
[[a, b, c] | acc2]
else
acc2
end
end
)
end
)
end

@doc """
Generates a list of pythagorean triplets from a given min to a given max, whose values add up to a given sum.
"""
@spec generate(non_neg_integer, non_neg_integer, non_neg_integer) :: [list(non_neg_integer)]
def generate(min, max, sum) do
generate(min, max)
|> Enum.filter(fn triplet -> sum(triplet) == sum end)
end

defp find_c(a, b) do
c_square = :math.pow(a, 2) + :math.pow(b, 2)
c = :math.pow(c_square, 0.5)

if c == Float.round(c) do
trunc(c)
else
nil
end
end
end