Created
February 25, 2017 14:11
-
-
Save NeilMadden/5dc2994e645d3f8e9503c0ad640adbaa to your computer and use it in GitHub Desktop.
Neil Madden Erlang MOOC assignment 1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% Functional Programming in Erlang MOOC | |
% Week 1 assignment submission - Neil Madden | |
-module(ex). | |
-export([perimeter/1,area/1,enclose/1,bits/1]). | |
% Type definitions! Found out Erlang supports these... | |
-type point() :: {number(), number()}. | |
-type circle() :: {circle, point(), number()}. | |
-type rectangle() :: {rectangle, point(), number(), number()}. | |
-type triangle() :: {triangle, point(), point(), point()}. | |
-type shape() :: circle() | rectangle() | triangle(). | |
% area/1 -- calculates the area of a shape | |
-spec area(shape()) -> number(). | |
area({circle, _, R}) -> | |
math:pi() * math:pow(R,2); | |
area({rectangle, _, W, H}) -> | |
W*H; | |
area({triangle, {X0,Y0}, {X1,Y1}, {X2,Y2}}) -> | |
% Area of an arbitrary triangle given vertices, from | |
% http://www.mathopenref.com/coordtrianglearea.html | |
% Had to look this up as it's been too long since I did GCSE maths! | |
abs((X0*(Y1-Y2) + X1*(Y2-Y0) + X2*(Y0-Y1)) / 2.0). | |
% perimeter/1 -- calculates the perimeter of a shape | |
-spec perimeter(shape()) -> number(). | |
perimeter({rectangle,_,H,W}) -> | |
2 * (H + W); | |
perimeter({circle,_,R}) -> | |
2 * math:pi() * R; | |
perimeter({triangle,P1,P2,P3}) -> | |
distance(P1, P2) + distance(P2,P3) + distance(P1,P3). | |
% enclose/1 -- calculates the bounding box of a shape | |
-spec enclose(shape()) -> rectangle(). | |
enclose({rectangle,P,W,H}) -> | |
{rectangle,P,W,H}; % Probably a simpler way to define this, maybe an is_rect macro? | |
enclose({circle, {X,Y}, R}) -> | |
% Subtract radius from X and Y coords of centre point to get bottom-left, then the width | |
% and height are just twice the radius. | |
{rectangle, {X-R,Y-R}, 2*R, 2*R}; | |
enclose({triangle, {X0,Y0}, {X1,Y1}, {X2,Y2}}) -> | |
% Use minThree/3 previously defined (and maxThree/3) to determine least and greatest | |
% bound coordinates of the three points. | |
Left = minThree(X0, X1, X2), | |
Right = maxThree(X0, X1, X2), | |
Bottom = minThree(Y0, Y1, Y2), | |
Top = maxThree(Y0, Y1, Y2), | |
{rectangle, {Left,Bottom}, Right-Left, Top-Bottom}. | |
% minThree/3 -- returns the minimum of 3 numbers | |
-spec minThree(number(), number(), number()) -> number(). | |
minThree(X, Y, Z) -> | |
min(X, min(Y, Z)). | |
% maxThree/3 -- returns the maximum of 3 numbers | |
-spec maxThree(number(), number(), number()) -> number(). | |
maxThree(X, Y, Z) -> | |
max(X, max(Y, Z)). | |
% distance/2 -- calculates the straight-line distance between two points | |
-spec distance(point(), point()) -> number(). | |
distance({X0,Y0}, {X1,Y1}) -> | |
% Pythagoras... | |
math:sqrt(math:pow(X1-X0,2) + math:pow(Y1-Y0,2)). | |
% bits/1 -- returns the sum of the bits in the binary representation of the given integer | |
-spec bits(non_neg_integer()) -> integer(). | |
bits(N) -> bits_iter(N, 0). % Call tail-recursive helper | |
% bits_iter/2 -- tail-recursive helper for calculating bits/1. | |
-spec bits_iter(non_neg_integer(), non_neg_integer()) -> non_neg_integer(). | |
bits_iter(0, A) -> A; | |
bits_iter(1, A) -> 1 + A; | |
bits_iter(N, A) when N > 1 -> | |
bits_iter(N div 2, A + N rem 2). | |
% Direct recursive version of bits would look like: | |
% bits(0) -> 0; | |
% bits(1) -> 1; | |
% bits(N) when N > 1 -> N rem 2 + bits(N rem 2). | |
% | |
% The tail-recursive/iterative version is better because it runs in constant space. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have interpreted the rectangle
{rectangle, Point, Width, Height}
with the point being the bottom-left coordinate. Re-watching the videos I see it was supposed to be the centre point, so my solution is different due to that.