Classify Quadrilaterals | Help me with my math exam! Help! My math exam is coming up soon and I didn't study! 1 Part of the exam is to classify a quadrilateral given its vertex coordinates, which I, unfortunately, do not know how to do. 2

So, your challenge is to write a program to do this for me so I don't fail!

Challenge

Given four vertices such that no three of them are colinear, determine the most specific classification of the quadrilateral formed by those four vertices.

What I mean by "most specific classification" is that even though all squares are rectangles, if the shape is a square, you should indicate that it is a square and not indicate that it is a rectangle.

Input

Input will be given as four (x, y) coordinates. You may take these as a list of length 4 of lists/tuples of length 2. Alternatively, you can take input as a list of the x-coordinates and a list of the respective y-coordinates.

For example, if my shape has vertices at points (0, 0), (5, 0), (6, 1), and (1, 1), you may choose to take input in either of the following formats or something similar:

[(0, 0), (5, 0), (6, 1), (1, 1)]
([0, 5, 6, 1], [0, 0, 1, 1])


You may assume that the quadrilateral is not self-intersecting and that the points are given in the correct order (that is, two consecutive points in the input will be connected by a line segment in the quadrilateral).

Output

You will need a unique output for each of the following classes of quadrilaterals:


Square
Rectangle
Rhombus
Parallelogram
Trapezoid/Trapezium
Kite
Quadrilateral


This could be the exact name itself, a character, an integer, etc.

Rules


Standard Loopholes Apply  
If your programming language has a built-in that will perform this exact task, that built-in is not allowed.  
Built-ins for finding the distance between two points are allowed.  
Built-ins for finding the angle between two lines are allowed.  


At this point, if you know all of the terms, you are ready to start programming! (Test Cases are at the end)

Terminology

This section is for anyone who needs clarification on the definitions of the different shapes.

Square

A quadrilateral is a square if and only if all 4 of its sides are equal in length and every pair of adjacent sides is perpendicular (that is, it is both a rectangle and a rhombus).

Rectangle

A quadrilateral is a rectangle if and only if every pair of adjacent sides is perpendicular.

Rhombus

A quadrilateral is a rhombus if and only if all 4 of its sides are equal.

Parallelogram

A quadrilateral is a parallelogram if and only if each pair of opposite sides is parallel and each pair of opposite angles is equal. Both of these conditions imply each other so you only need to check for one of them.

Trapezoid/Trapezium

A quadrilateral is a trapezoid/trapezium if and only if it has at least one pair of parallel sides.

Kite

A quadrilateral is a kite if two opposite pairs of adjacent sides are equal in length; that is, two of its adjacent sides are equal and the other two are also equal.

Test Cases

input as (x, y) * 4 -&gt; full name
[(0, 0), (1, 0), (1, 1), (0, 1)] -&gt; square
[(0, 0), (1, 1), (-1, 3), (-2, 2)] -&gt; rectangle
[(0, 0), (5, 0), (8, 4), (3, 4)] -&gt; rhombus
[(0, 0), (5, 0), (6, 1), (1, 1)] -&gt; parallelogram
[(0, 0), (4, 0), (3, 1), (1, 1)] -&gt; trapezoid/trapezium
[(0, 0), (1, 1), (0, 3), (-1, 1)] -&gt; kite  
[(0, 0), (2, 0), (4, 4), (0, 1)] -&gt; quadrilateral


Links (Desmos Graphing Calculator)

Here are links to visualizations of each of the test cases.

Square
Rectangle
Rhombus
Parallelogram
Trapezoid/Trapezium
Kite
Quadrilateral  

Winning Criteria

I can't bring a computer into the exam obviously, so I need you to write the shortest code possible so I can memorize it. I need to write it into the margins and run it using TryItOfflineTM so to fit it into the margins your program needs to be as small as possible!

1 Of course I actually did :P
2 Of course I actually do :P
APL (Dyalog), 104 89 80 82 81 79 78 bytes

⍙←{⍵⍺⍺1⌽⍵}
⎕←(|x){⍵≡2⌽⍵:≡⍙¨0⍺⍵⋄2 4=+/1=2|+⍙↑⍵(=⍙⍺)}2|1+-⍙(12○x←-⍙⎕+.×1 0J1)÷○1

Try it online!

Input/Output
Takes a 4×2 matrix of coordinates as input
Outputs

1 1 1 for Square
1 1 0 for Rhombus
1 0 1 for Rectangle
1 0 0 for Parallelogram
1 0 for Kite
0 1 for Trapezium
0 0 for Quadrilateral


Algorithm
First, find all 4 side lengths and angles of the quadrilateral
If both pairs of opposite angles are equal (OA), then the shape is some kind of parallelogram. Determine if all side lengths are equal (AS, Adjacent Sides) and if all angles are equal (AA).
+--------+----------------+----------------+
|        |       AA       |      ~AA       |
+--------+----------------+----------------+
|   AS   |     Square     |    Rhombus     |
|--------+----------------+----------------+
|  ~AS   |    Rectangle   |  Parallelogram |
+--------+----------------+----------------+

If not OA, then:

Determine if there are exactly 2 pairs of equal adjacent sides and if they are separated (aabb instead of aaab). If so, the shape is a kite.

Determine if there are exactly 1 pair of parallel opposite sides. If so, the shape is a trapezium.

Otherwise, the shape is a quadrilateral.



Code
⍙←{⍵⍺⍺1⌽⍵} defines a new operator. In APL, an operator means a higher-order function. This operator takes 1 functional argument (⍺⍺) and returns a monadic function that:

Rotates (1⌽) the argument (⍵)
Apply ⍺⍺ between it and ⍵

