Визначте, чи 4 точки утворюють квадрат


29

Напишіть функцію, яка бере 4 точки на площині як вхідну і повертає справжнє, якщо 4 точки утворюють квадрат. Точки матимуть інтегральні координати з абсолютними значеннями <1000.

Ви можете використовувати будь-яке розумне подання 4-х пунктів як вхідних даних. Бали не надаються в певному порядку.

Найкоротший код виграє.

Приклад квадратів:

(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,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

Ви можете повернути справжнє або хибне для виродженого квадрата (0,0),(0,0),(0,0),(0,0)


Ми говоримо тут про 3D-точки, правда?
гніблер

3
@gnibbler частина запитання " в площині" робить 3D бали малоймовірними.
JB

Чи вказуються бали в порядку?
JB

@JB, я думав, що це означає, що точки були на площині, але я чомусь візуалізував площину в 3D-просторі :)
gnibbler

1
@eBusiness: -1, що ви наділили 11 голосів: 7 з них знизилися.
Ельвенкс

Відповіді:


12

Python 176 90 79 байт

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

Функція S приймає список складних чисел як свій вхід (A). Якщо ми знаємо і центр, і один кут квадрата, ми можемо реконструювати квадрат, обертаючи кут на 90,180 та 270 градусів навколо центральної точки (с). На складній площині обертання на 90 градусів щодо початку відбувається шляхом множення точки на i . Якщо наша первісна форма і реконструйований квадрат мають однакові точки, то це, мабуть, був квадрат.


Кілька оптимізацій: 1) використовувати "S" замість "is_square" 2) поставити все це на один рядок, використовуючи; 3) повторіть 4 напрямки безпосередньо "для i в (1,1j, -1, -1j)" 4) не потрібно [] у аргументі встановлення.
Кіт Рендалл

Дякую Кіт. (Я покинув (3), оскільки, схоже, це така ж довжина, як і мій код)
папір для коней

2
@Keith Randall - Чому це було прийнято, коли JB має набагато коротше рішення?
aaaaaaaaaaaa

1
Дві причини. Один, J завжди перемагав. Тому я люблю трохи нормалізувати мову. Крім того, мені подобається ця відповідь, тому що вона не страждає від тієї самої проблеми, що відповіді лише на відстань, де інші фігури (правда, лише ірраціональні) дають помилкові позитиви.
Кіт Рендалл

5
@Keith Randall - Цитати з питання: "Очки матимуть інтегральні координати" "Найкоротший код виграє." Це цілком чудово, якщо ви обираєте різні критерії для вибору відповіді, навіть суб’єктивні критерії, але тоді ви повинні це зазначити у питанні.
aaaaaaaaaaaa

13

J, 28 17 25 27

J насправді не має функцій, але ось монадичне дієслово, яке приймає вектор точок зі складної площини:

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

Метод - це суміш Майкла Спенсера (робота виключно на міжвершинних довжинах; але в даний час він не відповідає моєму ромбу2) і Eelvex (перевірити розміри наборів) працює. Читання справа наліво:

  • -/~ обчислити всі точкові різниці
  • , сплющити
  • | величина вилучення
  • /:~ розібратися
  • #/.~ нуб і рахувати
  • 4 8 4 -:має бути рівно 4 рівновіддалених (на 0), 8 трохи більших (довжина 1, сторони), ще 4 більших (довжина sqrt 2, діагоналі)

Демонстрація:

   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

Для пам’яті мій попередній метод (вимагав упорядкованих вершин, але міг виявляти регулярні багатокутники будь-якого порядку):

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

Дивіться історію для пояснення та демонстрації. Поточний метод, можливо, може бути розширений на інші багатокутники, що 4 8 4схоже на біноміальне розподіл.


Чи можете ви зв’язатись із цією мовою?
Саргун Діллон

1
@gnibbler: Чому ні? Я майже впевнений, що так і є.
Ельвакс

