Tentukan apakah 4 poin membentuk bujur sangkar

29

Tulis fungsi yang mengambil 4 titik pada bidang sebagai input dan mengembalikan true jika 4 poin membentuk kuadrat. Poin akan memiliki koordinat integral dengan nilai absolut <1000.

Anda dapat menggunakan representasi 4 poin yang masuk akal sebagai input. Poin tidak disediakan dalam urutan tertentu.

Kode terpendek menang.

Kotak contoh:

(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

Contoh non-kotak:

(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

Anda dapat mengembalikan benar atau salah untuk kotak degenerasi (0,0),(0,0),(0,0),(0,0)

Keith Randall
sumber
Kami berbicara poin 3D di sini, kan?
gnibbler
3
@gnibbler "pada the plane" bagian dari pertanyaan make 3D poin tidak mungkin.
JB
Apakah poin diberikan secara berurutan?
JB
@ JP, saya berpikir bahwa itu berarti poinnya ada di pesawat, tapi saya memvisualisasikan pesawat dalam ruang 3D untuk beberapa alasan :)
gnibbler
1
@eBusiness: -1 yang Anda berikan 11 suara: 7 di antaranya jatuh.
Eelvex

Jawaban:

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

Fungsi S mengambil daftar bilangan kompleks sebagai inputnya (A). Jika kita tahu pusat dan salah satu sudut kotak, kita dapat merekonstruksi kotak dengan memutar sudut 90.180 dan 270 derajat di sekitar titik pusat (c). Pada rotasi bidang yang rumit sebesar 90 derajat tentang titik asal dilakukan dengan mengalikan titik dengan i . Jika bentuk asli kita dan alun-alun yang direkonstruksi memiliki titik yang sama maka itu pasti persegi.

kuda kertas
sumber
Beberapa optimasi: 1) gunakan "S" bukan "is_square" 2) letakkan semuanya dalam satu baris menggunakan; 3) beralih ke 4 arah secara langsung "untuk i in (1,1j, -1, -1j)" 4) tidak perlu [] dalam argumen yang ditetapkan.
Keith Randall
Terima kasih Keith. (Saya ketinggalan (3) karena panjangnya sama dengan kode saya)
paperhorse
2
@Keith Randall - Mengapa ini diterima ketika JB memiliki solusi yang jauh lebih pendek?
aaaaaaaaaaaa
1
Dua alasan. Satu, J akan selalu menang. Jadi saya ingin menormalkan sedikit berdasarkan bahasa. Juga, saya lebih suka jawaban ini karena tidak menderita masalah yang sama dengan jawaban hanya jarak di mana angka-angka lain (diakui, hanya yang tidak rasional) memberikan positif palsu.
Keith Randall
5
@Keith Randall - Kutipan dari pertanyaan: "Poin akan memiliki koordinat integral" "Kode terpendek menang.". Tidak apa-apa jika Anda memilih kriteria yang berbeda untuk memilih jawaban, bahkan kriteria subjektif, tetapi kemudian Anda harus menyatakannya dalam pertanyaan.
aaaaaaaaaaaa
13

J, 28 17 25 27

J tidak benar-benar memiliki fungsi, tetapi inilah kata kerja monadik yang mengambil vektor titik dari bidang kompleks:

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

Metode adalah campuran dari Michael Spencer (bekerja hanya pada panjang antar-simpul; tetapi dia saat ini gagal rhombus2 saya) dan karya Eelvex (periksa ukuran set). Membaca dari kanan ke kiri:

  • -/~ hitung semua perbedaan poin
  • , meratakan
  • | ekstrak besarnya
  • /:~ memilah
  • #/.~ nub dan hitung
  • 4 8 4 -:harus memiliki 4 equidistant (pada 0), 8 sedikit lebih besar (panjang 1, sisi), 4 lebih besar lagi (panjang sqrt 2, diagonal)

Demonstrasi:

   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

