Спиральная последовательность


29

Задний план

Последовательность OEIS A272573 описывает спираль на гексагональной сетке следующим образом:

Начните спираль чисел на гексагональной плитке с начальным шестиугольником как a (1) = 1. a (n) - наименьшее положительное целое число, не равное или ранее смежное с его соседями.

Последовательность начинается

1, 2, 3, 4, 5, 6, 7, 4, 6, 8, 5, 9, 8, 10, 2, 11, ...

Вот иллюстрация спирального узора: введите описание изображения здесь

  • a(11) != 1потому что тогда 3и 1будет смежным в двух местах.
  • a(11) != 2потому что тогда 3и2будет смежным в двух местах.
  • a(11) != 3 потому что тогда 3 было бы прилегающим к себе.
  • a(11) != 4потому что тогда 3и4будет смежным в двух местах.
  • Поэтому a(11) = 5.

Вызов

Задача состоит в том, чтобы написать программу, которая вычисляет A272573 . Это , поэтому выигрывает самый короткий код.


Я не вижу изображение, поскольку оно заблокировано здесь, поэтому, возможно, я что-то упустил, но ваш пример показывает a (11) = 4, но в вашем списке последовательности a (11) равно 5.
Geobits

Просто ошибка - спасибо, что поймали это.
Питер Кейдж

7
Эта последовательность OEIS была представлена ​​вами, по-видимому. Ницца. :)
Арно

какой предел для п? есть ли ограничение по времени?
сентября

5
В ожидании гексагонии ответ ...
Джонатан Аллан

Ответы:


23

JavaScript (ES6),  267 .. 206  199 байт

Возвращает массив, содержащий N

n=>(F=v=>++i<n?F([...v,(A=N[i]=[1,!j++||d+1,j%L?d:(j%=L*6)?++d:L++&&d++].map(k=>N[k=i-k].push(i)&&k),g=k=>v[E='every']((V,x)=>V-k|N[x][E](y=>A[E](z=>v[y]-v[z])))?k:g(-~k))()]):v)([L=1],N=[[i=j=d=0]])

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

Как?

Определения

По соглашению, мы будем называть угловой ячейкой ячейкой, которая имеет только одно ребро, общее с предыдущим слоем спирали, а боковую ячейку - ячейкой, которая имеет два общих ребра с предыдущим слоем. Как предложено Ourous, мы также можем рассматривать их как ячейки порядка 1 и порядка 2 соответственно.

Угловые клетки показаны желтым цветом ниже. Все остальные ячейки являются боковыми (кроме центральной ячейки, которая является частным случаем).

типы клеток

О сотовых соседях

Нам не нужно отслеживать координаты ячеек в сетке. Единственное, что нам нужно знать, это список соседних ячеек для каждой ячейки в спирали в любой момент времени.

На следующих диаграммах соседи в предыдущем слое показаны светлым оттенком, а дополнительные соседи в текущем слое - более темным.

Ячейка имеет 2 соседей среди предыдущих ячеек, если:

  • это первая боковая ячейка нового слоя (например, 8 )
  • или это угловая ячейка, но не последний слой (например, 9 )

2 соседа

Ячейка имеет 3 соседей среди предыдущих ячеек, если:

  • это боковая ячейка, но не первый слой (например, 10 )
  • или это последняя угловая ячейка текущего слоя (например, 19 )

3 соседа

Реализация сотовых соседей

1яNA[N]

1-1

[                    //
  1,                 // the previous cell is always a neighbor of the current cell
  !j++ || d + 1,     // if this is not the first cell of the layer, the cell at -(d + 1)
                     // is a neighbor (otherwise, we insert 1 twice; doing it that way
                     // saves bytes and having duplicate neighbors is not a problem)
  j % L ?            // if this is a side-cell:
    d                //   the cell at -d is a neighbor
  :                  // else (corner-cell):
    (j %= L * 6) ?   //   if this is not the last cell:
      ++d            //     insert the dummy duplicate neighbor at -(d + 1); increment d
    :                //   else (last cell):
      L++ && d++     //     the cell at -d is a neighbor; increment L; increment d
]                    //

В приведенном выше коде:

  • L1
  • J16×L
  • dрасстояние текущей ячейки от ячейки предыдущего слоя. Он увеличивается каждый раз, когда мы проходим через угловую ячейку.

Затем мы обрабатываем map()цикл, который преобразует смещенияК в индексы (я-К) и выдвинуть текущую ячейку в качестве нового соседа для всех соседних ячеек, чтобы обеспечить симметрию соседства.

.map(k =>
  N[k = i - k].push(i) && k
)

Нахождение следующего члена последовательности

Теперь, когда у нас есть актуальный список соседей для всех ячеек, мы можем наконец вычислить следующий член К последовательности, используя другую рекурсивную вспомогательную функцию.

Значение ячейки N хранится в v[N],

