Determina se 4 punti formano un quadrato


29

Scrivi una funzione che accetta 4 punti sul piano come input e restituisce vero se i 4 punti formano un quadrato. I punti avranno coordinate integrali con valori assoluti <1000.

È possibile utilizzare qualsiasi rappresentazione ragionevole dei 4 punti come input. I punti non sono forniti in alcun ordine particolare.

Il codice più corto vince.

Quadrati di esempio:

(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

Esempio di non quadrati:

(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

Puoi restituire vero o falso per il quadrato degenerato (0,0),(0,0),(0,0),(0,0)


Stiamo parlando di punti 3D qui, giusto?
Gnibbler,

3
@gnibbler "on il piano" parte della domanda make 3D sottolinea improbabile.
JB

I punti vengono assegnati in ordine?
JB

@JB, stavo pensando che significava che i punti erano su un piano, ma ho visualizzato un piano nello spazio 3D per qualche motivo :)
gnibbler

1
@eBusiness: -1 che hai espresso 11 voti: 7 di loro sono in calo.
Eelvex,

Risposte:


12

Python 176 90 79 byte

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

La funzione S prende un elenco di numeri complessi come input (A). Se conosciamo sia il centro che l'angolo di un quadrato, possiamo ricostruire il quadrato ruotando l'angolo di 90.180 e 270 gradi attorno al punto centrale (c). Sul piano complesso la rotazione di 90 gradi attorno all'origine viene fatta moltiplicando il punto per i . Se la nostra forma originale e il quadrato ricostruito hanno gli stessi punti, allora deve essere stato un quadrato.


Alcune ottimizzazioni: 1) usa "S" invece di "is_square" 2) metti tutto su una riga usando; 3) scorrere le 4 direzioni direttamente "per i in (1,1j, -1, -1j)" 4) non è necessario [] nell'argomento set.
Keith Randall,

Grazie Keith. (Ho lasciato fuori (3) in quanto sembra avere la stessa lunghezza del mio codice)
paperhorse

2
@Keith Randall - Perché è stato accettato quando JB ha una soluzione molto più breve?
aaaaaaaaaaaa

1
Due ragioni. Uno, J vincerebbe sempre. Quindi mi piace normalizzare un po 'per lingua. Inoltre, mi piace meglio questa risposta perché non soffre dello stesso problema delle risposte a distanza in cui altre figure (è vero, solo quelle irrazionali) danno falsi positivi.
Keith Randall,

5
@Keith Randall - Citazioni dalla domanda: "I punti avranno coordinate integrali" "Il codice più corto vince.". Va benissimo se scegli criteri diversi per la selezione di una risposta, anche criteri soggettivi, ma poi dovresti affermarlo nella domanda.
aaaaaaaaaaaa

13

J, 28 17 25 27

J non ha davvero funzioni, ma ecco un verbo monadico che prende un vettore di punti dal piano complesso:

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

Il metodo è un mix di Michael Spencer (lavora esclusivamente su lunghezze inter-vertici; ma al momento non riesce il mio rombo2) e le opere di Eelvex (controlla le dimensioni dei set). Lettura da destra a sinistra:

  • -/~ calcola tutte le differenze di punti
  • , appiattire
  • | estrarre magnitudine
  • /:~ ordinare
  • #/.~ strofinare e contare
  • 4 8 4 -:deve avere esattamente 4 equidistanti (a 0), 8 un po 'più grandi (lunghezza 1, lati), 4 ancora più grandi (lunghezza sqrt 2, diagonali)

Dimostrazione:

   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

Per amor di memoria, il mio metodo precedente (richiesto vertici ordinati, ma poteva rilevare poligoni regolari di qualsiasi ordine):

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

Vedi la storia per spiegazioni e demo. Il metodo attuale potrebbe probabilmente essere esteso ad altri poligoni, che 4 8 4assomigliano molto a una distribuzione binomiale.


Puoi collegarti a questa lingua?
Sargun Dhillon,

1
@gnibbler: Perché no? Sono abbastanza sicuro che lo faccia.
Eelvex,

1
In realtà, esiste una figura non quadrata che soddisfa le condizioni da verificare, un triangolo regolare più un punto una lunghezza laterale da una punta del triangolo posizionata sulla mediana estesa. Ma la domanda richiedeva un input intero, quindi immagino che la soluzione sia ok.
aaaaaaaaaaaa

1
Ah ok. Stavo pensando a triangoli equilateri con il quarto punto al centro, ma questo è escluso dalle coordinate
intere

1
Puoi tagliare 3 caratteri cambiandolo in una definizione esplicita: 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

Aggiornamento 1) per richiedere 4 punti diversi (in precedenza darebbe falsi positivi per punti ripetuti - ce ne sono altri?) 2) per definire una funzione per specifica

Per un quadrato, il vettore tra due punti qualsiasi deve essere 0 (lo stesso punto), un lato o una diagonale. Quindi, l'insieme della grandezza di questi vettori deve avere lunghezza 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)

Penso che la domanda abbia esplicitamente dichiarato un elenco di punti e non un vettore.
Sargun Dhillon,

Falsi positivi.
aaaaaaaaaaaa

1
Quindi (0 + 0j, 0 + 0j, 1 + 0j, 0 + 1j) è un quadrato?
mhagger,

Il mio rombo 2 non è 1 +/- 60j, è più simile a exp (i j pi / 3) per valori da -1, 0, 1. Nota che, come sottolineato da eBusiness, non possono essere tutti integrali, quindi non proprio in la portata della domanda.
JB

3

Haskell, 100 personaggi

Ecco come scriverei la soluzione J di JB in Haskell. Senza tentare di danneggiare la leggibilità rimuovendo i caratteri non essenziali, sono circa 132 caratteri:

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]

Puoi ridimensionarlo un po 'fino a 100 rimuovendo gli spazi in eccesso e rinominando alcune cose

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]

Usiamo QuickCheck per assicurarci che accetti quadrati arbitrari, con un vertice in (x, y) e il vettore del bordo (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)]

Provandolo in ghci:

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

Oh giusto, il quadrato vuoto non è considerato un quadrato qui, quindi rivedremo il nostro test:

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 riprovare:

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

1
Salva 11 caratteri srotolando la funzione d. s l=[4,8,4]==(map length.group.sort)[(x-a)^2+(y-b)^2|(x,y)<-l,(a,b)<-l]
Ray,

3

Fattore

Un'implementazione nel linguaggio di programmazione 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 ;

E alcuni test unitari:

[ 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

Esegui in questo modo:

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

Disobbediamo e spieghiamo un po '.

Per prima cosa definiamo una norma:

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

Noterai che non c'è chiamata a sqrt, non è necessario qui.

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

Qui a, b, c e d sono punti. Partiamo dal presupposto che questi punti sono disposti in questo modo:

a - b
| / |
c - d

Se abbiamo un quadrato, tutte queste condizioni devono contenere:

  • abc è un triangolo rettangolo
  • bcd è un triangolo rettangolo
  • i lati più piccoli di ciascun triangolo rettangolo hanno le stesse norme

Si noti che vale sempre quanto segue:

is_square_with_fixed_layout r s t u = is_square_with_fixed_layout r t s u

Lo useremo per semplificare la nostra funzione di test di seguito.

Poiché il nostro input non è ordinato, dobbiamo anche verificare tutte le permutazioni. Senza perdita di generalità possiamo evitare di permutare il primo 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

Dopo la semplificazione:

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

Modifica: seguito il consiglio di M.Giovannini.


Bello. Non abbiamo visto molto OCaml qui :)
Eelvex

Utilizzare un operatore, invece di nuna riduzione del 20 caratteri: 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)

I punti sono rappresentati da (x,y)tuple. I punti possono essere in qualsiasi ordine e accettano solo quadrati. Crea un elenco sdi distanze a coppie (diverse da zero) tra i punti. Dovrebbero esserci 12 distanze in totale, in due gruppi unici.

def f (p): s = filtro (Nessuno, [(xz) ** 2+ (yw) ** 2per x, y in p per z, w in p]); return len (s) == 12and len ( set (s)) == 2

Potresti tralasciare il filtro e verificare se la len del set è 3. Questo però soffre dello stesso falso problema positivo della mia risposta.
Gnibbler,

>>> f ([(0,0), (0,4), (2,2), (- 2,2)]) = True
Sargun Dhillon

2
f([(0,0),(0,4),(2,2),(-2,2)]) è una piazza
gnibbler

2

Python - 42 caratteri

Sembra un miglioramento usare numeri complessi per i punti

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

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

vecchia risposta:

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

I punti sono specificati in qualsiasi ordine come un elenco, ad es

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,

@Sargun, questo è un caso speciale di un'intera classe di input che non funziona. Sto cercando di pensare a una soluzione che non spenga le dimensioni della risposta. Nel frattempo, riesco a capire la classe generale di casi fallimentari?
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: quell'esempio è un quadrato.
Keith Randall,

per sbarazzarsi di punti duplicati è possibile aggiungere -set ([0])
Keith Randall

2

C # - non esattamente breve. Abuso di LINQ. Seleziona due combinazioni distinte di punti nell'input, calcola le loro distanze, quindi verifica che esattamente quattro di loro siano uguali e che vi sia solo un altro valore di distanza distinto. Point è una classe con due membri doppi, X e Y. Potrebbe essere facilmente una Tupla, ma 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 caratteri


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

Ma solo perché il rettangolo di selezione è quadrato non significa che i punti si trovino in un quadrato. Condizione necessaria ma non sufficiente. Considera (0,0), (5,5), (10,0), (0, -5). Il riquadro di delimitazione è quadrato (0:10, -5: 5); la figura non lo è.
Floris,

2

K - 33

Traduzione del soluzione J di JB :

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

K soffre qui delle sue parole riservate (_sqr e _sqrt).

test:

  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

Batterie OCaml +, 132 caratteri

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

(guarda, Ma, niente spazi!) La comprensione dell'elenco in q forme la lista delle norme quadrate per ogni distinta coppia di punti non ordinata. Un quadrato ha quattro lati uguali e due diagonali uguali, le lunghezze quadrate di quest'ultima sono il doppio delle lunghezze quadrate della prima. Dal momento che non esistono triangoli equilateri nel reticolo intero, il test non è realmente necessario, ma lo includo per completezza.

test:

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 che il numero di distanze tra punti distinte (esclusa la distanza da un punto a se stesso) sia 2 e che la più breve delle due non sia 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 *)

Vero
Vero
Vero
Falso
Falso
Falso
Falso

NB: \[And]è un singolo personaggio di Mathematica.


1
Mi stai dicendo che Mathematica non ha una funzione IsSquare integrata?
Goodguy

2

Gelatina , 8 byte

_Æm×ıḟƊṆ

Provalo online!

Prende un elenco di numeri complessi come argomento della riga di comando. Stampe 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.

Sembra una sfida divertente da rilanciare!


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

Primo tentativo ingenuo. Verifica le seguenti due condizioni per tutte le permutazioni dell'elenco di input dei punti (dove una data permutazione rappresenta, diciamo, un ordine in senso orario dei punti):

  • tutti gli angoli sono di 90 gradi
  • tutti i lati hanno la stessa lunghezza

Codice e test deobfuscati

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

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 caratteri

Matematicamente uguale alla risposta di J Bs. Genera le 6 lunghezze e afferma che i 2 più grandi sono uguali e che i 4 più piccoli sono uguali. L'input deve essere una matrice di array.

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 caratteri

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

Questo si basa sulla risposta JavaScript di eBuisness .


Non è chiaro dall'affermazione del problema i punti verrebbero ordinati. Vado a chiedere.
JB

1
Non penso che questo gestirà correttamente molti casi. Ad esempio, etichetterà erroneamente i rombi come quadrati.
Keith Randall,

