Determine si 4 puntos forman un cuadrado

29

Escriba una función que tome 4 puntos en el plano como entrada y devuelva verdadero si los 4 puntos forman un cuadrado. Los puntos tendrán coordenadas integrales con valores absolutos <1000.

Puede usar cualquier representación razonable de los 4 puntos como entrada. Los puntos no se proporcionan en ningún orden en particular.

El código más corto gana.

Cuadrados de ejemplo:

(0,0),(0,1),(1,1),(1,0)    # standard square
(0,0),(2,1),(3,-1),(1,-2)  # non-axis-aligned square
(0,0),(1,1),(0,1),(1,0)    # different order

Ejemplos no cuadrados:

(0,0),(0,2),(3,2),(3,0)  # rectangle
(0,0),(3,4),(8,4),(5,0)  # rhombus
(0,0),(0,0),(1,1),(0,0)  # only 2 distinct points
(0,0),(0,0),(1,0),(0,1)  # only 3 distinct points

Puede devolver verdadero o falso para el cuadrado degenerado (0,0),(0,0),(0,0),(0,0)

Keith Randall
fuente
Estamos hablando de puntos 3D aquí, ¿verdad?
gnibbler
3
@gnibbler la parte "en el avión" de la pregunta hace que los puntos 3D sean poco probables.
JB
¿Se dan los puntos en orden?
JB
@JB, estaba pensando que significaba que los puntos estaban en un avión, pero visualicé un avión en el espacio 3D por alguna razón :)
gnibbler
1
@eBusiness: -1 que ha emitido 11 votos: 7 de ellos cayeron.
Eelvex

Respuestas:

12

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))

La función S toma una lista de números complejos como su entrada (A). Si conocemos el centro y una esquina de un cuadrado, podemos reconstruir el cuadrado girando la esquina 90,180 y 270 grados alrededor del punto central (c). En el plano complejo, la rotación de 90 grados sobre el origen se realiza multiplicando el punto por i . Si nuestra forma original y el cuadrado reconstruido tienen los mismos puntos, entonces debe haber sido un cuadrado.

caballo de papel
fuente
Algunas optimizaciones: 1) use "S" en lugar de "is_square" 2) ponga todo en una línea usando; 3) iterar sobre las 4 direcciones directamente "para i en (1,1j, -1, -1j)" 4) no necesita [] en el argumento establecido.
Keith Randall
Gracias Keith (Dejé afuera (3) ya que parece tener la misma longitud que mi código)
paperhorse
2
@Keith Randall: ¿Por qué se aceptó esto cuando JB tiene una solución mucho más corta?
aaaaaaaaaaaa
1
Dos razones. Uno, J siempre ganaría. Entonces me gusta normalizar un poco por idioma. Además, me gusta más esta respuesta porque no sufre el mismo problema que las respuestas de solo distancia donde otras figuras (ciertamente, solo las irracionales) dan falsos positivos.
Keith Randall
55
@Keith Randall - Citas de la pregunta: "Los puntos tendrán coordenadas integrales" "El código más corto gana". Está perfectamente bien si elige diferentes criterios para seleccionar una respuesta, incluso criterios subjetivos, pero luego debe indicarlo en la pregunta.
aaaaaaaaaaaa
13

J, 28 17 25 27

J realmente no tiene funciones, pero aquí hay un verbo monádico que toma un vector de puntos del plano complejo:

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

El método es una mezcla de Michael Spencer (funciona únicamente en longitudes entre vértices; pero actualmente está fallando mi rombo2) y funciona Eelvex (verifique los tamaños de los conjuntos). Lectura de derecha a izquierda:

  • -/~ calcular todas las diferencias de puntos
  • , aplanar
  • | extraer magnitud
  • /:~ ordenar
  • #/.~ protuberancia y cuenta
  • 4 8 4 -:debe tener exactamente 4 equidistantes (en 0), 8 un poco más grandes (longitud 1, lados), 4 más grandes (longitud sqrt 2, diagonales)

Demostración:

   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

Por el bien de la memoria, mi método anterior (requería vértices ordenados, pero podía detectar polígonos regulares de cualquier orden):

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

Ver historia para explicación y demostración. El método actual probablemente podría expandirse a otros polígonos, que 4 8 4se parece mucho a una distribución binomial.

JB
fuente
¿Puedes enlazar a este idioma?
Sargun Dhillon
1
@gnibbler: ¿Por qué no? Estoy bastante seguro de que sí.
Eelvex
1
En realidad, existe una figura no cuadrada que satisface las condiciones que usted verifica, un triángulo regular más un punto de longitud lateral desde una punta del triángulo colocado en la mediana extendida. Pero la pregunta requería una entrada entera, así que supongo que la solución está bien.
aaaaaaaaaaaa
1
Ah ok Estaba pensando en triángulos equiláteros con el cuarto punto como el centro, pero eso está descartado por las coordenadas
enteras
1
Puede cortar 3 caracteres cambiándolo a una definición explícita: 3 :'4 8 4-:#/.~/:~|,-/~y'
isawdrones
5

Pitón, 71 42

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

Actualización 1) para requerir 4 puntos diferentes (anteriormente daría falsos positivos para puntos repetidos, ¿hay otros?) 2) para definir una función por especificación

Para un cuadrado, el vector entre dos puntos debe ser 0 (el mismo punto), un lado o una diagonal. Entonces, el conjunto de la magnitud de estos vectores debe tener una longitud 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)
mbomb007
fuente
Creo que la pregunta establece explícitamente una lista de puntos, y no un vector.
Sargun Dhillon
Falsos positivos.
aaaaaaaaaaaa
1
Entonces (0 + 0j, 0 + 0j, 1 + 0j, 0 + 1j) es un cuadrado?
mhagger
Mi rombo 2 no es 1 +/- 60j, es más como exp (i j pi / 3) para valores de -1, 0, 1. Tenga en cuenta que, como eBusiness señaló, no todos pueden ser integrales, por lo que en realidad no El alcance de la pregunta.
JB
3

Haskell, 100 personajes

Así es como escribiría la solución J de JB en Haskell. Sin ningún intento de dañar la legibilidad eliminando caracteres no esenciales, se trata de 132 caracteres:

import Data.List
d (x,y) (x',y') = (x-x')^2 + (y-y')^2
square xs = (== [4,8,4]) . map length . group . sort $ [d x y | x<-xs, y<-xs]

Puede reducirlo un poco a 100 eliminando espacios en exceso y renombrando algunas cosas

import Data.List
d(x,y)(a,b)=(x-a)^2+(y-b)^2
s l=(==[4,8,4]).map length.group.sort$[d x y|x<-l,y<-l]

Usemos QuickCheck para asegurarnos de que acepta cuadrados arbitrarios, con un vértice en (x, y) y un vector de borde (a, b):

prop_square (x,y) (a,b) = square [(x,y),(x+a,y+b),(x-b,y+a),(x+a-b,y+b+a)]

Probándolo en ghci:

ghci> quickCheck prop_square
*** Failed! Falsifiable (after 1 test):  
(0,0)
(0,0)

Ah, claro, el cuadrado vacío no se considera un cuadrado aquí, así que revisaremos nuestra prueba:

prop_square (x,y) (a,b) =
   (a,b) /= (0,0) ==> square [(x,y),(x+a,y+b),(x-b,y+a),(x+a-b,y+b+a)]

Y probándolo de nuevo:

ghci> quickCheck prop_square
+++ OK, passed 100 tests.

fuente
1
Ahorre 11 caracteres desenrollando la función d. s l=[4,8,4]==(map length.group.sort)[(x-a)^2+(y-b)^2|(x,y)<-l,(a,b)<-l]
Ray
3

Factor

Una implementación en el lenguaje de programación Factor :

USING: kernel math math.combinatorics math.vectors sequences sets ;

: square? ( seq -- ? )
    members [ length 4 = ] [
        2 [ first2 distance ] map-combinations
        { 0 } diff length 2 =
    ] bi and ;

Y algunas pruebas unitarias:

[ t ] [
    {
        { { 0 0 } { 0 1 } { 1 1 } { 1 0 } }   ! standard square
        { { 0 0 } { 2 1 } { 3 -1 } { 1 -2 } } ! non-axis-aligned square
        { { 0 0 } { 1 1 } { 0 1 } { 1 0 } }   ! different order
        { { 0 0 } { 0 4 } { 2 2 } { -2 2 } }  ! rotated square
    } [ square? ] all?
] unit-test

[ f ] [
    {
        { { 0 0 } { 0 2 } { 3 2 } { 3 0 } }   ! rectangle
        { { 0 0 } { 3 4 } { 8 4 } { 5 0 } }   ! rhombus
        { { 0 0 } { 0 0 } { 1 1 } { 0 0 } }   ! only 2 distinct points
        { { 0 0 } { 0 0 } { 1 0 } { 0 1 } }   ! only 3 distinct points
    } [ square? ] any?
] unit-test
mrjbq7
fuente
3

OCAML, 145164

let(%)(a,b)(c,d)=(c-a)*(c-a)+(d-b)*(d-b)
let t a b c d=a%b+a%c=b%c&&d%c+d%b=b%c&&a%b=a%c&&d%c=d%b
let q(a,b,c,d)=t a b c d||t a c d b||t a b d c

Corre así:

q ((0,0),(2,1),(3,-1),(1,-2))

Desobusquemos y expliquemos un poco.

Primero definimos una norma:

let norm (ax,ay) (bx,by) = (bx-ax)*(bx-ax)+(by-ay)*(by-ay)

Notarás que no hay llamada a sqrt, no es necesario aquí.

let is_square_with_fixed_layout a b c d =
  (norm a b) + (norm a c) = norm b c
  && (norm d c) + (norm d b) = norm b c
  && norm a b = norm a c
  && norm d c = norm d b

Aquí a, b, cyd son puntos. Suponemos que estos puntos se presentan así:

a - b
| / |
c - d

Si tenemos un cuadrado, entonces todas estas condiciones deben cumplir:

  • ABC es un triángulo rectángulo
  • bcd es un triángulo rectángulo
  • los lados más pequeños de cada triángulo rectángulo tienen las mismas normas

Observe que siempre se cumple lo siguiente:

is_square_with_fixed_layout r s t u = is_square_with_fixed_layout r t s u

Usaremos eso para simplificar nuestra función de prueba a continuación.

Como nuestra entrada no está ordenada, también tenemos que verificar todas las permutaciones. Sin pérdida de generalidad podemos evitar permutar el primer punto:

let is_square (a,b,c,d) =
  is_square_with_fixed_layout a b c d
  || is_square_with_fixed_layout a c b d
  || is_square_with_fixed_layout a c d b
  || is_square_with_fixed_layout a b d c
  || is_square_with_fixed_layout a d b c
  || is_square_with_fixed_layout a d c b

Después de la simplificación:

let is_square (a,b,c,d) =
  is_square_with_fixed_layout a b c d
  || is_square_with_fixed_layout a c d b
  || is_square_with_fixed_layout a b d c

Editar: siguió el consejo de M.Giovannini.

bltxd
fuente
Agradable. No hemos visto mucho OCaml aquí :)
Eelvex
Utilice un operador en lugar de nuna reducción de 20 caracteres: let t a b c d=a%b+a%c=b%c&&d%c+d%b=b%c&&a%b=a%c&&d%c=d%b.
Matías Giovannini
2

Pitón (105)

Los puntos están representados por (x,y)tuplas. Los puntos pueden estar en cualquier orden y solo acepta cuadrados. Crea una lista, sde distancias por pares (no cero) entre los puntos. Debe haber 12 distancias en total, en dos grupos únicos.

def f (p): s = filtro (Ninguno, [(xz) ** 2+ (yw) ** 2 para x, y en p para z, w en p]); devuelve len (s) == 12 y len ( conjunto (s)) == 2
Hoa Long Tam
fuente
Sin embargo, puede omitir el filtro y verificar si la lente del conjunto es 3. Sin embargo, esto tiene el mismo problema de falsos positivos que mi respuesta.
gnibbler
>>> f ([(0,0), (0,4), (2,2), (- 2,2)]) = Verdadero
Sargun Dhillon
2
f([(0,0),(0,4),(2,2),(-2,2)]) es un cuadrado
gnibbler
2

Python - 42 caracteres

Parece que es una mejora usar números complejos para los puntos

len(set(abs(x-y)for x in A for y in A))==3

donde A = [(11 + 13j), (14 + 12j), (13 + 9j), (10 + 10j)]

vieja respuesta:

from itertools import*
len(set((a-c)**2+(b-d)**2 for(a,b),(c,d)in combinations(A,2)))==2

Los puntos se especifican en cualquier orden como una lista, por ej.

A = [(11, 13), (14, 12), (13, 9), (10, 10)]
gnibbler
fuente
>>> A=[(0,0),(0,0),(1,1),(0,0)] >>> len(set((a-c)**2+(b-d)**2 for(a,b),(c,d)in combinations(A,2)))==2 True
Sargun Dhillon
@Sargun, ese es un caso especial de toda una clase de entradas que no funcionan. Estoy tratando de pensar en una solución que no explote el tamaño de la respuesta. Mientras tanto, ¿se puede resolver la clase general de casos fallidos?
gnibbler
A=[(0,0),(0,4),(2,2),(-2,2)]; len(set((a-c)**2+(b-d)**2 for(a,b),(c,d)in combinations(A,2)))==2
Sargun Dhillon
@Sargun: ese ejemplo es un cuadrado.
Keith Randall
para deshacerse de los puntos duplicados puede agregar -set ([0])
Keith Randall
2

C # - no exactamente corto. Abusando de LINQ. Selecciona dos combinaciones distintas de puntos en la entrada, calcula sus distancias, luego verifica que exactamente cuatro de ellos sean iguales y que solo haya otro valor de distancia distinto. Point es una clase con dos miembros dobles, X e Y. Podría ser fácilmente una Tupla, pero meh.

var points = new List<Point>
             {
                 new Point( 0, 0 ), 
                 new Point( 3, 4 ), 
                 new Point( 8, 4 ), 
                 new Point( 5, 0 )
              };    
var distances = points.SelectMany(
    (value, index) => points.Skip(index + 1),
    (first, second) => new Tuple<Point, Point>(first, second)).Select(
        pointPair =>
        Math.Sqrt(Math.Pow(pointPair.Item2.X - pointPair.Item1.X, 2) +
                Math.Pow(pointPair.Item2.Y - pointPair.Item1.Y, 2)));
return
    distances.Any(
        d => distances.Where( p => p == d ).Count() == 4 &&
                distances.Where( p => p != d ).Distinct().Count() == 1 );
Daniel Coffman
fuente
2

PHP, 82 caracteres


//$x=array of x coordinates
//$y=array of respective y coordinates
/* bounding box of a square is also a square - check if Xmax-Xmin equals Ymax-Ymin */
function S($x,$y){sort($x);sort($y);return ($x[3]-$x[0]==$y[3]-$y[0])?true:false};

//Or even better (81 chars):
//$a=array of points - ((x1,y1), (x2,y2), (x3,y3), (x4,y4))
function S($a){sort($a);return (bool)($a[3][0]-$a[0][0]-abs($a[2][1]-$a[3][1]))};
arek
fuente
Pero solo porque el cuadro delimitador sea cuadrado no significa que los puntos se encuentren en un cuadrado. Condición necesaria pero no suficiente. Considere (0,0), (5,5), (10,0), (0, -5). El cuadro delimitador es cuadrado (0:10, -5: 5); La figura no lo es.
Floris
2

K - 33

Traducción de la solución J por JB :