Demi ingatan, metode saya sebelumnya (diperlukan simpul yang dipesan, tetapi dapat mendeteksi poligon reguler dari pesanan apa pun):

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

Lihat riwayat untuk penjelasan dan demo. Metode saat ini mungkin dapat diperluas ke poligon lain, yang 4 8 4memang terlihat banyak seperti distribusi binomial.

JB
sumber
Bisakah Anda menautkan ke bahasa ini?
Sargun Dhillon
1
@gnibbler: Kenapa tidak? Saya cukup yakin.
Eelvex
1
Sebenarnya, sosok non-kuadrat yang memenuhi kondisi yang Anda periksa memang ada, segitiga biasa plus satu titik panjang sisi dari ujung segitiga yang ditempatkan pada median yang diperpanjang. Tapi pertanyaannya adalah input integer, jadi saya kira solusinya ok.
aaaaaaaaaaaa
1
Ah, baiklah. Saya sedang memikirkan segitiga sama sisi dengan titik ke-4 menjadi pusatnya, tetapi itu dikesampingkan oleh koordinat bilangan bulat
gnibbler
1
Anda dapat memotong 3 karakter dengan mengubahnya ke definisi eksplisit: 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

Perbarui 1) untuk memerlukan 4 poin berbeda (sebelumnya akan memberikan positif palsu untuk poin berulang - apakah ada yang lain?) 2) untuk mendefinisikan fungsi per spec

Untuk bujur sangkar, vektor antara dua titik harus 0 (titik yang sama), sisi, atau diagonal. Jadi, himpunan besarnya vektor-vektor ini harus memiliki panjang 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
sumber
Saya pikir pertanyaannya secara eksplisit menyatakan daftar poin, dan bukan vektor.
Sargun Dhillon
Positif palsu.
aaaaaaaaaaaa
1
Jadi (0 + 0j, 0 + 0j, 1 + 0j, 0 + 1j) adalah kotak?
mhagger
Belah ketupat 2 saya bukan 1 +/- 60j, ini lebih seperti exp (i j pi / 3) untuk nilai dari -1, 0, 1. Perhatikan bahwa seperti yang ditunjukkan eBusiness, mereka tidak dapat semuanya menjadi integral, jadi tidak benar-benar dalam ruang lingkup pertanyaan.
JB
3

Haskell, 100 karakter

Inilah cara saya menulis solusi JB's di Haskell. Dengan tidak ada upaya untuk merusak keterbacaan dengan menghapus karakter yang tidak penting, ini tentang 132 karakter:

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]

Anda dapat mengikisnya sedikit hingga 100 dengan menghapus ruang berlebih dan mengganti nama beberapa hal

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]

Mari kita gunakan QuickCheck untuk memastikan bahwa ia menerima kuadrat sembarang, dengan satu simpul di (x, y) dan vektor tepi (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)]

Mencoba dalam ghci:

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

Oh benar, kotak kosong tidak dianggap sebagai kotak di sini, jadi kami akan merevisi pengujian kami:

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

Dan mencobanya lagi:

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

sumber
1
Simpan 11 karakter dengan membuka gulungan fungsi d. s l=[4,8,4]==(map length.group.sort)[(x-a)^2+(y-b)^2|(x,y)<-l,(a,b)<-l]
Ray
3

Faktor

Implementasi dalam bahasa pemrograman 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 ;

Dan beberapa tes unit:

[ 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
sumber
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

Jalankan seperti ini:

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

Ayo deobfuscate dan jelaskan sedikit.

Pertama kita mendefinisikan suatu norma:

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

Anda akan melihat bahwa tidak ada panggilan ke sqrt, itu tidak diperlukan di sini.

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

Di sini a, b, c dan d adalah poin. Kami berasumsi bahwa poin-poin ini ditata seperti ini:

a - b
| / |
c - d

Jika kita memiliki kotak maka semua syarat ini harus berlaku:

  • abc adalah segitiga siku-siku
  • bcd adalah segitiga siku-siku
  • sisi yang lebih kecil dari setiap segitiga siku-siku memiliki norma yang sama

Perhatikan bahwa yang berikut ini selalu berlaku:

is_square_with_fixed_layout r s t u = is_square_with_fixed_layout r t s u

Kami akan menggunakannya untuk menyederhanakan fungsi pengujian kami di bawah ini.

Karena input kami tidak dipesan, kami juga harus memeriksa semua permutasi. Tanpa kehilangan sifat umum kita dapat menghindari permutasi pada poin pertama:

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

Setelah penyederhanaan:

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

Sunting: mengikuti saran M.Giovannini.

bltxd
sumber
Bagus. Kami belum melihat banyak OCaml di sini :)
Eelvex
Gunakan operator bukan nuntuk pengurangan 20 karakter: 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)

Poin diwakili oleh (x,y)tupel. Poin bisa dalam urutan apa pun dan hanya menerima kotak. Membuat daftar,, sdari jarak berpasangan (bukan nol) antara titik-titik. Total harus ada 12 jarak, dalam dua kelompok unik.

def f (p): s = filter (Tidak ada, [(xz) ** 2+ (yw) ** 2 untuk x, y dalam p untuk z, w dalam p]); return len (s) == 12 dan len ( set (s)) == 2
Hoa Long Tam
sumber
Anda dapat meninggalkan filter dan memeriksa apakah len set adalah 3. Ini menderita masalah positif palsu yang sama dengan jawaban saya.
gnibbler
>>> f ([(0,0), (0,4), (2,2), (- 2,2)]) = Benar
Sargun Dhillon
2
f([(0,0),(0,4),(2,2),(-2,2)]) adalah persegi
gnibbler
2

Python - 42 karakter

Sepertinya ini peningkatan untuk menggunakan bilangan kompleks untuk poin

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

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

jawaban lama:

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

Poin ditentukan dalam urutan apa pun sebagai daftar, misalnya

A = [(11, 13), (14, 12), (13, 9), (10, 10)]
gnibbler
sumber
>>> 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, itu adalah kasus khusus dari seluruh kelas input yang tidak berfungsi. Saya mencoba memikirkan perbaikan yang tidak menghilangkan ukuran jawabannya. Sementara itu, bisakah menghitung kelas umum kasus gagal?
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
@ Kargun: contoh itu adalah kotak.
Keith Randall
untuk menghilangkan duplikasi poin, Anda dapat menambahkan -set ([0])
Keith Randall
2

C # - tidak terlalu pendek. LINQ yang menyalahgunakan. Memilih dua kombinasi titik yang berbeda dalam input, menghitung jaraknya, lalu memverifikasi bahwa empat di antaranya sama dan hanya ada satu nilai jarak berbeda. Point adalah kelas dengan dua anggota ganda, X dan Y. Bisa dengan mudah menjadi Tuple, tapi 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
sumber
2

PHP, 82 karakter


//$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
sumber
Tetapi hanya karena kotak pembatas berbentuk bujur sangkar tidak berarti titik-titiknya terletak pada bujur sangkar. Kondisi yang diperlukan tetapi tidak cukup. Pertimbangkan (0,0), (5,5), (10,0), (0, -5). Bounding box berbentuk bujur sangkar (0:10, -5: 5); angka tidak.
Floris
2

K - 33

Terjemahan dari solusi J oleh JB :

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

K menderita di sini dari kata-kata yang dicadangkan ( _sqrdan _sqrt).

Pengujian:

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

Baterai OCaml +, 132 karakter

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

(lihat, Bu, tidak ada spasi!) Pemahaman daftar di q bentuk daftar norma kuadrat untuk setiap pasangan poin unordered berbeda. Sebuah bujur sangkar memiliki empat sisi yang sama dan dua diagonal yang sama, panjang kuadrat dari yang terakhir menjadi dua kali panjang kuadrat dari yang pertama. Karena tidak ada segitiga sama sisi dalam kisi integer tes tidak benar-benar diperlukan, tapi saya memasukkannya untuk kelengkapan.