Aggiornato questo per abbinare una delle risposte JavaScript, dovrebbe gestire tutti i casi.
Kevin Brown,

1

JavaScript 1.8, 112 caratteri

Aggiornamento: salvato 2 caratteri piegando insieme le comprensioni dell'array.

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

Un'altra reimplementazione della risposta di JB. Sfrutta le funzionalità di JavaScript 1.7 / 1.8 (chiusure di espressioni, comprensione di array, assegnazione di destrutturazione). Abusa anche ~~(doppio bit a bit non operatore) per forzare undefinedin numerico, con coercizione da array a stringa e una regexp per verificare che i conteggi di lunghezza siano[4, 8, 4] (presuppone che siano passati esattamente 4 punti). L'abuso dell'operatore virgola è un vecchio trucco offuscato C.

test:

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 caratteri

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

allargato:

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

Stesso algoritmo di della risposta di JB .

Prova come:

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

Output trueper true e blank per false


Mai sentito parlare di GoRuby. C'è qualcosa di ufficiale scritto al riguardo? stackoverflow.com/questions/63998/hidden-features-of-ruby/…
Jonas Elfström

@Jonas: non ho visto nulla di veramente ufficiale al riguardo, il miglior post sul blog che ho visto è questo . In realtà non sono stato in grado di farlo costruire e lavorare, ma un'alternativa è semplicemente copiare il preludio del golf nella stessa cartella ed eseguire ruby -r ./golf-prelude.rb FILE_TO_RUN.rbe funzionerà esattamente allo stesso modo.
Nemo157,

non è necessario sortprima group_by. .sort.group_by {...}dovrebbe essere scritto come.group_by {...}
user102008 il

1

Python 97 (senza punti complessi)

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

Questo prenderà elenchi di tuple di punti in [(x, y), (x, y), (x, y), (x, y)] in qualsiasi ordine e può gestire duplicati o un numero errato di punti. NON richiede punti complessi come le altre risposte di Python.

Puoi provarlo in questo modo:

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)

Questo richiederà un po 'di spiegazione, ma l'idea generale è che ci sono solo tre distanze tra i punti in un quadrato (Lato, Diagonale, Zero (punto rispetto a se stesso)):

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]))
  • per un elenco p di tuple (x, y)
  • Rimuovere i duplicati usando set (p) e quindi testare la lunghezza
  • Ottieni ogni combinazione di punti (a, b in p per c, d in p)
  • Ottieni l'elenco della distanza da ogni punto a ogni altro punto
  • Usa set per verificare che ci siano solo tre distanze uniche - Zero (punto rispetto a se stesso) - Lunghezza laterale - Lunghezza diagonale

Per salvare i caratteri in codice sono:

  • utilizzando un nome di funzione 1 carattere
  • usando una definizione di funzione a 1 riga
  • Invece di verificare che il numero di punti univoci sia 4, controllo che sia -1 le diverse lunghezze dei punti (salva == 3 ==)
  • usa list e tuple unpacking per ottenere a, b in p per c, d in p, invece di usare a [0], a [1]
  • usa pow (x, .5) invece di includere la matematica per ottenere sqrt (x)
  • non mettere spazi dopo il)
  • non mettere uno zero iniziale sul float

Temo che qualcuno riesca a trovare un caso di prova che lo rompa. Quindi, per favore, fallo e maledetto. Ad esempio, il fatto che io controlli solo tre distanze, invece di fare un abs () e controllare la lunghezza del lato e l'ipotenusa, sembra un errore.

La prima volta che ho provato il codice golf. Sii gentile se ho infranto le regole della casa.


1

Clojure, 159 caratteri.

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

Modifica: per spiegare anche un po '.

  • Per prima cosa definisci una norma che sostanzialmente fornisce la distanza tra due punti dati.
  • Quindi calcola la distanza del primo punto rispetto agli altri tre punti.
  • Ordina le tre distanze. (Ciò consente qualsiasi ordine dei punti.)
  • Le due distanze più brevi devono essere uguali a un quadrato.
  • La terza (più lunga) distanza deve essere uguale alla radice quadrata della somma dei quadrati delle brevi distanze dal teorema di Pitagora.

(Nota: il rooting quadrato non è necessario e quindi nel codice salvato sopra.)


1

C #, 107 caratteri

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

Dove punti è Elenco di Vector3D contenente i punti.

Calcola tutte le distanze al quadrato tra tutti i punti e se esistono esattamente tre tipi distinti (deve essere 0, un valore a e 2 * a) e 4 punti distinti, i punti formano un quadrato.



1

Python 2 , 49 byte

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

Provalo online!

Prende un elenco di quattro numeri complessi come input. Ruota ogni punto di 90 gradi attorno alla media e verifica che ciascun punto risultante sia nell'elenco originale.

Stessa lunghezza (sebbene più corta in Python 3 usando {*l}).

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

Provalo online!


Perché non usare Python 3 se è più corto? Inoltre, se è consentito restituire valori di verità / falsità arbitrari in Python, è ^possibile utilizzare al posto di ==.
Gioele il

@Joel Python 2 è principalmente una preferenza, e questa è una sfida molto vecchia del 2011, quando Python 2 era praticamente considerato il golf di Python. E la sfida dice di tornare vero o falso, quindi mi sono bloccato con quello. Se questo è stato pubblicato oggi, probabilmente specificherà l'output di verità / falsità o uno di due valori distinti, e potrebbe anche essere accettabile per impostazione predefinita da parte di OK.
xnor

1

Wolfram Language (Mathematica) , 32 31 byte

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

Provalo online!

Prende un elenco di punti rappresentati da numeri complessi, calcola il secondo e il terzo momento centrale e verifica che entrambi siano zero.

Un-giocato a golf:

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

o

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

prova

Questo criterio funziona su tutto il piano complesso, non solo sugli interi gaussiani .

  1. Innanzitutto, notiamo che il momenti centrali non cambiano quando i punti vengono tradotti insieme. Per una serie di punti

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

    i momenti centrali sono tutti indipendenti c(ecco perché sono chiamati centrali ):

    {FreeQ[FullSimplify[CentralMoment[P, 2]], c], FreeQ[FullSimplify[CentralMoment[P, 3]], c]}
    (*    {True, True}    *)
    
  2. In secondo luogo, i momenti centrali hanno una semplice dipendenza dal complesso ridimensionamento (ridimensionamento e rotazione) dell'insieme di punti:

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

    Ciò significa che se un momento centrale è zero, il ridimensionamento e / o la rotazione dell'insieme di punti manterrà il momento centrale uguale a zero.

  3. Terzo, dimostriamo il criterio per un elenco di punti in cui sono fissati i primi due punti:

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

    In quali condizioni le parti reali e immaginarie del secondo e terzo momento centrale sono 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}}    *)
    

    Tutte queste sei soluzioni rappresentano i quadrati: enter image description here Pertanto, l'unico modo in cui un elenco di punti del modulo {0, 1, x[3] + I*y[3], x[4] + I*y[4]}può avere zero secondi e terzi momenti centrali è quando i quattro punti formano un quadrato.

A causa delle proprietà di traduzione, rotazione e ridimensionamento dimostrate nei punti 1 e 2, ciò significa che ogni volta che il secondo e il terzo momento centrale sono zero, abbiamo un quadrato in uno stato di traslazione / rotazione / ridimensionamento. ∎

generalizzazione

Il k-esimo momento centrale di un normale n-gon è zero se k non è divisibile per n. Basta queste condizioni devono essere combinate per costituire un criterio sufficiente per rilevare n-gon. Nel caso n = 4 è stato sufficiente rilevare zeri in k = 2 e k = 3; per rilevare, ad esempio, esagoni (n = 6) potrebbe essere necessario controllare k = 2,3,4,5 per gli zeri. Non ho dimostrato quanto segue, ma sospetto che rileverà qualsiasi normale n-gon:

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

La sfida del codice è essenzialmente questo codice specializzato per elenchi di lunghezza 4.


