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)


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.


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.


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)

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.

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

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.


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

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

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

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

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

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

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.


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!


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

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

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

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 .


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

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


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.


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


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.



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!


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.


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.


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


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.


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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.