1
Власне, не квадратна фігура, яка відповідає умовам, які ви перевіряєте, існує, звичайний трикутник плюс одна точка довжини сторони від кінчика трикутника, розміщеного на розширеній медіані. Але питання вимагало введення цілого числа, тому я думаю, що рішення нормально.
aaaaaaaaaaaa

1
Ну, тоді добре. Я думав про рівносторонні трикутники з центром 4-ї точки, але це виключено цілими координатами
gnibbler

1
Ви можете вирізати 3 символи, змінивши його на явне визначення: 3 :'4 8 4-:#/.~/:~|,-/~y'
isawdrones

5

Пітона, 71 42

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

Оновлення 1) вимагати 4 різних точок (попередньо давав би помилкові позитиви для повторних точок - чи є інші?) 2) для визначення функції на специфікацію

Для квадрата вектор між будь-якими двома точками повинен бути 0 (однакова точка), сторона або діагональ. Отже, множина величин цих векторів повинна мати довжину 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)

Я думаю, що питання прямо вказав перелік пунктів, а не вектор.
Саргун Діллон

Помилкові позитиви.
aaaaaaaaaaaa

1
Отже (0 + 0j, 0 + 0j, 1 + 0j, 0 + 1j) - квадрат?
mhagger

Мій ромб 2 не 1 +/- 60j, він більше схожий на exp (i j pi / 3) для значень від -1, 0, 1. Зауважте, що, як вказував електронний бізнес, вони не можуть бути цілісними, тому не дуже обсяг питання.
JB

3

Хаскелл, 100 символів

Ось як я написав J-рішення J в Haskell. Не намагаючись пошкодити читабельність, видаляючи несуттєві символи, це приблизно 132 символи:

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]

Ви можете скорегувати його трохи до 100, видаливши зайві пробіли та перейменувавши деякі речі

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]

Давайте скористаємося QuickCheck, щоб переконатися, що він приймає довільні квадрати, з однією вершиною у (x, y) та вектором ребер (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)]

Спробуйте його в ghci:

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

О так, порожній квадрат тут не вважається квадратом, тому ми переглянемо наш тест:

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

І спробуйте ще раз:

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

1
Збережіть 11 знаків, розгорнувши функцію d. s l=[4,8,4]==(map length.group.sort)[(x-a)^2+(y-b)^2|(x,y)<-l,(a,b)<-l]
Рей

3

Фактор

Реалізація мовою програмування 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 ;

І деякі одиничні тести:

[ 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

Бігайте так:

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

Давайте дебфускуємо і пояснимо трохи.

Спочатку визначимо норму:

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

Ви помітите, що немає дзвінка до sqrt, він тут не потрібен.

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

Тут a, b, c і d - точки. Ми припускаємо, що ці точки викладені так:

a - b
| / |
c - d

Якщо у нас квадрат, то всі ці умови повинні виконуватися:

  • abc - це правильний трикутник
  • bcd - це правильний трикутник
  • менші сторони кожного правого трикутника мають однакові норми

Зауважте, що завжди має місце:

is_square_with_fixed_layout r s t u = is_square_with_fixed_layout r t s u

Ми будемо використовувати це для спрощення нашої тестової функції нижче.

Оскільки наше введення не впорядковане, ми також повинні перевірити всі перестановки. Не втрачаючи загальності, ми можемо уникати першої точки:

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

Після спрощення:

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

Редагувати: дотримуючись порад М.Гіованініні.


Приємно. Тут ми не бачили багато OCaml :)
Eelvex

Використовуйте оператор замість nдля скорочення 20 символів: 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.
Матіас Джованніні

2

Пітон (105)

Окуляри представлені (x,y)кортежами. Очки можуть бути в будь-якому порядку і приймають лише квадрати. Створює список sпарних (ненульових) відстаней між точками. Загалом має бути 12 дистанцій у двох унікальних групах.

