Определите, если 4 точки образуют квадрат


29

Напишите функцию, которая принимает 4 точки на плоскости в качестве входных данных и возвращает true, если 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

Вы можете вернуть либо true, либо false для вырожденного квадрата (0,0),(0,0),(0,0),(0,0)


Мы говорим о 3D точках здесь, верно?
— gnibbler

3
@gnibbler «включено в плоскости» часть вопроса сделать 3D очков вряд ли .
— JB

Очки приведены в порядке?
— JB

@JB, я думал, что это означало, что точки были на плоскости, но я почему-то визуализировал плоскость в трехмерном пространстве :)
— gnibbler

1
@eBusiness: -1, что вы дали 11 голосов: 7 из них не работают.
— Eelvex

Ответы:


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) выполнить итерацию по четырем направлениям напрямую "для i in (1,1j, -1, -1j)" 4) не нужно указывать [] в аргументе set.
— Кит Рэндалл

Спасибо Кит. (Я пропустил (3), поскольку он имеет ту же длину, что и мой код)
— paperhorse

2
@ Кит Рэндалл - Почему это было принято, когда у JB есть более короткое решение?
— аааааааааааа

1
Две причины. Во-первых, Джей всегда победит. Поэтому мне нравится немного нормализовать язык. Кроме того, мне больше нравится этот ответ, потому что он не страдает от той же проблемы, что и ответы только на расстоянии, где другие цифры (правда, только иррациональные) дают ложные срабатывания.
— Кит Рэндалл

5
@Keith Randall - Цитаты из вопроса: «Точки будут иметь целочисленные координаты», «Кратчайший код выигрывает». Совершенно хорошо, если вы выбираете разные критерии для выбора ответа, даже субъективные критерии, но тогда вы должны указать это в вопросе.
— аааааааааааа

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: почему бы и нет? Я уверен, что это так.
— Eelvex

1
На самом деле существует неквадратная фигура, которая удовлетворяет условиям, которые вы проверяете, - правильный треугольник плюс одна точка на одной стороне от кончика треугольника, расположенного на расширенной медиане. Но вопрос требует целочисленного ввода, поэтому я думаю, что решение в порядке.
— аааааааааааа

1
Ах хорошо. Я думал о равносторонних треугольниках с 4-ой точкой, являющейся центром, но это исключено целочисленными координатами
— gnibbler

1
Вы можете сократить 3 символа, изменив его на явное определение: 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

Обновление 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)

Я думаю, что в вопросе четко указан список точек, а не вектор.
— Саргун Диллон

Ложные срабатывания.
— аааааааааааа

1
Итак, (0 + 0j, 0 + 0j, 1 + 0j, 0 + 1j) это квадрат?
— Mhagger

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

3

Хаскель, 100 знаков

Вот как я бы написал решение JB для J на ​​Хаскеле. Без попыток повредить читаемости, удалив несущественные символы, это около 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

Python (105)

Точки представлены (x,y)кортежами. Очки могут быть в любом порядке и принимает только квадраты. Создает список sпарных (ненулевых) расстояний между точками. Всего должно быть 12 дистанций в двух уникальных группах.

def f (p): s = фильтр (Нет, [(xz) ** 2+ (yw) ** 2 для x, y в p для z, w в p]); return len (s) == 12and len ( набор (ы)) == 2

Вы можете пропустить фильтр и проверить, равно ли длина набора 3. Это страдает от той же самой ложной положительной проблемы, что и мой ответ.
— Гнибблер

>>> f ([(0,0), (0,4), (2,2), (- 2,2)]) = True
— Саргун Диллон

2
f([(0,0),(0,4),(2,2),(-2,2)]) это квадрат
— gnibbler

2

Python - 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])
— Кит Рэндалл

2

C # - не совсем короткий. Злоупотребление LINQ. Выбирает различные две комбинации точек на входе, вычисляет их расстояния, а затем проверяет, что ровно четыре из них равны и что существует только одно другое отдельное значение расстояния. Point - это класс с двумя двойными членами, X и Y. Может быть, это просто Tuple, но не так.

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}