La soluzione sembra abbastanza interessante. Potresti spiegare perché dà la risposta corretta?
Gioele,

@Joel ho aggiunto una prova.
Roman

Molte grazie. Sarebbe ideale che ci potesse essere una spiegazione matematica più intuitiva di questa bella soluzione.
Gioele il

@ Gioele, posso darti il ​​filo conduttore che mi ha portato a questa soluzione. Ho iniziato notando che i quadrati (come elenchi di coordinate, non numeri complessi) hanno una matrice di covarianza proporzionale alla matrice dell'unità; tuttavia, questa condizione non è sufficiente (falsi positivi). Il terzo momento centrale deve essere zero per qualsiasi struttura di simmetria del punto. Quindi sono passato alla rappresentazione complessa per porre una condizione sul secondo e terzo momento centrale, e con mia sorpresa si è scoperto che il secondo momento centrale è zero per i quadrati.
Roman

Grande. Grazie per aver mostrato il percorso per questa soluzione.
Gioele,

0

J, 31 29 27 26

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

controlla se le 8 distanze più piccole tra i punti sono uguali. controlla se ci sono esattamente tre tipi di distanze tra i punti (zero, lunghezza laterale e lunghezza diagonale).

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 $ è un modo di scrivere un array in J.


Questo fallisce il test del rombo.
JB

@JB: ho avuto un refuso. Ho cambiato il metodo comunque ora.
Eelvex,

Eeew ... stai seguendo lo stesso metodo che stavo rubando. Tranne la mia versione più breve: p
JB

@JB: davvero? Non me ne sono accorto. Chi altro controlla (3 == #distanze)?
Eelvex,

@JB: oic ... alcuni controlli per combinazioni di 2.: - /
Eelvex

0

Smalltalk per 106 caratteri

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

dove p è una raccolta di punti, ad es

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

Penso che la matematica sia sana ...


Il controllo di 2 prodotti con punti distinti non lo taglia. I punti collocati nella stessa posizione possono produrre falsi positivi.
aaaaaaaaaaaa

0

Mathematica, 123 caratteri (ma puoi fare di meglio):

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

Dove "a" è l'input nel modulo elenco di Mathematica, ad esempio: a={{0,0},{3,4},{8,4},{5,0}}

La chiave è guardare il punto prodotti tra tutti i vettori e notare che devono avere esattamente tre valori: 0, xe 2 * x per un valore di x. Il prodotto punto controlla sia la perpendicolarità sia la lunghezza in un unico rigonfiamento.

So che ci sono scorciatoie di Mathematica che possono rendere questo più breve, ma non so cosa siano.


Penso che anche questo sia sbagliato, ma non riesco a capire cosa faccia il codice.
aaaaaaaaaaaa

Calcola tutti i vettori tra i 4 punti, prende tutti i prodotti punto (valore assoluto) e si aspetta che il risultato sia esattamente 0, x, 2 * x per un valore di x.
Barrycarter

Quindi 16 vettori -> 256 punti di prodotti e controlli che il valore più alto sia 2 volte più basso, ma non quanti ne esistono di ogni valore. È capito bene?
aaaaaaaaaaaa

Sì, questo descrive correttamente il mio algoritmo. E ora penso che tu abbia ragione: potresti costruire uno scenario in cui si sono verificati tutti e 3 i valori, ma non nella giusta quantità. Ratti. Dovrebbe essere risolvibile però?
Barrycarter

@barrycarter Puoi salvare i caratteri usando Unioninvece di Sort@DeleteDuplicates. Metto insieme anche le tue 3 righe:#[[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" riporta 110 caratteri. Non verifica che l'ingresso abbia 4 elementi.

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

Ho provato

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

Nota quanto sopra non ottiene mai la distanza da un punto a se stesso, quindi la presenza di una distanza di 0 indicherebbe un punto ripetuto nell'elenco di input, e questo verrà mostrato nell'elenco ordinato come k [0, b] quindi 2 * 0 == b fallirà sempre poiché b non può essere uguale a 0.
Chris Kuklewicz
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.