{4 8 4~#:'=_sqrt+/'_sqr,/x-/:\:x}

K sufre aquí de sus palabras reservadas ( _sqry _sqrt).

Pruebas:

  f:{4 8 4~#:'=_sqrt+/'_sqr,/x-/:\:x}

  f (0 0;0 1;1 1;1 0)
1

  f 4 2#0 0 1 1 0 1 1 0
1

  f 4 2#0 0 3 4 8 4 5 0
0
isawdrones
fuente
2

OCaml + Batteries, 132 caracteres

let q l=match List.group(-)[?List:(x-z)*(x-z)+(y-t)*(y-t)|x,y<-List:l;z,t<-List:l;(x,y)<(z,t)?]with[[s;_;_;_];[d;_]]->2*s=d|_->false

(¡mira, Ma, sin espacios!) La comprensión de qla lista en forma la lista de normas al cuadrado para cada par de puntos desordenados distintos. Un cuadrado tiene cuatro lados iguales y dos diagonales iguales, siendo las longitudes al cuadrado de este último el doble de las longitudes al cuadrado del primero. Como no hay triángulos equiláteros en la red de enteros, la prueba no es realmente necesaria, pero la incluyo para completarla.

Pruebas:

q [(0,0);(0,1);(1,1);(1,0)] ;;
- : bool = true
q [(0,0);(2,1);(3,-1);(1,-2)] ;;
- : bool = true
q [(0,0);(1,1);(0,1);(1,0)] ;;
- : bool = true
q [(0,0);(0,2);(3,2);(3,0)] ;;
- : bool = false
q [(0,0);(3,4);(8,4);(5,0)] ;;
- : bool = false
q [(0,0);(0,0);(1,1);(0,0)] ;;
- : bool = false
q [(0,0);(0,0);(1,0);(0,1)] ;;
- : bool = false
Matías Giovannini
fuente
2

Mathematica 65 80 69 66

Comprueba que el número de distancias entre puntos distintas (sin incluir la distancia de un punto a sí mismo) es 2 y la más corta de las dos no es 0.

h = Length@# == 2 \[And] Min@# != 0 &[Union[EuclideanDistance @@@ Subsets[#, {2}]]] &;

Uso

h@{{0, 0}, {0, 1}, {1, 1}, {1, 0}}       (*standard square *)
h@{{0, 0}, {2, 1}, {3, -1}, {1, -2}}     (*non-axis aligned square *)
h@{{0, 0}, {1, 1}, {0, 1}, {1, 0}}       (*a different order *)

h@{{0, 0}, {0, 2}, {3, 2}, {3, 0}}       (* rectangle *)
h@{{0, 0}, {3, 4}, {8, 4}, {5, 0}}       (* rhombus   *)
h@{{0, 0}, {0, 0}, {1, 1}, {0, 0}}       (* only 2 distinct points *)
h@{{0, 0}, {0, 1}, {1, 1}, {0, 1}}       (* only 3 distinct points *)

Verdadero
Verdadero
Verdadero
Falso
Falso
Falso
Falso

NB: \[And]es un solo personaje en Mathematica.

DavidC
fuente
1
¿Me estás diciendo que Mathematica no tiene una función IsSquare incorporada?
goodguy
2

Jalea , 8 bytes

_Æm×ıḟƊṆ

Pruébalo en línea!

Toma una lista de números complejos como argumento de línea de comando. Impresiones 1o 0.

_Æm        Subtract mean of points from each point (i.e. center on 0)
   ×ıḟƊ    Rotate 90°, then compute set difference with original.
       Ṇ   Logical negation: if empty (i.e. sets are equal) then 1 else 0.

¡Esto parece un desafío agradable para revivir!

Lynn
fuente
1

Haskell (212)

import Data.List;j=any f.permutations where f x=(all g(t x)&&s(map m(t x)));t x=zip3 x(drop 1$z x)(drop 2$z x);g(a,b,c)=l a c==sqrt 2*l a b;m(a,b,_)=l a b;s(x:y)=all(==x)y;l(m,n)(o,p)=sqrt$(o-m)^2+(n-p)^2;z=cycle

Ingenuo primer intento. Comprueba las siguientes dos condiciones para todas las permutaciones de la lista de puntos de entrada (donde una permutación dada representa, por ejemplo, un orden de los puntos en el sentido de las agujas del reloj):

  • todos los ángulos son 90 grados
  • todos los lados son del mismo largo

Código desofuscado y pruebas

j' = any satisfyBothConditions . permutations
          --f
    where satisfyBothConditions xs = all angleIs90 (transform xs) && 
                                     same (map findLength' (transform xs))
          --t
          transform xs = zip3 xs (drop 1 $ cycle xs) (drop 2 $ cycle xs)
          --g
          angleIs90 (a,b,c) = findLength a c == sqrt 2 * findLength a b
          --m
          findLength' (a,b,_) = findLength a b
          --s
          same (x:xs) = all (== x) xs
          --l
          findLength (x1,y1) (x2,y2) = sqrt $ (x2 - x1)^2 + (y2 - y1)^2


main = do print $ "These should be true"
          print $ j [(0,0),(0,1),(1,1),(1,0)]
          print $ j [(0,0),(2,1),(3,-1),(1,-2)]
          print $ j [(0,0),(1,1),(0,1),(1,0)]
          print $ "These should not"
          print $ j [(0,0),(0,2),(3,2),(3,0)]
          print $ j [(0,0),(3,4),(8,4),(5,0)]
          print $ "also testing j' just in case"
          print $ j' [(0,0),(0,1),(1,1),(1,0)]
          print $ j' [(0,0),(2,1),(3,-1),(1,-2)]
          print $ j' [(0,0),(1,1),(0,1),(1,0)]
          print $ j' [(0,0),(0,2),(3,2),(3,0)]
          print $ j' [(0,0),(3,4),(8,4),(5,0)]
Dan Burton
fuente
1

Scala (146 caracteres)

def s(l:List[List[Int]]){var r=Set(0.0);l map(a=>l map(b=>r+=(math.pow((b.head-a.head),2)+math.pow((b.last-a.last),2))));print(((r-0.0).size)==2)}
Gareth
fuente
1

JavaScript 144 caracteres

Matemáticamente igual a la respuesta de J Bs. Genera las 6 longitudes y afirma que las 2 más grandes son iguales y que las 4 más pequeñas son iguales. La entrada debe ser una matriz de matrices.

function F(a){d=[];g=0;for(b=4;--b;)for(c=b;c--;d[g++]=(e*e+f*f)/1e6)e=a[c][0]-a[b][0],f=a[c][1]-a[b][1];d.sort();return d[0]==d[3]&&d[4]==d[5]} //Compact function
testcases=[
[[0,0],[1,1],[1,0],[0,1]],
[[0,0],[999,999],[999,0],[0,999]],
[[0,0],[2,1],[3,-1],[1,-2]],
[[0,0],[0,2],[3,2],[3,0]],
[[0,0],[3,4],[8,4],[5,0]],
[[0,0],[0,0],[1,1],[0,0]],
[[0,0],[0,0],[1,0],[0,1]]
]
for(v=0;v<7;v++){
    document.write(F(testcases[v])+"<br>")
}

function G(a){ //Readable version
    d=[]
    g=0
    for(b=4;--b;){
        for(c=b;c--;){
            e=a[c][0]-a[b][0]
            f=a[c][1]-a[b][1]
            d[g++]=(e*e+f*f)/1e6 //The division tricks the sort algorithm to sort correctly by default method.
        }
    }
    d.sort()
    return (d[0]==d[3]&&d[4]==d[5])
}
aaaaaaaaaaaa
fuente
1

PHP, 161 158 caracteres

function S($a){for($b=4;--$b;)for($c=$b;$c--;){$e=$a[$c][0]-$a[$b][0];$f=$a[$c][1]-$a[$b][1];$d[$g++]=$e*$e+$f*$f;}sort($d);return$d[0]==$d[3]&&$d[4]==$d[5];}

Prueba (1x1): http://codepad.viper-7.com/ZlBpOB

Esto se basa en la respuesta JavaScript de eBuisness .

Kevin Brown
fuente
No está claro por el enunciado del problema que los puntos entrarían ordenados. Iré a preguntar.
JB
1
No creo que esto maneje adecuadamente muchos casos. Por ejemplo, etiquetará incorrectamente los rombos como cuadrados.
Keith Randall
Actualizado esto para que coincida con una de las respuestas de JavaScript, debe manejar todos los casos.
Kevin Brown
1

JavaScript 1.8, 112 caracteres

Actualización: salvó 2 caracteres al plegar las comprensiones de la matriz juntas.

function i(s)(p=[],[(e=x-a,f=y-b,d=e*e+f*f,p[d]=~~p[d]+1)for each([a,b]in s)for each([x,y]in s)],/8,+4/.test(p))

Otra reimplementación de la respuesta de JB. Explota las características de JavaScript 1.7 / 1.8 (cierre de expresiones, comprensión de matrices, asignación de desestructuración). También abusa ~~(doble bitbit no operador) para obligar undefineda numérico, con coerción de matriz a cadena y una expresión regular para verificar que los recuentos de longitud son [4, 8, 4](se supone que se pasan exactamente 4 puntos). El abuso del operador de coma es un viejo truco C ofuscado.

Pruebas:

function assert(cond, x) { if (!cond) throw ["Assertion failure", x]; }

let text = "function i(s)(p=[],[(e=x-a,f=y-b,d=e*e+f*f,p[d]=~~p[d]+1)for each([a,b]in s)for each([x,y]in s)],/8,+4/.test(p))"
assert(text.length == 112);
assert(let (source = i.toSource()) (eval(text), source == i.toSource()));

// Example squares:
assert(i([[0,0],[0,1],[1,1],[1,0]]))    // standard square
assert(i([[0,0],[2,1],[3,-1],[1,-2]]))  // non-axis-aligned square
assert(i([[0,0],[1,1],[0,1],[1,0]]))    // different order

// Example non-squares:
assert(!i([[0,0],[0,2],[3,2],[3,0]]))  // rectangle
assert(!i([[0,0],[3,4],[8,4],[5,0]]))  // rhombus
assert(!i([[0,0],[0,0],[1,1],[0,0]]))  // only 2 distinct points
assert(!i([[0,0],[0,0],[1,0],[0,1]]))  // only 3 distinct points

// Degenerate square:
assert(!i([[0,0],[0,0],[0,0],[0,0]]))   // we reject this case
ecatmur
fuente
1

GoRuby - 66 caracteres

f=->a{z=12;a.pe(2).m{|k,l|(k-l).a}.so.go{|k|k}.a{|k,l|l.sz==z-=4}}

expandido:

f=->a{z=12;a.permutation(2).map{|k,l|(k-l).abs}.sort.group_by{|k|k}.all?{|k,l|l.size==(z-=4)}}

Mismo algoritmo que la respuesta de JB .

Prueba como:

p f[[Complex(0,0), Complex(0,1), Complex(1,1), Complex(1,0)]]

Salidas truepara verdadero y en blanco para falso

Nemo157
fuente
Nunca oí hablar de GoRuby. ¿Hay algo oficial escrito al respecto? stackoverflow.com/questions/63998/hidden-features-of-ruby/…
Jonas Elfström
@Jonas: No he visto nada realmente oficial al respecto, la mejor publicación de blog que he visto es esta . En realidad no pude hacer que funcionara, pero una alternativa es copiar el preludio de golf en la misma carpeta y ejecutarlo, ruby -r ./golf-prelude.rb FILE_TO_RUN.rby funcionará exactamente igual.
Nemo157
No es necesario sortantes group_by. .sort.group_by {...}debe escribirse como.group_by {...}
user102008
1

Python 97 (sin puntos complejos)

def t(p):return len(set(p))-1==len(set([pow(pow(a-c,2)+pow(b-d,2),.5)for a,b in p for c,d in p]))

Esto tomará listas de tuplas de puntos en [(x, y), (x, y), (x, y), (x, y)] en cualquier orden, y puede manejar duplicados o el número incorrecto de puntos. NO requiere puntos complejos como las otras respuestas de Python.

Puedes probarlo así:

S1 = [(0,0),(1,0),(1,1),(0,1)]   # standard square
S2 = [(0,0),(2,1),(3,-1),(1,-2)] # non-axis-aligned square
S3 = [(0,0),(1,1),(0,1),(1,0)]   # different order
S4 = [(0,0),(2,2),(0,2),(2,0)]   #
S5 = [(0,0),(2,2),(0,2),(2,0),(0,0)] #Redundant points

B1 = [(0,0),(0,2),(3,2),(3,0)]  # rectangle
B2 = [(0,0),(3,4),(8,4),(5,0)]  # rhombus
B3 = [(0,0),(0,0),(1,1),(0,0)]  # only 2 distinct points
B4 = [(0,0),(0,0),(1,0),(0,1)]  # only 3 distinct points
B5 = [(1,1),(2,2),(3,3),(4,4)]  # Points on the same line
B6 = [(0,0),(2,2),(0,2)]        # Not enough points

def tests(f):
    assert(f(S1) == True)
    assert(f(S2) == True)
    assert(f(S3) == True)
    assert(f(S4) == True)
    assert(f(S5) == True)

    assert(f(B1) == False)
    assert(f(B2) == False)
    assert(f(B3) == False)
    assert(f(B4) == False)
    assert(f(B5) == False)
    assert(f(B6) == False)

def t(p):return len(set(p))-1==len(set([pow(pow(a-c,2)+pow(b-d,2),.5)for a,b in p for c,d in p]))

tests(t)

Esto requerirá una pequeña explicación, pero la idea general es que solo hay tres distancias entre los puntos en un cuadrado (lateral, diagonal, cero (punto en comparación con sí mismo)):

def t(p):return len(set(p))-1==len(set([pow(pow(a-c,2)+pow(b-d,2),.5)for a,b in p for c,d in p]))
  • para una lista p de tuplas (x, y)
  • Elimine los duplicados con el conjunto (p) y luego pruebe la longitud
  • Obtenga todas las combinaciones de puntos (a, b en p para c, d en p)
  • Obtenga una lista de la distancia desde cada punto a cualquier otro punto
  • Use el set para verificar que solo haya tres distancias únicas: cero (punto en comparación con sí mismo), longitud lateral, longitud diagonal

Para guardar caracteres de código soy:

  • usando un nombre de función 1 char
  • utilizando una definición de función de 1 línea
  • En lugar de verificar que el número de puntos únicos es 4, verifico que es -1 las diferentes longitudes de puntos (guarda == 3 ==)
  • use el desempaquetado de listas y tuplas para obtener a, b en p para c, d en p, en lugar de usar a [0], a [1]
  • usa pow (x, .5) en lugar de incluir matemáticas para obtener sqrt (x)
  • no poner espacios después del)
  • no poner un cero a la izquierda en el flotador

Me temo que alguien puede encontrar un caso de prueba que rompa esto. Así que por favor hazlo y lo corregiré. Por ejemplo, el hecho de que solo verifique tres distancias, en lugar de hacer un abs () y verificar la longitud del lado y la hipotenusa, parece un error.

La primera vez que probé el código de golf. Sé amable si he roto las reglas de la casa.

Jagu
fuente
1

Clojure, 159 caracteres.

user=> (def squares
         [[[0,0] [0,1] [1,1]  [1,0]]   ; standard square
         [[0,0] [2,1] [3,-1] [1,-2]]  ; non-axis-aligned square
         [[0,0] [1,1] [0,1]  [1,0]]]) ; different order
#'user/squares
user=> (def non-squares
         [[[0,0] [0,2] [3,2] [3,0]]    ; rectangle
          [[0,0] [3,4] [8,4] [5,0]]])  ; rhombus
#'user/non-squares
user=> (defn norm
         [x y]
         (reduce + (map (comp #(* % %) -) x y)))
#'user/norm
user=> (defn square?
         [[a b c d]]
         (let [[x y z] (sort (map #(norm a %) [b c d]))]
           (and (= x y) (= z (* 2 x)))))
#'user/square?
user=> (every? square? squares)
true
user=> (not-any? square? non-squares)
true

Editar: Para explicar también un poco.

  • Primero defina una norma que básicamente dé la distancia entre dos puntos dados.
  • Luego calcule la distancia del primer punto a los otros tres puntos.
  • Ordena las tres distancias. (Esto permite cualquier orden de los puntos).
  • Las dos distancias más cortas deben ser iguales para ser un cuadrado.
  • La tercera distancia (más larga) debe ser igual a la raíz cuadrada de la suma de los cuadrados de las distancias cortas según el teorema de Pitágoras.

(Nota: el enrutamiento cuadrado no es necesario y, por lo tanto, en el código guardado anteriormente)

Meikel
fuente
1

C #, 107 caracteres

return p.Distinct().Count()==4&&
(from a in p from b in p select (a-b).LengthSquared).Distinct().Count()==3;

Donde puntos es la Lista de Vector3D que contiene los puntos.

Calcula todas las distancias al cuadrado entre todos los puntos, y si hay exactamente tres tipos distintos (debe ser 0, algún valor a y 2 * a) y 4 puntos distintos, entonces los puntos forman un cuadrado.


fuente
1

Python, 66

Mejorando la respuesta de paperhorse de 76 a 66:

def U(A):c=sum(A)/4;d=A[0]-c;return{d+c,c-d,d*1j+c,c-d*1j}==set(A)
Reinstala a Monica
fuente
1

Python 2 , 49 bytes

lambda l:all(1j*z+(1-1j)*sum(l)/4in l for z in l)

Pruébalo en línea!

Toma una lista de cuatro números complejos como entrada. Rota cada punto 90 grados alrededor del promedio y verifica que cada punto resultante esté en la lista original.

Misma longitud (aunque más corta en Python 3 usando {*l}).

lambda l:{1j*z+(1-1j)*sum(l)/4for z in l}==set(l)

Pruébalo en línea!

xnor
fuente
¿Por qué no usar Python 3 si es más corto? Además, si se permite devolver valores de verdad / falsedad arbitrarios en Python, ^se puede usar en lugar de ==.
Joel
@Joel Python 2 es en su mayoría preferencia, y que este es un desafío realmente antiguo de 2011 cuando Python 2 se suponía que era el golf de Python. Y el desafío dice devolver verdadero o falso, así que me quedé con eso. Si esto se publicó hoy, probablemente especificaría la salida de truey / falsey o uno de los dos valores distintos, e incluso podría estar bien asumirlo de forma predeterminada.
XNOR
1

Wolfram Language (Mathematica) , 32 31 bytes

Tr[#^2]==Tr[#^3]==0&[#-Mean@#]&

Pruébalo en línea!

Toma una lista de puntos representados por números complejos, calcula el segundo y tercer momento central y comprueba que ambos son cero.

Sin golf:

S[p_] := Total[(p - Mean[p])^2] == Total[(p - Mean[p])^3] == 0

o

S[p_] := CentralMoment[p, 2] == CentralMoment[p, 3] == 0

prueba

Este criterio funciona en todo el plano complejo, no solo en el enteros gaussianos .

  1. Primero, notamos que el momentos centrales no cambian cuando los puntos se traducen juntos. Por un conjunto de puntos

    P = Table[c + x[i] + I*y[i], {i, 4}]
    

    los momentos centrales son independientes de c(es por eso que se llaman centrales ):

    {FreeQ[FullSimplify[CentralMoment[P, 2]], c], FreeQ[FullSimplify[CentralMoment[P, 3]], c]}
    (*    {True, True}    *)
    
  2. En segundo lugar, los momentos centrales tienen una dependencia simple del escalado complejo general (escalado y rotación) del conjunto de puntos:

    P = Table[f * (x[i] + I*y[i]), {i, 4}];
    FullSimplify[CentralMoment[P, 2]]
    (*    f^2 * (...)    *)
    FullSimplify[CentralMoment[P, 3]]
    (*    f^3 * (...)    *)
    

    Esto significa que si un momento central es cero, entonces escalar y / o rotar el conjunto de puntos mantendrá el momento central igual a cero.

  3. Tercero, demostremos el criterio para una lista de puntos donde los dos primeros puntos son fijos:

    P = {0, 1, x[3] + I*y[3], x[4] + I*y[4]};
    

    ¿En qué condiciones son cero las partes reales e imaginarias del segundo y tercer momento central?

    C2 = CentralMoment[P, 2] // ReIm // ComplexExpand // FullSimplify;
    C3 = CentralMoment[P, 3] // ReIm // ComplexExpand // FullSimplify;
    Solve[Thread[Join[C2, C3] == 0], {x[3], y[3], x[4], y[4]}, Reals] // FullSimplify
    (*    {{x[3] -> 0, y[3] -> -1, x[4] -> 1, y[4] -> -1},
           {x[3] -> 0, y[3] -> 1, x[4] -> 1, y[4] -> 1},
           {x[3] -> 1/2, y[3] -> -1/2, x[4] -> 1/2, y[4] -> 1/2},
           {x[3] -> 1/2, y[3] -> 1/2, x[4] -> 1/2, y[4] -> -1/2},
           {x[3] -> 1, y[3] -> -1, x[4] -> 0, y[4] -> -1},
           {x[3] -> 1, y[3] -> 1, x[4] -> 0, y[4] -> 1}}    *)
    

    Todas estas seis soluciones representan cuadrados: ingrese la descripción de la imagen aquí Por lo tanto, la única forma en que una lista de puntos de la forma {0, 1, x[3] + I*y[3], x[4] + I*y[4]}puede tener cero segundos y terceros momentos centrales es cuando los cuatro puntos forman un cuadrado.

Debido a las propiedades de traslación, rotación y escala demostradas en los puntos 1 y 2, esto significa que cada vez que el segundo y tercer momento central son cero, tenemos un cuadrado en algún estado de traslación / rotación / escala. ∎

generalización

El k-ésimo momento central de un n-gon regular es cero si k no es divisible por n. Se deben combinar suficientes condiciones para formar un criterio suficiente para detectar n-gons. Para el caso n = 4 fue suficiente para detectar ceros en k = 2 yk = 3; para detectar, por ejemplo, hexágonos (n = 6) puede ser necesario verificar k = 2,3,4,5 para ceros. No he probado lo siguiente, pero sospecho que detectará cualquier n-gon regular:

isregularngon[p_List] :=
  And @@ Table[PossibleZeroQ[CentralMoment[p, k]], {k, 2, Length[p] - 1}]

El desafío del código es esencialmente este código especializado para listas de longitud 4.

romano
fuente
La solución parece bastante interesante. ¿Podría explicar por qué da la respuesta correcta?
Joel
@ Joel He agregado una prueba.
Romano
Muchas gracias. Sería ideal que pudiera haber una explicación matemática más intuitiva de esta buena solución.
Joel
@ Joo, puedo darte el hilo que me llevó a esta solución. Comencé notando que los cuadrados (como listas de coordenadas, no números complejos) tienen una matriz de covarianza que es proporcional a la matriz unitaria; sin embargo, esta condición no es suficiente (falsos positivos). El tercer momento central debe ser cero para cualquier estructura de simetría de puntos. Así que cambié a una representación compleja para colocar una condición en el segundo y tercer momento central, y para mi sorpresa resultó que el segundo momento central es cero para los cuadrados.
Romano
Excelente. Gracias por mostrar el camino a esta solución.
Joel
0

J, 31 29 27 26

3=[:#[:~.[:,([:+/*:@-)"1/~

comprueba si las 8 distancias más pequeñas entre los puntos son las mismas. comprueba si hay exactamente tres tipos de distancias entre los puntos (cero, longitud lateral y longitud diagonal).

f 4 2 $ 0 0 2 1 3 _1 1 _2
1
f 4 2 $ 0 0 0 2 3 2 3 0
0

4 2 $ es una forma de escribir una matriz en J.

Eelvex
fuente
Esto falla la prueba de rombos.
JB
@JB: tuve un error tipográfico. Cambié el método de todos modos ahora.
Eelvex
Eeew ... estás tomando el mismo método que estaba robando. Excepto que mi versión es más corta: p
JB
@JB: ¿en serio? No me di cuenta de eso. ¿Quién más verifica (3 == #distancias)?
Eelvex
@JB: oic ... alguna comprobación para combinaciones de 2.: - /
Eelvex
0

Smalltalk para 106 caracteres

s:=Set new.
p permutationsDo:[:e|s add:((e first - e second) dotProduct:(e first - e third))].
s size = 2

donde p es una colección de puntos, p. ej.

p := { 0@0. 2@1. 3@ -1. 1@ -2}. "twisted square"

Creo que las matemáticas son buenas ...


fuente
La comprobación de 2 productos de puntos distintos no es suficiente. Los puntos colocados en la misma posición pueden producir falsos positivos.
aaaaaaaaaaaa
0

Mathematica, 123 caracteres (pero puedes hacerlo mejor):

Flatten[Table[x-y,{x,a},{y,a}],1]
Sort[DeleteDuplicates[Abs[Flatten[Table[c.d,{c,%},{d,%}]]]]]
%[[1]]==0&&%[[3]]/%[[2]]==2

Donde 'a' es la entrada en el formulario de lista de Mathematica, por ejemplo: a={{0,0},{3,4},{8,4},{5,0}}

La clave es mirar el punto productos de entre todos los vectores y observar que deben tener exactamente tres valores: 0, x, y 2 * x para algún valor de x. El producto de punto verifica tanto la perpendicularidad como la longitud en una sola bola.

Sé que hay atajos de Mathematica que pueden acortar esto, pero no sé cuáles son.

barrycarter
fuente
Creo que este también está mal, pero no puedo entender qué hace el código.
aaaaaaaaaaaa
Calcula todos los vectores entre los 4 puntos, toma todos los productos de punto (valor absoluto) y espera que el resultado consista exactamente en 0, x, 2 * x para algún valor de x.
barrycarter
Entonces 16 vectores -> 256 productos de puntos, y usted verifica que el valor alto es 2 veces el bajo, pero no sabe cuántos hay de cada valor. ¿Es eso correcto entendido?
aaaaaaaaaaaa
Sí, eso describe correctamente mi algoritmo. Y ahora creo que tiene razón: podría construir un escenario en el que ocurrieran los 3 valores, pero no en la cantidad correcta. Ratas Sin embargo, ¿debería ser reparable?
barrycarter
@barrycarter Puede guardar caracteres usando en Unionlugar de Sort@DeleteDuplicates. Puse tus 3 líneas juntas también:#[[1]] == 0 && #[[3]]/#[[2]] == 2 &[ Union@Abs@Flatten[Table[c.d, {c, #}, {d, #}]] &[ Flatten[Table[x - y, {x, a}, {y, a}], 1]]]
DavidC
0

Haskell, "wc -c" informa 110 caracteres. No comprueba que la entrada tenga 4 elementos.

import Data.List
k [a,b]=2*a==b
k _=0<1
h ((a,b):t)=map (\(c,d)->(a-c)^2+(b-d)^2) t++h t
h _=[]
j=k.nub.sort.h

Probé en

test1 = [(0,0),(3,4),(-4,3),(-1,7)] -- j test1 is True
test2 = [(0,0),(3,4),(-3,4),(0,8)]  -- j test2 is False
Chris Kuklewicz
fuente
Tenga en cuenta que lo anterior nunca obtiene la distancia de un punto a sí mismo, por lo que la presencia de una distancia de 0 indicaría un punto repetido en la lista de entrada, y esto se mostrará en la lista ordenada como k [0, b] así que 2 * 0 == b siempre fallará ya que b no puede ser igual que 0.
Chris Kuklewicz