Skip to content

Instantly share code, notes, and snippets.

@gorkaio
Created May 7, 2020 08:18
Show Gist options
  • Save gorkaio/9ad92c25ef5d5ad13340008c68e343d8 to your computer and use it in GitHub Desktop.
Save gorkaio/9ad92c25ef5d5ad13340008c68e343d8 to your computer and use it in GitHub Desktop.
-module(assignment).
-export([bits/1,distance/2,perimeter/1,area/1]).
-export([bitsTest/0,perimeterTest/0,areaTest/0]).
% Bits %%%
%% Exposed bit counter function
bits(N) -> bits(N, 0).
%% Internal functions
%% Base cases: just one bit left, result is accumulator plus bit
bits(0, Acc) -> Acc;
bits(1, Acc) -> Acc + 1;
%% General case:
%% Divide by base and accumulate reminder (least significant bit).
%% Continue iterating with the integer division result (rest of bits).
bits(N, Acc) when N rem 2 == 0 ->
bits(N div 2, Acc);
bits(N, Acc) ->
bits(N div 2, Acc + 1).
%% Test
bitsTest() ->
0 = bits(0),
1 = bits(1),
1 = bits(2),
2 = bits(3),
1 = bits(4),
2 = bits(5),
2 = bits(6),
3 = bits(7),
1 = bits(8),
passed.
% Shapes %%%%
%% Perimeter
%% Special case: a dot perimeter is zero.
perimeter([{_X0, _Y0} | []]) -> 0.0;
%% Special case: a line perimeter is the length of the line.
perimeter([{_X0, _Y0} = P0 | [{_X1, _Y1} = P1 | []]]) ->
distance(P0, P1);
%% Triangle case:
%% Use the general case, but accept a triangle tuple as input.
perimeter({triangle, [{_X0,_Y0}, {_X1,_Y1}, {_X2,_Y2}] = Points}) ->
perimeter(Points);
%% General case:
%% Accumulate distances between the points and keep the starting point,
%% so we can return to it to close the polygon shape on last iteration.
perimeter([{_X0, _Y0} = P0 | [{_X1, _Y1} | _]] = Points) ->
perimeter(Points, P0, 0).
%% Basic case: we only have one point left, close the path using the starting point.
perimeter([{_X1, _Y1} = P1 | []], P0, Acc) ->
distance(P1, P0) + Acc;
%% General case: accumulate distance between two points and continue with the rest.
perimeter([P1 | [P2 | _] = R], P0, Acc) ->
perimeter(R, P0, Acc + distance(P1, P2)).
%% Test
perimeterTest() ->
0.0 = perimeter([{3,7}]),
2.0 = perimeter([{-2,0},{0,0}]),
10.47213595499958 = perimeter([{0,0}, {0,2}, {4,0}]),
10.47213595499958 = perimeter({triangle, [{0,0}, {0,2}, {4,0}]}),
8.0 = perimeter([{0,0},{0,2},{2,2},{2,0}]),
passed.
%% Area
%% Calculates area based on triangle points
area({triangle, [{X0,Y0}, {X1,Y1}, {X2,Y2}]}) ->
abs(X0*(Y1-Y2) + X1*(Y2-Y0) + X2*(Y0-Y1))/2.
%% Test
areaTest() ->
0.0 = area({triangle, [{0,2}, {0,27}, {0, 42}]}), % colinear points, area 0.0
222.50 = area({triangle, [{15,15}, {23,30}, {50,25}]}),
357.00 = area({triangle, [{31,-5}, {-5,10}, {21,19}]}),
passed.
%% Euclidean distance between two points
distance({X1, Y1}, {X2, Y2}) ->
math:sqrt(math:pow((X2-X1), 2) + math:pow((Y2-Y1), 2)).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment