Determine se 4 pontos formam um quadrado

29

Escreva uma função que use 4 pontos no plano como entrada e retorne verdadeiro se os 4 pontos formarem um quadrado. Os pontos terão coordenadas integrais com valores absolutos <1000.

Você pode usar qualquer representação razoável dos 4 pontos como entrada. Os pontos não são fornecidos em nenhuma ordem específica.

O menor código vence.

Quadrados de exemplo:

(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

Exemplos não quadrados:

(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

Você pode retornar verdadeiro ou falso para o quadrado degenerado (0,0),(0,0),(0,0),(0,0)

Keith Randall
fonte
Estamos falando de pontos 3D aqui, certo?
gnibbler
3
@gnibbler o "on a plane" parte da pergunta make 3D aponta improvável.
JB
Os pontos são dados em ordem?
JB
@JB, eu estava pensando que isso significava os pontos estavam em um avião, mas eu visualizei um avião no espaço 3D por algum motivo :)
gnibbler
11
@eBusiness: -1 que você emitiu 11 votos: 7 deles em queda.
Eelvex

Respostas:

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

A função S recebe uma lista de números complexos como entrada (A). Se conhecermos o centro e o canto de um quadrado, podemos reconstruí-lo girando o canto 90.180 e 270 graus em torno do ponto central (c). No plano complexo, a rotação de 90 graus sobre a origem é feita multiplicando o ponto por i . Se a nossa forma original e o quadrado reconstruído tiverem os mesmos pontos, deve ter sido um quadrado.

cavalo de papel
fonte
Algumas otimizações: 1) use "S" em vez de "is_square" 2) coloque tudo em uma linha usando; 3) itere diretamente nas 4 direções "para i in (1,1j, -1, -1j)" 4) não precisa de [] no argumento de conjunto.
Keith Randall
Obrigado Keith. (Eu deixei de fora (3), uma vez que parece ser o mesmo comprimento que o meu código)
paperhorse
2
@ Keith Randall - Por que isso foi aceito quando o JB tem uma solução muito mais curta?
Aaaaaaaaaaaa
11
Duas razões. Primeiro, J sempre venceria. Então, eu gosto de normalizar um pouco por idioma. Além disso, eu gosto mais dessa resposta porque ela não sofre do mesmo problema que as respostas somente à distância, onde outras figuras (reconhecidamente, apenas irracionais) dão falsos positivos.
Keith Randall
5
@Keith Randall - Citações da pergunta: "Os pontos terão coordenadas integrais" "O menor código vence". Está perfeitamente bem se você escolher critérios diferentes para selecionar uma resposta, mesmo critérios subjetivos, mas, em seguida, deve declarar isso na pergunta.
Aaaaaaaaaaaa
13

J, 28 17 25 27

J realmente não tem funções, mas aqui está um verbo monádico que pega um vetor de pontos do plano complexo:

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

O método é uma mistura de Michael Spencer (trabalho exclusivamente em comprimentos entre vértices; mas ele está atualmente falhando no meu losango2) e do Eelvex (verifique o tamanho dos conjuntos) funciona. Leitura da direita para a esquerda:

  • -/~ calcular todas as diferenças de pontos
  • , aplainar
  • | extrair magnitude
  • /:~ arrumar
  • #/.~ nub e count
  • 4 8 4 -:deve ter exatamente 4 equidistantes (em 0), 8 um pouco maiores (comprimento 1, lados), 4 maiores ainda (comprimento sqrt 2, diagonais)

Demonstração:

   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 uma questão de memória, meu método anterior (exigia vértices ordenados, mas podia detectar polígonos regulares de qualquer ordem):

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

Veja o histórico para obter explicações e demonstrações. O método atual provavelmente poderia ser expandido para outros polígonos, que 4 8 4se parece muito com uma distribuição binomial.

JB
fonte
Você pode criar um link para esse idioma?
Sargun Dhillon 11/03/11
11
@gnibbler: Por que não? Tenho certeza que sim.
Eelvex
11
Na verdade, existe uma figura não quadrada que satisfaz as condições que você verifica, um triângulo regular mais um ponto ao lado de uma ponta do triângulo colocada na mediana estendida. Mas a pergunta pedia uma entrada inteira, então acho que a solução está ok.
Aaaaaaaaaaaa
11
Ah ok. Eu estava pensando em triângulos equiláteros com o quarto ponto é o centro, mas que é governado pelos inteiros coordenadas
gnibbler
11
Você poderia cortar 3 caracteres alterando-o para uma definição explícita: 3 :'4 8 4-:#/.~/:~|,-/~y'
isawdrones
5

Python, 71 42

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

Atualização 1) para exigir 4 pontos diferentes (anteriormente daria falsos positivos para pontos repetidos - existem outros?) 2) para definir uma função por especificação

Para um quadrado, o vetor entre dois pontos deve ser 0 (o mesmo ponto), um lado ou uma diagonal. Portanto, o conjunto da magnitude desses vetores deve ter comprimento 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
fonte
Eu acho que a pergunta declarou explicitamente uma lista de pontos, e não um vetor.
Sargun Dhillon 11/03/11
Falso-positivo.
Aaaaaaaaaaaa
11
Então (0 + 0j, 0 + 0j, 1 + 0j, 0 + 1j) é um quadrado?
mhagger
Meu losango 2 não é 1 +/- 60j, é mais como exp (i j pi / 3) para valores de -1, 0, 1. Observe que, como o eBusiness apontou, eles não podem ser todos integrais; o escopo da pergunta.
JB
3

Haskell, 100 caracteres

Aqui está como eu escreveria a solução J do JB em Haskell. Sem nenhuma tentativa de prejudicar a legibilidade removendo caracteres não essenciais, são cerca 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]

Você pode reduzi-lo um pouco para 100 removendo espaços em excesso e renomeando algumas coisas

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]

Vamos usar o QuickCheck para garantir que ele aceite quadrados arbitrários, com um vértice em (x, y) e o vetor de aresta (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)]

Tentando em ghci:

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

Ah, certo, o quadrado vazio não é considerado quadrado aqui, então revisaremos nosso teste:

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

E tentando novamente:

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

fonte
11
Salve 11 caracteres desenrolando a função d. s l=[4,8,4]==(map length.group.sort)[(x-a)^2+(y-b)^2|(x,y)<-l,(a,b)<-l]
21413 Ray
3

Fator

Uma implementação na linguagem de programação do Fator :

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 ;

E alguns testes de unidade:

[ 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
fonte
3

OCaml, 145 164

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

Execute assim:

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

Vamos desobstruir e explicar um pouco.

Primeiro, definimos uma norma:

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

Você notará que não há chamada para o sqrt, não é necessário aqui.

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

Aqui a, b, c e d são pontos. Assumimos que esses pontos são dispostos da seguinte maneira:

a - b
| / |
c - d

Se temos um quadrado, todas essas condições devem ser válidas:

  • abc é um triângulo retângulo
  • bcd é um triângulo retângulo
  • os lados menores de cada triângulo retângulo têm as mesmas normas

Observe que o seguinte sempre se aplica:

is_square_with_fixed_layout r s t u = is_square_with_fixed_layout r t s u

Usaremos isso para simplificar nossa função de teste abaixo.

Como nossa entrada não é ordenada, também precisamos verificar todas as permutações. Sem perda de generalidade, podemos evitar permutar o primeiro ponto:

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

Após a simplificação:

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

Edit: seguiu o conselho de M.Giovannini.

bltxd
fonte
Agradável. Nós não vimos muito OCaml aqui :)
Eelvex
Use um operador em vez de numa redução em 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

Python (105)

Os pontos são representados por (x,y)tuplas. Os pontos podem estar em qualquer ordem e só aceitam quadrados. Cria uma lista sde distâncias em pares (diferentes de zero) entre os pontos. Deve haver 12 distâncias no total, em dois grupos únicos.

def f (p): s = filtro (Nenhum, [(xz) ** 2+ (yw) ** 2para x, y em p para z, w em p]); return len (s) == 12and len ( conjuntos (s)) == 2
Hoa Long Tam
fonte
Você pode deixar de fora o filtro e verificar se o len do conjunto é 3. Isso sofre do mesmo problema de falso positivo que a minha resposta.
gnibbler
>>> f ([(0,0), (0,4), (2,2), (- 2,2)]) = Verdadeiro
Sargun Dhillon 11/11/11
2
f([(0,0),(0,4),(2,2),(-2,2)]) é um quadrado
gnibbler 11/03/11
2

Python - 42 caracteres

Parece que é uma melhoria usar números complexos para os pontos

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

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

resposta antiga:

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

Os pontos são especificados em qualquer ordem como uma lista, por exemplo

A = [(11, 13), (14, 12), (13, 9), (10, 10)]
mordedor
fonte
>>> 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 11/03/11
@ Sargun, esse é um caso especial de toda uma classe de entradas que não funcionam. Estou tentando pensar em uma solução que não exploda o tamanho da resposta. Enquanto isso, pode resolver a classe geral de casos com falha?
N
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 11/03/11
@ Sargun: esse exemplo é um quadrado.
Keith Randall
para se livrar de pontos duplicados, você pode adicionar -set ([0])
Keith Randall
2

C # - não exatamente curto. Abusando do LINQ. Seleciona duas combinações distintas de pontos na entrada, calcula suas distâncias e verifica se exatamente quatro são iguais e se existe apenas um outro valor de distância distinto. Point é uma classe com dois membros duplos, X e Y. Poderia facilmente ser uma tupla, mas 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
fonte
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
fonte
Mas apenas porque a caixa delimitadora é quadrada, não significa que os pontos estejam em um quadrado. Condição necessária, mas não suficiente. Considere (0,0), (5,5), (10,0), (0, -5). A caixa delimitadora é quadrada (0:10, -5: 5); figura não é.
Floris
2

K - 33

Tradução da solução J por JB :

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

K sofre aqui de suas palavras reservadas ( _sqre _sqrt).

Teste:

  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
fonte
2

OCaml + baterias, 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

(veja, Ma, sem espaços!) A compreensão qda lista forma a lista de normas ao quadrado para cada par de pontos não ordenados distintos. Um quadrado tem quatro lados iguais e duas diagonais iguais, os comprimentos ao quadrado do último sendo duas vezes os comprimentos ao quadrado do anterior. Como não existem triângulos equiláteros na rede inteira, o teste não é realmente necessário, mas eu o incluo para completar.

Testes:

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
fonte
2

Mathematica 65 80 69 66

Verifica se o número de distâncias entre pontos distintos (sem incluir a distância de um ponto a si mesmo) é 2 e o menor dos dois não é 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 *)

Verdadeiro
Verdadeiro
Verdadeiro
Falso
Falso
Falso
Falso

NB: \[And]é um caractere único no Mathematica.

DavidC
fonte
11
Você está me dizendo que o Mathematica não possui uma função IsSquare integrada?
goodguy 25/03
2

Gelatina , 8 bytes

_Æm×ıḟƊṆ

Experimente online!

Leva uma lista de números complexos como um argumento de linha de comando. Imprime 1ou 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.

Parece um desafio agradável para reviver!

Lynn
fonte
1

Haskell (211)

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

Primeira tentativa ingênua. Verifica as duas condições a seguir para todas as permutações da lista de pontos de entrada (onde uma determinada permutação representa, por exemplo, uma ordem dos pontos no sentido horário):

  • todos os ângulos são 90 graus
  • todos os lados têm o mesmo comprimento

Código e testes desofuscados

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
fonte
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
fonte
1

JavaScript 144 caracteres

Matematicamente igual à resposta J Bs. Ele gera os 6 comprimentos e afirma que os 2 maiores são iguais e que os 4 menores são iguais. A entrada deve ser uma matriz de matrizes.

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
fonte
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];}

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

Isso é baseado na resposta JavaScript do eBuisness .

Kevin Brown
fonte
Não está claro, a partir da declaração do problema, que os pontos seriam ordenados. Eu vou perguntar.
JB
11
Eu não acho que isso irá lidar adequadamente com muitos casos. Por exemplo, ele rotulará incorretamente os losangos como quadrados.
Keith Randall
Atualizado para corresponder a uma das respostas de JavaScript, deve lidar com todos os casos.
Kevin Brown
1

JavaScript 1,8, 112 caracteres

Atualização: salvou 2 caracteres dobrando as compreensões da matriz.

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

Outra reimplementação da resposta de JB. Explora os recursos do JavaScript 1.7 / 1.8 (fechamento de expressões, compreensão de array, atribuição de desestruturação). Também abusa ~~(operador não bit a bit duplo) para coagir undefinedpara numérico, com coerção de matriz para string e um regexp para verificar se a contagem de comprimento é [4, 8, 4](pressupõe que exatamente 4 pontos foram passados). O abuso do operador de vírgula é um velho truque C ofuscado.

Testes:

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

Mesmo algoritmo que a resposta de JB .

Teste como:

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

Saídas truepara verdadeiro e em branco para falso

Nemo157
fonte
Nunca ouvi falar do GoRuby. Existe alguma coisa oficial escrita sobre isso? stackoverflow.com/questions/63998/hidden-features-of-ruby/…
Jonas Elfström
@Jonas: Eu não vi nada realmente oficial sobre isso, o melhor post que eu vi foi esse . Na verdade, não consegui fazê-lo funcionar, mas uma alternativa é apenas copiar o prelúdio de golfe na mesma pasta e executar, ruby -r ./golf-prelude.rb FILE_TO_RUN.rbe ele funcionará exatamente da mesma maneira.
Nemo157
não é necessário sortantes group_by. .sort.group_by {...}deve ser escrito como.group_by {...}
user102008
1

Python 97 (sem pontos complexos)

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

Isso pega listas de tuplas de pontos em [(x, y), (x, y), (x, y), (x, y)] em qualquer ordem e pode lidar com duplicatas ou com o número errado de pontos. NÃO requer pontos complexos, como as outras respostas em python.

Você pode testá-lo assim:

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)

Isso vai exigir um pouco de explicação, mas a ideia geral é que existem apenas três distâncias entre os pontos em um quadrado (Lateral, Diagonal, Zero (ponto comparado a ele mesmo)):

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 obter uma lista p de tuplas (x, y)
  • Remova as duplicatas usando o conjunto (p) e teste o comprimento
  • Obtenha todas as combinações de pontos (a, b em p para c, d em p)
  • Obter lista da distância de cada ponto a qualquer outro ponto
  • Use set para verificar se existem apenas três distâncias únicas - Zero (ponto comparado com ele mesmo) - Comprimento lateral - Comprimento diagonal

Para salvar os caracteres de código, eu sou:

  • usando um nome de função de 1 caractere
  • usando uma definição de função de 1 linha
  • Em vez de verificar se o número de pontos únicos é 4, eu verifico se -1 possui diferentes comprimentos de pontos (salva == 3 ==)
  • use descompactar lista e tupla para obter a, b em p para c, d em p, em vez de usar a [0], a [1]
  • usa pow (x, .5) em vez de incluir matemática para obter sqrt (x)
  • não colocando espaços após o)
  • não colocando um zero à esquerda no flutuador

Receio que alguém possa encontrar um caso de teste que quebre isso. Então, por favor, faça e eu corrijo. Por exemplo, o fato de verificar apenas três distâncias, em vez de fazer um abs () e verificar o comprimento do lado e a hipotenusa, parece um erro.

Primeira vez que experimentei código de golfe. Seja gentil se eu violar alguma regra da casa.

Jagu
fonte
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

Edit: Para também explicar um pouco.

  • Primeiro defina uma norma que basicamente dê a distância entre dois pontos dados.
  • Em seguida, calcule a distância do primeiro ponto aos outros três pontos.
  • Classifique as três distâncias. (Isso permite qualquer ordem dos pontos.)
  • As duas distâncias mais curtas devem ser iguais a um quadrado.
  • A terceira distância (mais longa) deve ser igual à raiz quadrada da soma dos quadrados das distâncias curtas pelo teorema de Pitágoras.

(Nota: o enraizamento quadrado não é necessário e, portanto, no código salvo acima.)

Meikel
fonte
1

C #, 107 caracteres

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

Onde points é Lista do Vector3D contendo os pontos.

Calcula todas as distâncias ao quadrado entre todos os pontos e, se houver exatamente três tipos distintos (deve ser 0, algum valor ae 2 * a) e 4 pontos distintos, os pontos formam um quadrado.

VOCÊS
fonte
1

Python 2 , 49 bytes

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

Experimente online!

Leva uma lista de quatro números complexos como entrada. Gira cada ponto 90 graus em torno da média e verifica se cada ponto resultante está na lista original.

Mesmo comprimento (embora menor no Python 3 usando {*l}).

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

Experimente online!

xnor
fonte
Por que não usar o Python 3 se for mais curto? Além disso, se for permitido retornar valores arbitrários de verdade / falsidade no Python, ele ^poderá ser usado em vez de ==.
Joel
O @Joel Python 2 é principalmente a preferência, e esse é um desafio muito antigo a partir de 2011, quando o Python 2 foi praticamente considerado um jogo de golfe em Python. E o desafio diz retornar verdadeiro ou falso, então fiquei com isso. Se isso fosse publicado hoje, provavelmente especificaria a saída truthy / falsey ou um dos dois valores distintos, e pode até ser aceitável aceitá-lo por padrão.
xnor 27/08
1

Wolfram Language (Mathematica) , 32 31 bytes

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

Experimente online!

Toma uma lista de pontos representados por números complexos, calcula o segundo e o terceiro momento central e verifica se ambos são zero.

Sem golfe:

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

ou

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

prova

Este critério funciona em todo o plano complexo, não apenas nos números inteiros gaussianos .

  1. Primeiro, notamos que os momentos centrais não mudam quando os pontos são traduzidos juntos. Para um conjunto de pontos

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

    os momentos centrais são todos independentes c(é por isso que são chamados central ):

    {FreeQ[FullSimplify[CentralMoment[P, 2]], c], FreeQ[FullSimplify[CentralMoment[P, 3]], c]}
    (*    {True, True}    *)
    
  2. Segundo, os momentos centrais dependem simples da escala complexa geral (escala e rotação) do conjunto de pontos:

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

    Isso significa que, se um momento central for zero, a escala e / ou a rotação do conjunto de pontos manterão o momento central igual a zero.

  3. Terceiro, vamos provar o critério para uma lista de pontos em que os dois primeiros pontos são fixos:

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

    Sob quais condições as partes reais e imaginárias do segundo e terceiro momentos centrais são zero?

    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 essas seis soluções representam quadrados: insira a descrição da imagem aqui Portanto, a única maneira de uma lista de pontos do formulário {0, 1, x[3] + I*y[3], x[4] + I*y[4]}ter zero segundo e terceiro momentos centrais é quando os quatro pontos formam um quadrado.

Devido às propriedades de translação, rotação e escala demonstradas nos pontos 1 e 2, isso significa que sempre que o segundo e o terceiro momentos centrais são zero, temos um quadrado em algum estado de translação / rotação / escala. ∎

generalização

O k-ésimo momento central de um n-gon regular é zero se k não é divisível por n. Muitas dessas condições devem ser combinadas para formar um critério suficiente para a detecção de n-gons. Para o caso n = 4, foi suficiente detectar zeros em k = 2 e k = 3; para detectar, por exemplo, hexágonos (n = 6), pode ser necessário verificar k = 2,3,4,5 quanto a zeros. Não provei o seguinte, mas suspeito que ele detectará qualquer n-gon regular:

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

O desafio do código é essencialmente esse código especializado para listas de tamanho 4.

romano
fonte
A solução parece bastante interessante. Você poderia explicar por que ela fornece a resposta correta?
Joel
@ Joel Adicionei uma prova.
Roman
Muito obrigado. Seria ideal que houvesse uma explicação matemática mais intuitiva dessa ótima solução.
Joel
@ Joel Eu posso lhe dar o fio que me levou a esta solução. Comecei percebendo que os quadrados (como listas de coordenadas, não números complexos) têm uma matriz de covariância proporcional à matriz unitária; no entanto, essa condição não é suficiente (falsos positivos). O terceiro momento central deve ser zero para qualquer estrutura de simetria de pontos. Então mudei para a representação complexa para colocar uma condição no segundo e no terceiro momento central e, para minha surpresa, verificou-se que o segundo momento central é zero para quadrados.
Roman
Ótimo. Obrigado por mostrar o caminho para esta solução.
Joel
0

J, 31 29 27 26

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

verifica se as 8 menores distâncias entre os pontos são iguais. verifica se existem exatamente três tipos de distâncias entre os pontos (zero, comprimento lateral e comprimento 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 $ é uma maneira de escrever uma matriz em J.

Eelvex
fonte
Isso falha no teste de losango.
JB
@JB: Eu tive um erro de digitação. Eu mudei o método de qualquer maneira agora.
Eelvex
Nossa ... você está seguindo o mesmo método que eu estava roubando. Exceto que minha versão é mais curta: p
JB
@JB: realmente? Eu não percebi isso. Quem mais verifica (3 == #distances)?
Eelvex 11/03/11
@JB: oic ... alguma verificação para combinações de 2.: - /
Eelvex 11/11
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

onde p é uma coleção de pontos, por exemplo

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

Eu acho que a matemática é boa ...


fonte
A verificação de 2 produtos com pontos distintos não é suficiente. Os pontos colocados na mesma posição podem produzir falsos positivos.
Aaaaaaaaaaaa
0

Mathematica, 123 caracteres (mas você pode fazer melhor):

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

Onde 'a' é a entrada no formulário de lista do Mathematica, por exemplo: a={{0,0},{3,4},{8,4},{5,0}}

A chave é examinar os produtos de ponto entre todos os vetores e observe que eles devem ter exatamente três valores: 0, x e 2 * x para algum valor de x. O produto pontilha verifica a perpendicularidade E o comprimento em um só swell.

Eu sei que existem atalhos do Mathematica que podem tornar isso mais curto, mas não sei o que são.

barrycarter
fonte
Acho que este também está errado, mas não consigo entender o que o código faz.
Aaaaaaaaaaaa
Ele calcula todos os vetores entre os 4 pontos, pega todos os produtos de ponto (valor absoluto) e espera que o resultado seja exatamente igual a 0, x, 2 * x para algum valor de x.
22125 barrycarter
Então, 16 vetores -> 256 produtos de ponto, e você verifica se o valor alto é 2 vezes o valor baixo, mas não sabe quantos existem de cada valor. Isso está correto?
Aaaaaaaaaaaa
Sim, isso descreve corretamente meu algoritmo. E agora acho que você está certo: você pode construir um cenário em que todos os três valores ocorreram, mas não na quantidade certa. Ratos. Mas deve ser corrigível?
Barrycarter
@barrycarter Você pode salvar caracteres usando em Unionvez de Sort@DeleteDuplicates. Coloquei suas 3 linhas juntas também:#[[1]] == 0 && #[[3]]/#[[2]] == 2 &[ Union@Abs@Flatten[Table[c.d, {c, #}, {d, #}]] &[ Flatten[Table[x - y, {x, a}, {y, a}], 1]]]
DavidC 15/05
0

Haskell, "wc -c" relata 110 caracteres. Não verifica se a entrada possui 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

Eu testei em

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
fonte
Observe que o acima nunca obtém a distância de um ponto para si mesmo; portanto, a presença de uma distância de 0 indica um ponto repetido na lista de entrada, e isso aparecerá na lista classificada como k [0, b], então 2 * 0 == b sempre falhará desde b não pode ser igual a como 0.
Chris Kuklewicz