Определите, если 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.