Tes:

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

Mathematica 65 80 69 66

Memeriksa bahwa jumlah jarak antar-titik yang berbeda (tidak termasuk jarak dari satu titik ke titik itu sendiri) adalah 2 dan yang lebih pendek dari keduanya bukan 0.

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

Pemakaian

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

Benar
Benar
Benar
Salah
Salah
Salah
Salah

NB: \[And] adalah karakter tunggal dalam Mathematica.

DavidC
sumber
1
Apakah Anda memberi tahu saya bahwa Mathematica tidak memiliki fungsi IsSquare bawaan?
goodguy
2

Jeli , 8 byte

_Æm×ıḟƊṆ

Cobalah online!

Mengambil daftar bilangan kompleks sebagai argumen baris perintah. Cetakan 1atau 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.

Ini sepertinya tantangan yang menyenangkan untuk dihidupkan kembali!

Lynn
sumber
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

Upaya pertama yang naif. Periksa dua kondisi berikut untuk semua permutasi dari daftar input poin (di mana permutasi yang diberikan mewakili, katakanlah, urutan searah jarum jam dari poin-poin):

  • semua sudut 90 derajat
  • semua sisi memiliki panjang yang sama

Kode dan tes yang didobobus

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

Scala (146 karakter)

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

JavaScript 144 karakter

Secara matematis sama dengan jawaban J Bs. Ini menghasilkan 6 panjang dan menyatakan bahwa 2 terbesar adalah sama dan bahwa 4 terkecil sama. Input harus berupa array 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])
}
aaaaaaaaaaaa
sumber
1

PHP, 161 158 karakter

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

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

Ini didasarkan pada jawaban JavaScript eBuisness .

Kevin Brown
sumber
Agak tidak jelas dari pernyataan masalah bahwa poin akan datang di pesan. Saya akan bertanya.
JB
1
Saya tidak berpikir ini akan menangani banyak kasus. Misalnya, itu akan salah memberi label pada belah ketupat sebagai kotak.
Keith Randall
Diperbarui ini untuk mencocokkan dengan salah satu jawaban JavaScript, harus menangani semua kasus.
Kevin Brown
1

JavaScript 1.8, 112 karakter

Pembaruan: menyimpan 2 karakter dengan melipatgandakan pemahaman 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))

Implementasi lain dari jawaban JB. Mengeksploitasi fitur JavaScript 1.7 / 1.8 (penutupan ekspresi, pemahaman array, tugas penataan). Juga penyalahgunaan ~~(bitwise bukan operator) untuk memaksa undefinedke numerik, dengan paksaan array-to-string dan regexp untuk memeriksa bahwa jumlah panjangnya adalah[4, 8, 4] (diasumsikan bahwa tepat 4 poin dilewatkan). Penyalahgunaan operator koma adalah trik C kuno yang dikaburkan.

Tes:

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

GoRuby - 66 karakter

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

diperluas:

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

Algoritma yang sama dengan jawaban JB .

Tes seperti:

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

Output trueuntuk true dan blank untuk false

Nemo157
sumber
Belum pernah mendengar tentang GoRuby. Adakah yang resmi ditulis tentang hal itu? stackoverflow.com/questions/63998/hidden-features-of-ruby/…
Jonas Elfström
@Jonas: Saya belum melihat sesuatu yang benar-benar resmi tentang hal itu, posting blog terbaik yang pernah saya lihat adalah yang ini . Saya sebenarnya tidak bisa membuatnya dibangun dan berfungsi tetapi alternatifnya adalah hanya menyalin prelude golf ke folder yang sama dan menjalankan ruby -r ./golf-prelude.rb FILE_TO_RUN.rbdan itu akan bekerja sama persis.
Nemo157
tidak perlu sortsebelumnya group_by. .sort.group_by {...}harus ditulis sebagai.group_by {...}
user102008
1

Python 97 (tanpa poin kompleks)

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

Ini akan mengambil daftar tupel titik dalam [(x, y), (x, y), (x, y), (x, y)] dalam urutan apa pun, dan dapat menangani duplikat, atau jumlah poin yang salah. TIDAK memerlukan poin kompleks seperti jawaban python lainnya.

Anda dapat mengujinya seperti ini:

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)

Ini akan membutuhkan sedikit penjelasan, tetapi gagasan keseluruhan adalah bahwa hanya ada tiga jarak antara titik-titik dalam kotak (Sisi, Diagonal, Nol (titik dibandingkan dengan dirinya sendiri)):

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]))
  • untuk daftar p dari tupel (x, y)
  • Hapus duplikat menggunakan set (p) dan kemudian menguji panjangnya
  • Dapatkan setiap kombinasi poin (a, b dalam p untuk c, d dalam p)
  • Dapatkan daftar jarak dari setiap titik ke setiap titik lainnya
  • Gunakan set untuk memeriksa hanya ada tiga jarak unik - Nol (titik dibandingkan dengan dirinya sendiri) - Panjang sisi - Panjang diagonal

Untuk menyimpan karakter kode saya adalah:

  • menggunakan nama fungsi 1 char
  • menggunakan definisi fungsi 1 baris
  • Alih-alih memeriksa jumlah poin unik adalah 4, saya memeriksa bahwa itu adalah -1 panjang titik yang berbeda (menyimpan == 3 ==)
  • gunakan daftar dan tuple membongkar untuk mendapatkan, b dalam p untuk c, d dalam p, alih-alih menggunakan [0], a [1]
  • menggunakan pow (x, .5) alih-alih memasukkan matematika untuk mendapatkan sqrt (x)
  • tidak menempatkan spasi setelah)
  • tidak menempatkan nol di depan float

Saya khawatir seseorang dapat menemukan test case yang memecahkan ini. Jadi tolong lakukan dan saya akan benar. Misalnya fakta saya hanya memeriksa tiga jarak, bukannya melakukan abs () dan memeriksa panjang sisi dan sisi miring, sepertinya kesalahan.

Pertama kali saya mencoba kode golf. Berbaik hatilah jika aku melanggar aturan rumah.

Jagu
sumber
1

Clojure, 159 karakter.

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

Sunting: Untuk juga menjelaskan sedikit.

  • Pertama, tentukan norma yang pada dasarnya memberi jarak antara dua titik yang diberikan.
  • Kemudian hitung jarak dari titik pertama ke tiga titik lainnya.
  • Urutkan tiga jarak. (Ini memungkinkan urutan poin apa pun.)
  • Dua jarak terpendek harus sama dengan menjadi persegi.
  • Jarak ketiga (terpanjang) harus sama dengan akar kuadrat dari jumlah kuadrat dari jarak pendek dengan teorema Pythagoras.

(Catatan: rooting persegi tidak diperlukan dan karenanya dalam kode yang disimpan di atas.)

Meikel
sumber
1

C #, 107 karakter

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

Di mana poin adalah Daftar Vector3D yang berisi poin.

Menghitung semua jarak yang dikuadratkan di antara semua titik, dan jika ada tepat tiga jenis berbeda (harus 0, beberapa nilai a, dan 2 * a) dan 4 titik berbeda maka titik-titik tersebut membentuk kuadrat.

KAMU
sumber
1

Python, 66

Meningkatkan jawaban kuda kertas dari 76 menjadi 66:

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

Python 2 , 49 byte

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

Cobalah online!

Mengambil daftar empat bilangan kompleks sebagai input. Putar setiap titik 90 derajat di sekitar rata-rata, dan periksa bahwa setiap titik yang dihasilkan ada dalam daftar asli.

Panjang yang sama (meskipun menggunakan Python 3 lebih pendek {*l}).

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

Cobalah online!