def f (p): s = фільтр (None, [(xz) ** 2+ (yw) ** 2 for x, y in p for z, w in p]); return len (s) == 12and len ( набір (и)) == 2

Ви можете залишити фільтр і перевірити, чи тривалість набору є 3. Це страждає від тієї ж помилкової позитивної проблеми, що і моя відповідь.
гніблер

>>> f ([(0,0), (0,4), (2,2), (- 2,2)]) = Істинно
Саргун Діллон

2
f([(0,0),(0,4),(2,2),(-2,2)]) - квадрат
гніблер

2

Пітон - 42 символи

Схоже, це вдосконалення використання складних чисел для точок

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

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

стара відповідь:

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

Бали задаються в будь-якому порядку як список, наприклад

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, це особливий випадок цілого класу входів, які не працюють. Я намагаюся придумати виправлення, яке не виверже розмір відповіді. Тим часом, чи може відпрацювати загальний клас несправних справ?
гніблер

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: цей приклад - квадрат.
Кіт Рендалл

щоб позбутися дублюваних очок, ви можете додати -set ([0])
Keith Randall

2

C # - не зовсім короткий. Зловживання LINQ. Вибирає окремі двокомбінаційні точки вхідних даних, обчислює їх відстані, а потім перевіряє, що рівно чотири з них є рівними та чи є лише одне інше чітке значення відстані. Пойнт - клас з двома подвійними членами, X і Y. Легко може бути кортеж, але мех.

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 символи


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

Але те, що обмежувальне поле квадратне, не означає, що точки лежать у квадраті. Необхідна, але недостатня умова. Розглянемо (0,0), (5,5), (10,0), (0, -5). Обв'язувальний ящик квадратний (0:10, -5: 5); цифра ні.
Флоріс,

2

К - 33

Переклад рішення J на ​​JB :

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

K страждає тут від своїх зарезервованих слів (_sqr і_sqrt ).

Тестування:

  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 + батареї, 132 символи

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

(дивись, ма, немає пробілів!) Зрозуміння списку в q формує перелік квадратних норм для кожної окремої невпорядкованої пари точок. Квадрат має чотири рівні сторони і дві рівні діагоналі, довжина квадрата останньої вдвічі більша за довжину квадрата. Оскільки в цілій решітці немає рівносторонніх трикутників, тест насправді не потрібен, але я включаю його для повноти.

Тести:

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

Математика 65 80 69 66

Перевіряє, що кількість чітких міжточкових відстаней (не враховуючи відстань від точки до самої себе) становить 2, а коротша з двох не дорівнює 0.

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

Використання

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

Правда
Правда
Правда
Брехня
Брехня
Брехня
Брехня

NB: \[And]це єдиний символ у Mathematica.


1
Ти мені кажеш, що Mathematica не має вбудованої функції IsSquare?
goodguy

2

Желе , 8 байт

_Æm×ıḟƊṆ

Спробуйте в Інтернеті!

Приймає список складних чисел як аргумент командного рядка. Друкує 1або 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.

Це здається приємним викликом відродження!


1

Хаскелл (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

Наївна перша спроба. Перевіряє наступні дві умови для всіх перестановок вхідного списку точок (де дана перестановка являє собою, скажімо, упорядкування точок за годинниковою стрілкою):

  • всі кути 90 градусів
  • всі сторони однакової довжини

Деобфукований код і тести

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 символів)

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 символів

Математично дорівнює J Bs відповіді. Він породжує 6 довжин і стверджує, що два найбільші рівні і 4 найменші рівні. Вхід повинен бути масивом масивів.

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 символів

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

Доказ (1x1): http://codepad.viper-7.com/ZlBpOB

Це засновано на відповіді JavaScript eBuisness .


З постановки проблеми трохи незрозуміло, які пункти будуть впорядковані. Я піду запитати.
JB

1
Я не думаю, що це буде належним чином вирішувати багато справ. Наприклад, він неправильно позначить ромби як квадрати.
Кіт Рендалл

