Una sequenza a spirale


29

sfondo

La sequenza OEIS A272573 descrive una spirale su una griglia esagonale come segue:

Inizia una spirale di numeri su una piastrellatura esagonale, con l'esagono iniziale come a (1) = 1. a (n) è il numero intero positivo più piccolo non uguale o precedentemente adiacente ai suoi vicini.

La sequenza ha inizio

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

Ecco un'illustrazione del modello a spirale: inserisci qui la descrizione dell'immagine

  • a(11) != 1perché allora 3e 1sarebbe adiacente in due posti.
  • a(11) != 2perché allora 3e 2sarebbe adiacente in due posti.
  • a(11) != 3perché allora 3sarebbe adiacente a se stesso.
  • a(11) != 4perché allora 3e4sarebbe adiacente in due posti.
  • Pertanto a(11) = 5.

Sfida

La sfida è scrivere un programma che calcola A272573 . Questo è , quindi vince il codice più corto.


Non riesco a vedere l'immagine perché è bloccata qui, quindi forse mi manca qualcosa, ma il tuo esempio mostra un (11) = 4, ma nell'elenco delle sequenze un (11) è 5.
Geobits

Solo un errore, grazie per averlo colto.
Peter Kagey,

7
Questa sequenza OEIS è stata presentata da te, a quanto pare. Bello. :)
Arnauld,

qual è il limite per n? C'è un limite di tempo ?
Setop,

5
In attesa di risposta esagonica ...
Jonathan Allan il

Risposte:


23

JavaScript (ES6),  267 .. 206  199 byte

Restituisce un array contenente gli N primi termini della sequenza.

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

Provalo online!

Come?

definizioni

Per convenzione, chiameremo angolo-cella una cella che ha solo un bordo in comune con il livello precedente della spirale e cella-laterale una cella che ha due bordi in comune con il livello precedente. Come suggerito da Ourous, possiamo anche pensarli rispettivamente come celle ordine-1 e celle ordine-2.

Le celle angolari sono mostrate in giallo sotto. Tutte le altre celle sono celle laterali (tranne la cella centrale che è un caso speciale).

tipi di cellule

Informazioni sui vicini di cella

Non abbiamo davvero bisogno di tenere traccia delle coordinate delle celle sulla griglia. L'unica cosa che dobbiamo sapere è l'elenco delle celle vicine per ogni cella della spirale in un dato momento.

Nei seguenti diagrammi, i vicini nel livello precedente sono mostrati in ombra chiara e i vicini aggiuntivi nel livello corrente in ombra più scura.

Una cella ha 2 vicini tra le celle precedenti se:

  • è la prima cella laterale di un nuovo livello (come 8 )
  • o è una cella d'angolo, ma non l'ultima del livello (come 9 )

2 vicini

Una cella ha 3 vicini tra le celle precedenti se:

  • è una cella laterale, ma non la prima del livello (come 10 )
  • o è l'ultima cella d'angolo del livello corrente (come 19 )

3 vicini

Implementazione dei vicini cellulari

1ionUN[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
]                    //

Nel codice sopra:

  • L1
  • j16×L
  • d

map()Kio-K

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

Trovare il prossimo termine della sequenza

K

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

Ottima spiegazione Un possibile miglioramento: rendere le spiegazioni nei blocchi di codice completamente visibili senza la necessità di scorrimento orizzontale (non importa per il codice golfizzato). Visualizzando in Firefox, ci sono 5 colonne nascoste nel primo blocco di codice esplicativo e 6 colonne nascoste nel secondo.
trichoplax,

@trichoplax Grazie per il tuo commento e suggerimento. Potresti specificare quale versione di Firefox stai utilizzando e su quale piattaforma? Cerco sempre di formattare i blocchi di spiegazioni in modo che non sia necessario lo scorrimento orizzontale. Sono su Firefox 65 / Win10 in questo momento e non ho colonne nascoste.
Arnauld,

Controllerò la versione di Firefox quando torno a casa, ma potrebbe essere perché sono su Fedora.
Verificherà

1
Sembra variare a seconda del sistema operativo. Aumenterà questo su MSE quando avrò avuto la possibilità di raccogliere alcune prove (se non è già stato)
trichoplax

1
L'ho sollevato su MSE . Sentiti libero di modificare se qualcuno vede altre combinazioni OS / browser che mostrano barre di scorrimento orizzontali.
trichoplax,

7

Clean , 284 279 272 262 byte

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

Provalo online!

Genera la sequenza per sempre.

Mappatura esagonale

La maggior parte del codice va a mappare gli esagoni in modo univoco (x,y) coordinate in modo che vi sia un'unica, semplice funzione per determinare l'adiacenza che vale per tutte le mappature dei punti.

I punti mappati si presentano così:

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

Da lì, determinare l'adiacenza è banale e si verifica quando uno di:

  • x1 == x2 e abs(y1-y2) == 1
  • y1 == y2 e abs(x1-x2) == 1
  • y1 == y2 - 1 e x2 == x1 - 1
  • y1 == y2 + 1 e x2 == x1 + 1
  • x1 == x2 e y1 == y2

Generazione punti

Si noti che quando si attraversa l'esagono in una spirale le differenze si ripetono per ogni strato n:

  1. n passaggi di (1,0)
  2. n-1 passaggi di (1,-1)
  3. n passaggi di (0,-1)
  4. n passaggi di (-1,0)
  5. n passaggi di (-1,1)
  6. n passaggi di (0,1)

Questo genera i punti nel giusto ordine prendendo somme di prefissi di questa sequenza:

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

Metterlo insieme

Il codice che trova effettivamente la sequenza dalla domanda è solo:

$[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]]

Che a sua volta sta filtrando principalmente per and[r<>j\\(u,v)<-m|c h u,(p,q)<-m|q==v,(i,j)<-m|c p i]

Questo filtro prende punti da m(l'elenco dei punti già mappati) da:

  • Ignorando numeri naturali uguali a nessuno j
  • Per ogni (i,j)dove iè adiacentep
  • Per ogni (p,q)dove il valore qè uguale av
  • Per ogni (u,v)dove uè adiacente al punto corrente
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.