Tidak
sumber
Mengapa tidak menggunakan Python 3 jika itu lebih pendek? Juga, jika diizinkan untuk mengembalikan nilai kebenaran / kepalsuan sewenang-wenang dengan Python, ^bisa digunakan sebagai ganti ==.
Joel
@ Joel Python 2 sebagian besar adalah preferensi, dan bahwa ini adalah tantangan yang sangat lama dari 2011 ketika Python 2 cukup banyak diasumsikan golf Python. Dan tantangannya mengatakan untuk mengembalikan benar atau salah, jadi saya terjebak dengan itu. Jika ini diposting hari ini, mungkin akan menentukan keluaran kebenaran / falsey atau salah satu dari dua nilai yang berbeda, dan mungkin bahkan dengan OK untuk menganggapnya secara default.
xnor
1

Bahasa Wolfram (Mathematica) , 32 31 byte

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

Cobalah online!

Mengambil daftar poin yang diwakili oleh bilangan kompleks, menghitung momen pusat kedua dan ketiga, dan memeriksa bahwa keduanya nol.

Tidak golf:

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

atau

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

bukti

Kriteria ini bekerja pada seluruh bidang kompleks, bukan hanya pada bilangan bulat Gaussian .

  1. Pertama, kami mencatat bahwa momen sentral tidak berubah ketika poin diterjemahkan bersama. Untuk satu set poin

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

    semua momen sentral tidak tergantung c(itulah sebabnya mereka disebut sentral ):

    {FreeQ[FullSimplify[CentralMoment[P, 2]], c], FreeQ[FullSimplify[CentralMoment[P, 3]], c]}
    (*    {True, True}    *)
    
  2. Kedua, momen sentral memiliki ketergantungan sederhana pada penskalaan kompleks keseluruhan (penskalaan dan rotasi) dari himpunan titik:

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

    Ini berarti bahwa jika momen pusat adalah nol, maka penskalaan dan / atau memutar himpunan titik akan menjaga momen pusat sama dengan nol.

  3. Ketiga, mari kita buktikan kriteria untuk daftar poin di mana dua poin pertama ditetapkan:

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

    Dalam kondisi apa sajakah bagian nyata dan imajiner dari momen pusat kedua dan ketiga nol?

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

    Semua dari enam solusi ini mewakili kuadrat: masukkan deskripsi gambar di sini Oleh karena itu, satu-satunya cara agar daftar titik dari formulir {0, 1, x[3] + I*y[3], x[4] + I*y[4]}dapat memiliki nol momen pusat kedua dan ketiga adalah ketika empat poin membentuk persegi.

Karena properti terjemahan, rotasi, dan penskalaan yang ditunjukkan dalam poin 1 dan 2, ini berarti bahwa setiap saat momen pusat kedua dan ketiga adalah nol, kami memiliki kotak dalam beberapa kondisi terjemahan / rotasi / penskalaan. ∎

generalisasi

Momen sentral k-th dari n-gon reguler adalah nol jika k tidak dapat dibagi oleh n. Cukup dari kondisi ini harus dikombinasikan untuk membuat kriteria yang cukup untuk mendeteksi n-gon. Untuk kasus n = 4 sudah cukup untuk mendeteksi nol dalam k = 2 dan k = 3; untuk mendeteksi, misalnya, segi enam (n = 6) mungkin perlu untuk memeriksa k = 2,3,4,5 untuk nol. Saya belum membuktikan yang berikut, tetapi curiga bahwa itu akan mendeteksi n-gon biasa:

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

Tantangan kode pada dasarnya adalah kode ini khusus untuk daftar panjang-4.

Roma
sumber
Solusinya terlihat cukup menarik. Bisakah Anda menjelaskan mengapa itu memberikan jawaban yang benar?
Joel
@ Joel saya sudah menambahkan bukti.
Roman
Terima kasih banyak. Akan ideal bahwa mungkin ada penjelasan matematis yang lebih intuitif tentang solusi yang bagus ini.
Joel
@ Joel, saya bisa memberi Anda utas yang mengarahkan saya ke solusi ini. Saya mulai dengan memperhatikan bahwa kotak (sebagai daftar koordinat, bukan bilangan kompleks) memiliki matriks kovarians yang sebanding dengan matriks unit; Namun, kondisi ini tidak cukup (false positive). Momen sentral ketiga harus nol untuk setiap struktur titik simetri. Jadi saya beralih ke representasi kompleks untuk menempatkan kondisi pada momen pusat kedua dan ketiga, dan yang mengejutkan saya ternyata momen pusat kedua adalah nol untuk kuadrat.
Roman
Besar. Terima kasih telah menunjukkan jalan ke solusi ini.
Joel
0