Оновлено це, щоб відповідати одній з відповідей JavaScript, має обробляти всі випадки.
Кевін Браун

1

JavaScript 1.8, 112 символів

Оновлення: збережено 2 символи, склавши розуміння масиву разом.

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

Ще одна реалізація відповіді JB. Використовує функції JavaScript 1.7 / 1.8 (закриття виразів, розуміння масиву, призначення руйнування). Також зловживає ~~(подвійний біт не оператор), щоб примусити undefinedдо числового, з примусом масиву до рядка і повторним перемиканням, щоб перевірити, чи є підрахунки довжини [4, 8, 4](передбачається, що передано рівно 4 бали). Зловживання оператором комами - стара затеплена C хитрість.

Тести:

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 символів

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

розширено:

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

Той же алгоритм, що і у відповіді JB .

Тест типу:

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

Виходи trueдля істинних та порожніх для помилкових


Ніколи не чув про GoRuby. Чи про це написано щось офіційне? stackoverflow.com/questions/63998/hidden-features-of-ruby / ...
Jónás Elfström

@ Jonas: Я не бачив нічого насправді офіційного про це, найкраща публікація в блозі, яку я бачив, - це ця . Я насправді не зміг її побудувати і працювати, але альтернативою є просто скопіювати прелюдію гольфу в ту саму папку і запустити, ruby -r ./golf-prelude.rb FILE_TO_RUN.rbі вона буде працювати точно так само.
Nemo157

це не потрібно , sortперш group_by. .sort.group_by {...}має бути записано як.group_by {...}
user102008

1

Python 97 (без складних точок)

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

Це займе списки точкових кортежів у [(x, y), (x, y), (x, y), (x, y)] у будь-якому порядку і може обробляти дублікати або неправильну кількість балів. Він НЕ вимагає складних балів, як інші відповіді пітона.

Ви можете перевірити його так:

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)

Це займе трохи пояснення, але загальна ідея полягає в тому, що між точками в квадраті є лише три відстані (Side, Diagonal, Zero (точка порівняно з собою)):

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]))
  • для списку p кортежів (x, y)
  • Видаліть дублікати, використовуючи set (p), а потім протестуйте довжину
  • Отримайте кожну комбінацію точок (a, b в p для c, d у p)
  • Отримайте список відстані від кожної точки до кожної іншої точки
  • Використовуйте для встановлення лише три унікальні відстані - Нуль (точка порівняно з самим собою) - Довжина сторони - Довжина діагоналі

Для збереження кодових символів я:

  • використовуючи ім'я функції 1 char
  • використовуючи визначення функції 1 рядка
  • Замість того, щоб перевіряти кількість унікальних точок 4, я перевіряю, що це -1 різної довжини точок (економить == 3 ==)
  • скористайтеся списком та розпакуванням кортежа, щоб отримати a, b в p для c, d у p, замість того, щоб використовувати [0], a [1]
  • використовує pow (x, .5) замість включення математики для отримання sqrt (x)
  • не ставлячи пробілів після)
  • не ставлячи провідний нуль на поплавок

Я боюся, що хтось може знайти тестовий випадок, який порушує це. Тому, будь ласка, зробіть і неправильно. Наприклад, те, що я просто перевіряю на три відстані, замість того, щоб робити abs () і перевіряти на бічну довжину та гіпотенузу, здається помилкою.

Перший раз я спробував код гольфу. Будьте ласкаві, якщо я порушив будь-які домашні правила.


1

Clojure, 159 символів.

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

Редагувати: щоб також трохи пояснити.

  • Спочатку визначте норму, яка в основному дає відстань між двома заданими точками.
  • Потім обчисліть відстань першої точки до інших трьох балів.
  • Сортуйте три відстані. (Це дозволяє будь-який порядок балів.)
  • Дві найкоротші відстані повинні дорівнювати квадрату.
  • Третя (найдовша) відстань повинна дорівнювати квадратному кореню суми квадратів коротких відстаней за теоремою Піфагора.