( g =                 // g = recursive function taking
  k =>                // the candidate value k
    v.every((V, x) => // for each previous cell of value V at position x, make sure that:
      V - k           //   V is not equal to k
      |               //   OR
      N[x].every(y => //   for each neighbor y of x:
        A.every(z =>  //     for each neighbor z of the current cell:
          v[y] - v[z] //       the value of y is not equal to the value of z
        )             //     end
      )               //   end
    )                 // end
    ?                 // if the above conditions are fulfilled:
      k               //   stop recursion and return k
    :                 // else:
      g(-~k)          //   try again with k + 1
)()                   // initial call to g with k undefined (this will cause V - k to be
                      // evaluated as NaN and force the 1st iteration to fail)

Отличное объяснение. Одно из возможных улучшений: сделать объяснения в блоках кода полностью видимыми без необходимости горизонтальной прокрутки (не имеет значения для гольф-кода). При просмотре в Firefox в первом блоке кода объяснения есть 5 скрытых столбцов, а во втором - 6 скрытых столбцов.
Трихоплакс

@trichoplax Спасибо за ваш комментарий и предложение. Не могли бы вы указать, какую версию Firefox вы используете и на какой платформе? Я всегда стараюсь форматировать блоки объяснения так, чтобы горизонтальная прокрутка не требовалась. Я сейчас на Firefox 65 / Win10 и у меня нет скрытых столбцов.
Арно

Когда я вернусь домой, проверим версию Firefox, но это может быть из-за того, что я на Fedora. Проверим другую ОС и сообщим
trichoplax

1
Кажется, это зависит от ОС. Подниму это на MSE, когда у меня будет возможность собрать некоторые доказательства (если это еще не было)
trichoplax

1
Я поднял это на MSE . Не стесняйтесь редактировать, если кто-то видит другие комбинации ОС / браузера, которые показывают горизонтальные полосы прокрутки.
Трихоплакс

7

Чистый , 284 279 272 262 байта

import StdEnv
l=[0,-1,-1,0,1,1]
c(u,v)(p,q)=(u-p)^2+(v-q)^2<2||(u-p)*(q-v)==1
$[h:t]m=hd[[e: $t[(h,e):m]]\\e<-[1..]|and[e<>j\\(u,v)<-m|c h u,(p,q)<-m|q==v,(i,j)<-m|c p i]]

$(scan(\(a,b)(u,v)=(a-u,b-v))(0,0)[(i,j)\\n<-[1..],i<-[1,1:l]&j<-l,_<-[max(~j<<i)1..n]])[]

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

Создает последовательность навсегда.

Отображение шестиугольника

Большая часть кода идет в сопоставление шестиугольников уникальным образом для (x,y) координаты, поэтому существует единственная простая функция для определения смежности, которая выполняется для всех точечных отображений.

Отображенные точки выглядят так:

              ---
        --- < 2,-2> ---       x-axis ___.X'
  --- < 1,-2> === < 2,-1> ---  /__.X'
< 0,-2> === < 1,-1> === < 2, 0>'
  === < 0,-1> === < 1, 0> ===
<-1,-1> === < 0, 0> === < 1, 1>
  === <-1, 0> === < 0, 1> ===
<-2, 0> === <-1, 1> === < 0, 2>.__
  --- <-2, 1> === <-1, 2> ---  \  'Y.___
        --- <-2, 2> ---       y-axis    'Y.
              ---

Отсюда определение смежности является тривиальным и происходит, когда один из:

  • x1 == x2 а также abs(y1-y2) == 1
  • y1 == y2 а также abs(x1-x2) == 1
  • y1 == y2 - 1 а также x2 == x1 - 1
  • y1 == y2 + 1 а также x2 == x1 + 1
  • x1 == x2 а также y1 == y2

Точка генерации

Обратите внимание, что при прохождении шестиугольника по спирали различия повторяются для каждого слоя n:

  1. n шаги (1,0)
  2. n-1 шаги (1,-1)
  3. n шаги (0,-1)
  4. n шаги (-1,0)
  5. n шаги (-1,1)
  6. n шаги (0,1)

Это генерирует точки в правильном порядке, принимая суммы префиксов этой последовательности:

scan(\(a,b)(u,v)=(a-u,b-v))(0,0)[(i,j)\\n<-[1..],i<-[1,1:l]&j<-l,_<-[max(~j<<i)1..n]]

Объединяя это

Код, который фактически находит последовательность из вопроса, просто:

$[h:t]m=hd[[e: $t[(h,e):m]]\\e<-[1..]|and[e<>j\\(u,v)<-m|c h u,(p,q)<-m|q==v,(i,j)<-m|c p i]]

Который, в свою очередь, в основном фильтрует and[r<>j\\(u,v)<-m|c h u,(p,q)<-m|q==v,(i,j)<-m|c p i]

Этот фильтр получает точки из m(списка уже сопоставленных точек):

  • Игнорирование натуральных чисел, равных любому j
  • Для каждого (i,j)где iрядом сp
  • Для каждого (p,q) где значениеq равноv
  • Для каждого (u,v)места uрядом с текущей точкой
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.