Determine if 4 points form a square

J, 28 17 25 27

J doesn't really have functions, but here's a monadic verb that takes a vector of points from the complex plane:

4 8 4-:#/.~&(/:~&:|&,&(-/~))

Method is a mix of Michael Spencer (work solely on inter-vertex lengths; but he's currently failing my rhombus2) and Eelvex's (check the sets' sizes) works. Reading right to left:

  • -/~ compute all point differences
  • , flatten
  • | extract magnitude
  • /:~ sort up
  • #/.~ nub and count
  • 4 8 4 -: must have exactly 4 equidistant (at 0), 8 a bit bigger (length 1, sides), 4 bigger yet (length sqrt 2, diagonals)

Demonstration:

   NB. give the verb a name for easier use
   f =: 4 8 4-:#/.~&(/:~&:|&,&(-/~))

   NB. standard square
   f 0 0j1 1j1 1
1

   NB. non-axis-aligned square
   f 0 2j1 3j_1 1j_2
1

   NB. different order
   f 0 1j1 0j1 1
1

   NB. rectangle
   f 0 0j2 3j2 3
0

   NB. rhombus 1
   f 0 3j4 8j4 5
0

   NB. rhombus 2
   f 0 1ad_60 1ad0 1ad60
0

For memory's sake, my previous method (required ordered vertices, but could detect regular polygons of any order):

*./&(={.)&(%1&|.)&(-1&|.)

See history for explanation and demo. The current method could probably be expanded to other polygons, that 4 8 4 does look a lot like a binomial distribution.


Python 176 90 79 bytes

def S(A):c=sum(A)/4.0;return set(A)==set((A[0]-c)\*1j\*\*i+c for i in range(4))

Function S takes a list of complex numbers as its input (A). If we know both the centre and one corner of a square, we can reconstruct the square by rotating the corner 90,180 and 270 degrees around the centre point (c). On the complex plane rotation by 90 degrees about the origin is done by multiplying the point by i. If our original shape and the reconstructed square have the same points then it must have been a square.


Python, 71 42

lambda A: len(set(A))==4 and len(set(abs(i-j)for i in A for j in A))==3

Update 1) to require 4 different points (would previously give false positives for repeated points - are there others?) 2) to define a function per spec

For a square, the vector between any two points must be 0 (the same point), a side, or a diagonal. So, the set of the magnitude of these vectors must have length 3.

# Accepts co-ordinates as sequences of complex numbers

SQUARES=[
 (0+0j,0+1j,1+1j,1+0j),  # standard square
 (0+0j,2+1j,3-1j,1-2j),  # non-axis-aligned square
 (0+0j,1+1j,0+1j,1+0j)   # different order
]

NONSQUARES=[
 (0+0j,0+2j,3+2j,3+0j),  # rectangle
 (0+0j,3+4j,8+4j,5+0j),  # rhombus
 (0+0j,0+1j,1+1j,0+0j),   # duplicated point
 (0+0j,1+60j,1+0j,1-60j)  # rhombus 2 (J B)
] 
 
test = "lambda A: len(set(A))==4 and len(set(abs(i-j)for i in A for j in A))==3"
assert len(test)==71

is_square=lambda A: len(set(A))==4 and len(set(abs(i-j)for i in A for j in A))==3    
    
for A in SQUARES:
    assert is_square(A)
    
for A in NONSQUARES:
    assert not is_square(A)

Tags:

Math

Code Golf