J, 31 29 27 26

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

memeriksa apakah 8 jarak terkecil antara titik adalah sama. memeriksa apakah ada tepat tiga jenis jarak antara titik (nol, panjang sisi dan panjang 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 $ adalah cara menulis array di J.

Eelvex
sumber
Ini gagal dalam tes belah ketupat.
JB
@ JK: Saya salah ketik. Saya mengubah metode itu sekarang.
Eelvex
Eeew ... kamu menggunakan metode yang sama dengan mencuri. Kecuali versi saya lebih pendek: p
JB
@ JK: benarkah? Saya tidak memperhatikan itu. Siapa lagi yang memeriksa (3 == #distances)?
Eelvex
@JB: oic ... beberapa cek untuk kombinasi 2.: - /
Eelvex
0

Smalltalk untuk 106 karakter

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

di mana p adalah kumpulan poin, misalnya

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

Saya pikir matematika itu sehat ...


sumber
Memeriksa 2 produk titik berbeda tidak memotongnya. Poin yang ditempatkan di posisi yang sama dapat menghasilkan false positive.
aaaaaaaaaaaa
0

Mathematica, 123 karakter (tetapi Anda bisa berbuat lebih baik):

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

Di mana 'a' adalah input dalam formulir daftar Mathematica, misalnya: a={{0,0},{3,4},{8,4},{5,0}}

Kuncinya adalah melihat titik produk antara semua vektor dan perhatikan bahwa mereka harus memiliki tepat tiga nilai: 0, x, dan 2 * x untuk beberapa nilai x. Produk titik memeriksa baik tegak lurus DAN panjangnya dalam satu gelombang besar.

Saya tahu ada cara pintas Mathematica yang bisa membuat ini lebih pendek, tapi saya tidak tahu apa itu.

barrycarter
sumber
Saya pikir ini salah juga, tapi saya tidak tahu apa yang dilakukan kode.
aaaaaaaaaaaa
Ini menghitung semua vektor antara 4 titik, mengambil semua produk titik (nilai absolut), dan mengharapkan hasilnya terdiri persis 0, x, 2 * x untuk beberapa nilai x.
barrycarter
Jadi 16 vektor -> 256 titik produk, dan Anda memeriksa bahwa nilainya tinggi 2 kali lebih rendah, tetapi Anda tidak tahu berapa banyak dari setiap nilainya. Apakah itu benar dipahami?
aaaaaaaaaaaa
Ya, itu menggambarkan dengan tepat algoritma saya. Dan sekarang saya pikir Anda benar: Anda bisa membuat skenario di mana ketiga nilai terjadi, tetapi tidak dalam jumlah yang tepat. Tikus Haruskah diperbaiki?
barrycarter
@ barrycarter Anda dapat menyimpan karakter dengan menggunakan Unionalih-alih Sort@DeleteDuplicates. Saya menempatkan 3 baris Anda bersama-sama juga:#[[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" melaporkan 110 karakter. Tidak memeriksa apakah input memiliki 4 elemen.

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

Saya diuji

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
sumber
Perhatikan bahwa di atas tidak pernah mendapatkan jarak dari satu titik ke titik itu sendiri, sehingga keberadaan jarak 0 akan menunjukkan titik yang berulang dalam daftar input, dan ini akan muncul dalam daftar yang diurutkan sebagai k [0, b] jadi 2 * 0 == b akan selalu gagal karena b tidak dapat sama dengan 0.
Chris Kuklewicz