This is especially useful for scalar functions since most of them implicitly map across array arguments, allowing ⍙ to apply those between each adjacent pair of elements with wrap around. For example +⍙1 2 3 4 is 1 2 3 4 + 2 3 4 1 which evaluates to 3 5 7 5.

x←-⍙⎕+.×1 0J1 converts the input coordinate matrix into an array of complex numbers representing the vectors of the 4 sides of the shape.

⎕, when referenced, takes and returns input

1 0J1 represents the vector [1,i] (&quot;vector&quot; in the mathematical sense, and &quot;i&quot; as the square root of -1). In APL, a complex number a+bi is written aJb

+.× matrix multiplication. Mathematically, the result would be a 4×1 matrix. However, +.× is called &quot;inner product&quot; in APL which generalizes matrix multiplication and vector inner product and allows you to do even stuff like &quot;multiply&quot; a 3-dimensional array with a 2-dimensional one. In this case, we are multiplying a 4×2 matrix and a 2-element vector, resulting in a 4-element vector (of the complex number representations of the 4 given vertices).

-⍙ is pairwise subtraction with wrap around as noted above. This gives the vectors of the 4 sides of the shape (as complex numbers). These vectors point in the &quot;reverse&quot; direction but that doesn't matter.

x← stores that into the variable x



2|1+-⍙(12○x)÷○1 finds (a representation of) the exterior angles at the 4 vertices of the shape.

12○x finds the principal argument, in radians, of each of the 4 side vectors.

÷○1 divides by π so that the angles are easier to work with. Thus, all angles are expressed as a multiple of a straight angle.

-⍙ Pairwise subtraction with wrap around as noted above. This gives the 4 exterior angles.

2|1+ The principal argument is capped (-1,1] and pairwise subtraction makes the range (-2,2]. This is bad since the same angle has 2 different representations. By doing &quot;add 1 mod 2&quot;, the angle is re-capped at (0,2]. Although all angles are 1 more than what it should be, it's fine if we keep that in mind.



|x finds the magnitude of each of the 4 side vectors

{⍵≡2⌽⍵:≡⍙¨0⍺⍵⋄2 4=+/1=2|+⍙↑⍵(=⍙⍺)} defines and applies a function with the array of 4 exterior angles as right argument ⍵ and the array of 4 side lengths as right argument ⍺.

The function has a guarded expression. In this case, ⍵≡2⌽⍵ is the guard.
If the guard evaluates to 1 then the next expression ≡⍙¨0⍺⍵ is executed and its value returned.
If the guard evaluates to 0, that expression is skipped and the one after that 2 4=...=⍙⍺) gets executed instead.


⍵≡2⌽⍵ checks if both pairs of opposite angles are equal.

2⌽⍵ rotates the angles array by 2 places.
⍵≡ checks if that is the same as ⍵ itself


≡⍙¨0⍺⍵ returns a unique value for each parallelogram-type shape.

0⍺⍵ is the 3-element array of the scalar 0, the side lengths array ⍺, and the angles array ⍵.
≡⍙¨ executes ≡⍙ for each of those elements.
≡⍙ checks if all values of an array are equal by checking if rotating it by 1 gives the same array. Scalars do not rotate so ≡⍙0 returns 1. As noted above, ≡⍙⍺ checks for a rhombus and ≡⍙⍵ checks for a rectangle.


2 4=+/1=2|+⍙↑⍵(=⍙⍺) returns a unique value for each non-parallelogram-type shape. This is achieved by intertwining the checks for kite and trapezium.

2=+/1=2|+⍙⍵ checks for a trapezium.

+⍙⍵ gives the adjacent angle sums. The interior angles of parallel lines sum to a straight angle, thus so does the exterior angles of parallel sides of a quadrilateral. So, each pair of parallel sides should lead to two 1 or -1 in the adjacent angle sums.

1=2| However, the angles in ⍵ are 1 more than what they should be, so the angles actually sum to 1 or 3. This can be checked by &quot;mod 2 equals 1&quot;.

+/ sums the array. This gives a count of adjacent angle sums which is 1 or 3.

2= check if that equals 2. (I.e. if there is exactly one pair of parallel sides)



4=+/1=2|+⍙(=⍙⍺) checks for a kite.

(=⍙⍺) gives an array indicating which adjacent sides are equal. Unlike ≡, = work element-wise. Thus, this is a 4-element array with 1s where the length of that side is equal to that of the &quot;next&quot; side.

+⍙ Pairwise sum with wrap around.

1=2| Since (=⍙⍺) gives a boolean array (one with only 0s and 1s), the only possible values of pairwise sum are 0, 1 and 2. So 1=2| is same as just 1=.

+/ sums the array. This gives a count of pairwise sums which is 1.

4= check if that equals 4. The only way that happens is if (=⍙⍺) is 1 0 1 0 or 0 1 0 1. As noted above, this means the shape is a kite.



2 4=+/1=2|+⍙↑⍵(=⍙⍺) intertwines the above checks.

⍵(=⍙⍺) is the 2-element nested array of the array ⍵ and the array (=⍙⍺)

↑ promotes the nested array to a proper matrix. Since ⍵(=⍙⍺) is a 2-element array of 4-element arrays, the result is a 2×4 matrix.

+⍙ Since ⌽ (and, by extension, ⍙) rotates the last (horizontal) axis, +⍙ to a matrix is same as applying +⍙ to each row individually.

1=2| both residue/mod (|) and equals (=) works on a per-element basis, even to matrices.

+/ By default, reduce (/) works along the last (horizontal) axis. So +/ sums along rows and turn a 2×4 matrix into a 2-element simple array.

2 4= Since = works per-element, this checks the kite and trapezium conditions simultaneously.