(Примітка: укорінення у квадраті не потрібно, а значить, і в коді, збереженому вище.)


1

C #, 107 символів

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

Де бали - Список Vector3D, що містить точки.

Обчислює всі відстані в квадраті між усіма точками, і якщо рівно трьох різних типів (повинно бути 0, деяке значення a і 2 * a) і 4 різних точки, то точки утворюють квадрат.



1

Python 2 , 49 байт

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

Спробуйте в Інтернеті!

Візьме список чотирьох складних чисел як вхідних даних. Обертає кожну точку на 90 градусів приблизно від середньої величини та перевіряє, чи є кожна отримана точка у вихідному списку.

Та ж довжина (хоча і коротша у використанні Python 3 {*l}).

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

Спробуйте в Інтернеті!


Чому б не використовувати Python 3, якщо він коротший? Крім того, якщо в Python дозволено повертати довільні значення truthy / falesy, ^можна використовувати замість ==.
Джоель

@Joel Python 2 є переважно перевагою, і що це справді старе завдання з 2011 року, коли Python 2 в значній мірі вважав, що Python гольфу. І виклик говорить повернути правду чи хибність, тому я дотримувався цього. Якби це було розміщено сьогодні, воно, ймовірно, вказало б виведення truthy / falsey або одне з двох різних значень, і навіть OK може вважати це за замовчуванням.
xnor

1

Мова Вольфрама (Mathematica) , 32 31 байт

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

Спробуйте в Інтернеті!

Бере перелік точок, представлених складними числами, обчислює другий і третій центральний момент і перевіряє, що обоє дорівнюють нулю.

Без гольфу:

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

або

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

доказ

Цей критерій працює на всій складній площині, а не лише на цілі числа Гаусса .

  1. Спочатку зазначимо, що центральні моменти не змінюються, коли бали переводяться разом. Для набору балів

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

    всі центральні моменти не залежать від c(тому їх називають центральними ):

    {FreeQ[FullSimplify[CentralMoment[P, 2]], c], FreeQ[FullSimplify[CentralMoment[P, 3]], c]}
    (*    {True, True}    *)
    
  2. По-друге, центральні моменти мають просту залежність від загального комплексного масштабування (масштабування та обертання) безлічі точок:

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

    Це означає, що якщо центральний момент дорівнює нулю, то масштабування та / або обертання набору точок збереже центральний момент рівним нулю.

  3. По-третє, докажемо критерій для списку балів, де зафіксовані перші два бали:

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

    За яких умов нульова реальна та уявна частини другого та третього центральних моментів?

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

    Усі ці шість розв'язків представляють квадрати. enter image description here Тому єдиний спосіб, коли список точок форми {0, 1, x[3] + I*y[3], x[4] + I*y[4]}може мати нульовий другий та третій центральні моменти, - це коли чотири точки утворюють квадрат.

Завдяки властивостям перекладу, обертання та масштабування, продемонстрованих у пунктах 1 та 2, це означає, що будь-коли другий та третій центральні моменти дорівнюють нулю, у нас є квадрат у деякому стані перекладу / обертання / масштабування. ∎

узагальнення

K-й центральний момент звичайного n-гона дорівнює нулю, якщо k не ділиться на n. Достатньо цих умов необхідно поєднувати, щоб скласти достатній критерій для виявлення n-гонів. Для випадку n = 4 досить було виявити нулі в k = 2 і k = 3; для виявлення, наприклад, шестикутників (n = 6), можливо, буде потрібно перевірити k = 2,3,4,5 на нулі. Я не довів наступного, але підозрюю, що він виявить будь-який регулярний n-gon:

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

Виклик коду по суті є цим кодом, спеціалізованим для списків довжиною-4.


Рішення виглядає досить цікаво. Чи можете ви пояснити, чому це дає правильну відповідь?
Джоель

@Joel Я додав доказ.
Роман