К страдает здесь от своих зарезервированных слов (_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

Mathematica 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

Скала (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 длин и утверждает, что 2 самых больших равны и что 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

Это основано на ответе eBuisness на JavaScript .


Из постановки задачи немного неясно, какие пункты будут упорядочены. Я пойду спросить.
— 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 точки). Злоупотребление оператором запятой - это старый запутанный трюк на Си.

тесты:

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/...
— Йонас Эльфстрем

@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)] в любом порядке и может обрабатывать дубликаты или неверное количество точек. Это НЕ требует сложных точек, как и другие ответы Python.

Вы можете проверить это так:

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)

Это потребует небольшого объяснения, но общая идея заключается в том, что между точками в квадрате есть только три расстояния (сторона, диагональ, ноль (точка по сравнению с самим собой)):

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 символом
  • используя 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 разрешено возвращать произвольные значения истинности / ложности, ^можно использовать вместо ==.
— Джоэл

@Joel Python 2 - это, в основном, предпочтение, и это действительно старая проблема с 2011 года, когда Python 2 в значительной степени предполагал игру в гольф на Python. И задача говорит, чтобы вернуть истину или ложь, поэтому я застрял с этим. Если бы это было опубликовано сегодня, это, вероятно, указывало бы на вывод truey / falsey или одного из двух различных значений, и это могло бы даже OK, чтобы принять это по умолчанию.
— xnor

1

Wolfram Language (Mathematica) , 32 31 байт

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

Попробуйте онлайн!

Принимает список точек, представленных комплексными числами, вычисляет второй и третий центральный момент и проверяет, что оба равны нулю.

Un-golfed:

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

    Все эти шесть решений представляют собой квадраты. введите описание изображения здесь Следовательно, единственный способ, чтобы список точек формы {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.


Решение выглядит довольно интересно. Не могли бы вы объяснить, почему он дает правильный ответ?
— Джоэл

@ Джоэл, я добавил доказательство.
— Роман

Большое спасибо. Было бы идеально, если бы у этого красивого решения было более понятное математическое объяснение.
— Джоэл

@ Джоэл, я могу дать вам ветку, которая привела меня к этому решению. Я начал с того, что заметил, что квадраты (в виде списков координат, а не комплексных чисел) имеют ковариационную матрицу, которая пропорциональна единичной матрице; Однако это условие не является достаточным (ложные срабатывания). Третий центральный момент должен быть нулевым для любой структуры точечной симметрии. Поэтому я переключился на сложное представление, чтобы поместить условие во второй и третий центральные моменты, и, к моему удивлению, оказалось, что второй центральный момент равен нулю для квадратов.
— Роман

Отлично. Спасибо за указание пути к этому решению.
— Джоэл

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 $ это способ записи массива в J.


Это не проходит тест ромба.
— JB

@JB: у меня была опечатка. Я изменил метод в любом случае сейчас.
— Eelvex

Э-э-э ... ты используешь тот же метод, что и я. За исключением моей версии короче: р
— JB

@JB: правда? Я этого не заметил. Кто еще проверяет (3 == # расстояния)?
— Eelvex

@JB: oic ... некоторые проверки комбинаций 2.: - /
— Eelvex

0

Smalltalk на 106 персонажей

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

где p - набор точек, например

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

Я думаю, что математика это звук ...


Проверка на наличие двух разных точечных продуктов не снижает это. Точки, расположенные в одной и той же позиции, могут давать ложные срабатывания.
— аааааааааааа

0

Mathematica, 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, которые могут сделать это короче, но я не знаю, что это такое.


Я думаю, что это тоже неправильно, но я не могу понять, что делает код.
— аааааааааааа

Он вычисляет все векторы между четырьмя точками, берет все точечные произведения (абсолютное значение) и ожидает, что результат будет точно равен 0, x, 2 * x для некоторого значения x.
— Баррикартер

Итак, 16 векторов -> 256-точечные произведения, и вы проверяете, что высокое значение в 2 раза меньше низкого, но вы не знаете, сколько есть каждого значения. Это правильно поняли?
— аааааааааааа

Да, это правильно описывает мой алгоритм. И теперь я думаю, что вы правы: вы могли бы построить сценарий, в котором встречались бы все 3 значения, но не в нужном количестве. Крысы. Должно быть исправимо, хотя?
— Баррикартер

@barrycarter Вы можете сохранять символы, используя Unionвместо Sort@DeleteDuplicates. Я также собрал ваши 3 строки:#[[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" сообщает 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.
— Крис Куклевич
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.