Спіральна послідовність


29

Фон

Послідовність OEIS A272573 описує спіраль на шестикутній сітці наступним чином:

Запустіть спіраль чисел на шестикутну плитку, при цьому початковий шестикутник як (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 . Це , тому найкоротший код виграє.


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

Просто помилка - спасибі за те, що ви її зробили.
Пітер Кагей

7
Цю послідовність OEIS, мабуть, подав сам. Приємно. :)
Арнольд

яка межа для n? чи існує обмеження часу?
Сетоп

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

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

Як?

Визначення

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

Кутові клітини зображені внизу жовтим кольором. Усі інші клітини є бічними клітинами (за винятком центральної клітини, яка є окремим випадком).

типи клітин

Про сусідів по клітинках

Нам дійсно не потрібно стежити за координатами комірок у сітці. Єдине, що нам потрібно знати, - це перелік сусідніх клітин для кожної комірки в спіралі в будь-який момент часу.

На наступних діаграмах сусіди попереднього шару відображаються у світлому відтінку, а додаткові сусіди у поточному шарі - у більш темному.

У комірці є 2 сусіди серед попередніх комірок, якщо:

  • це перша бічна клітина нового шару (наприклад, 8 )
  • або це кутова клітина, але не остання з шару (як 9 )

2 сусіди

У комірці є три сусіди серед попередніх комірок, якщо:

  • це бічна комірка, але не перша з шару (як 10 )
  • або це остання кутова клітина поточного шару (наприклад, 19 )

3 сусіди

Реалізація клітинних сусідів

1iнА[н]

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
  • г

map()кi-к

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

Знаходження наступного члена послідовності

к

нv[н]

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