Дуже дякую. Ідеально було б, щоб було більш інтуїтивне математичне пояснення цього приємного рішення.
Джоель

@Joel Я можу дати вам тему, яка привела мене до цього рішення. Я почав із зауваження, що квадрати (як списки координат, а не складні числа) мають коваріаційну матрицю , пропорційну одиничній матриці; однак ця умова недостатня (помилкові позитиви). Третій центральний момент повинен дорівнювати нулю для будь-якої структури точкової симетрії. Тож я перейшов до складного подання, щоб поставити умову на другий та третій центральні моменти, і на мій подив виявилось, що другий центральний момент дорівнює нулю для квадратів.
Роман

Чудово. Дякуємо, що показали шлях до цього рішення.
Джоель

0

J, 31 29 27 26

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

перевіряє, чи 8 найменших відстаней між точками однакові. перевіряє, чи є між точками рівно три види відстаней (нуль, довжина сторони та довжина діагоналі).

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 $ - це спосіб запису масиву в Дж.


Це не відповідає тесту на ромб.
JB

@JB: У мене був помилка друку. Я все-таки змінив метод.
Ельвакс

Eeew ... ти використовуєш той самий метод, який я вкрав. За винятком коротшої моєї версії: p
JB

@JB: справді? Я цього не помічав. Хто ще перевіряє (3 == # відстань)?
Ельвакс

@JB: oic ... дещо перевіряємо на комбінації 2.: - /
Eelvex

0

Маленька розмова на 106 символів

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

де р - це сукупність точок, наприклад

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

Я думаю, що математика є здоровою ...


Перевірка для двох різних точкових продуктів не вирішує це. Точки, розміщені в одному положенні, можуть видавати помилкові позитиви.
aaaaaaaaaaaa

0

Математика, 123 символи (але ви можете зробити краще):

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

Де "a" - це вхід у формі списку Mathematica, наприклад: a={{0,0},{3,4},{8,4},{5,0}}

Ключ - подивитися на крапку продуктів між усіма векторами та зауважте, що вони повинні мати рівно три значення: 0, x та 2 * x для деякого значення x. Точковий виріб перевіряє як перпендикулярність, так і довжину в одній навороті.

Я знаю, що є ярлики Mathematica, які можуть скоротити це, але я не знаю, що вони є.


Я думаю, що і цей помиляється, але я не можу зрозуміти, що робить код.
aaaaaaaaaaaa

Він обчислює всі вектори між 4 балами, приймає всі крапки добутку (абсолютне значення) і очікує, що результат складається точно з 0, x, 2 * x для деякого значення x.
barrycarter

Отже, 16 векторів -> 256 точкових продуктів, і ви перевіряєте, що високе значення в 2 рази нижче, але ви не знаєте, скільки є кожного значення. Це правильно зрозуміло?
aaaaaaaaaaaa

Так, це правильно описує мій алгоритм. І я зараз думаю, що ти маєш рацію: ти міг побудувати сценарій, коли всі три значення мали місце, але не в потрібній кількості. Щури Чи має бути виправданим?
barrycarter

@barrycarter Можна зберегти символи, використовуючи Unionзамість них Sort@DeleteDuplicates. Я також #[[1]] == 0 && #[[3]]/#[[2]] == 2 &[ Union@Abs@Flatten[Table[c.d, {c, #}, {d, #}]] &[ Flatten[Table[x - y, {x, a}, {y, a}], 1]]]
поєднав

0

Haskell, "wc -c" повідомляє про 110 символів. Не перевіряє, чи є на вході 4 елементи.

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

Я тестував на

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

Зауважимо, що вищезазначене ніколи не отримує відстань від точки до себе, тому наявність відстані 0 означатиме повторну точку у вхідному списку, і це відображатиметься у відсортованому списку як k [0, b], так 2 * 0 == b завжди буде невдалим, оскільки b не може бути таким, як 0.
Chris Kuklewicz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.