Elettroni che rimbalzano in un filo


46

Immagina un "filo" che ha nspazi. Immagina inoltre che ci siano "elettroni" in quel filo. Questi elettroni vivono solo per un'unità di tempo. Qualsiasi spazio nel filo adiacente esattamente a un elettrone diventa un elettrone. Nella terminologia di Game of Life, questo è B1/S.

Ad esempio, questo è un filo di lunghezza 10, con periodo 62.

inserisci qui la descrizione dell'immagine

Regole

  • Input,, nè un singolo numero intero positivo.
  • L'output deve essere un singolo numero intero che indica il periodo di un filo di lunghezza n.
  • Lo stato iniziale è un singolo elettrone ad un'estremità del filo.
  • Il periodo non include necessariamente lo stato iniziale. Alcune lunghezze non ritornano mai allo stato iniziale, ma tutte periodiche.
  • Un filo statico (cioè uno senza elettroni) ha il periodo 1.
  • Le condizioni al contorno non sono periodiche. Cioè, il filo non è toroidale in alcun modo.

Casi test

Un ringraziamento speciale a orlp per aver prodotto questo elenco. (L'ho verificato fino a n = 27.)

1 1
2 2
3 1
4 6
5 4
6 14
7 1
8 14
9 12
10 62
11 8
12 126
13 28
14 30
15 1
16 30
17 28
18 1022
19 24
20 126
21 124
22 4094
23 16
24 2046
25 252
26 1022
27 56
28 32766
29 60
30 62
31 1
32 62
33 60
34 8190
35 56
36 174762
37 2044
38 8190
39 48
40 2046
41 252
42 254
43 248
44 8190
45 8188

Puoi vedere i casi di test da n = 2 a 21 qui con il mio simulatore di Game-of-Life-esque: Variations of Life .


EDIT: la sequenza qui è stata pubblicata come A268754 !


tutti sono periodici E il periodo è limitato da 2^n-1, perché questo è il numero di possibili stati diversi da zero del "filo"
Luis Mendo,

@LuisMendo: In realtà, il limite superiore è inferiore perché gli elettroni non sono mai adiacenti. Esattamente quanto meno, non lo so.
El'endia Starman,

The period does not necessarily include the starting state. Some lengths never return to the starting state, but all of them are periodic.Hai un esempio?
edc65,

@ edc65: un filo di lunghezza 5 è l'esempio più piccolo.
El'endia Starman,

1
Più fortemente, gli elettroni si alternano tra posizioni pari e dispari, quindi il periodo è al massimo 2 ^ (n / 2 + 1).
xnor

Risposte:


10

Python 2, 148 142 87 byte

n=input()
p=l=1
t=1
h=2
while t!=h:
 if p==l:t,l,p=h,0,p*2
 h=h/2^h*2%2**n;l+=1
print l

Utilizza l'algoritmo di rilevamento del ciclo di Brent e quindi funziona davvero velocemente.


Ho anche scritto un'animazione in Python (entrambi i lavori 2 e 3). Deve pygletfunzionare. È possibile visualizzare l'animazione eseguendo:

python -m pip install --user pyglet
curl -s https://gist.githubusercontent.com/orlp/f32d158130259cbae0b0/raw/ | python

(Sentitevi liberi di scaricare l'essenza e ispezionare il codice prima di eseguire.) È possibile premere i tasti + e - per aumentare / ridurre la visualizzazione di n .


E infine, per coloro che sono interessati ad esplorare ulteriormente questa sequenza numerica, ecco una versione leggibile (questa è stata utilizzata per generare i casi di test sopra):

# Brent's cycle detection, modified from wikipedia.
def electron_period(n):
    wire_mask = (1 << n) - 1
    power = lam = 1
    tortoise, hare = 1, 2
    while tortoise != hare:
        if power == lam:
            tortoise = hare
            power *= 2
            lam = 0
        hare = ((hare << 1) ^ (hare >> 1)) & wire_mask
        lam += 1
    return lam

So che è passato più di un anno, ma mi chiedo se l'uso di HashLife lo avrebbe accelerato del tutto
solo ASCII il

7

Mathematica, 127 byte

p@n_:=Tr[#2-#]&@@Position[#,Last@#]&@NestWhileList[1~Table~n~ArrayPad~1*18~CellularAutomaton~#&,{1}~ArrayPad~{1,n},Unequal,All]

Spiegazione

Regola 18 :

{0,0,0} -> 0
{0,0,1} -> 1
{0,1,0} -> 0
{0,1,1} -> 0
{1,0,0} -> 1
{1,0,1} -> 0
{1,1,0} -> 0
{1,1,1} -> 0

Casi test

p/@Range[10]
(* {1,2,1,6,4,14,1,14,12,62} *)

7

Python 2, 68 byte

f=lambda n,k=1,l=[]:k in l and-~l.index(k)or f(n,k/2^k*2%2**n,[k]+l)

Il rilevamento del ciclo potrebbe essere migliore, ma il passaggio iterativo è piacevole.

k -> k/2^k*2%2**n

Rappresentando l'array come un numero binario k, l'aggiornamento può essere eseguito prendendo l'XOR di kspostato a sinistra con /2e a destra con *2, quindi troncando a nbyte come %2**n.


4

Python 3 2, 134 121 118 byte

Q=input()
h=[]
n=[0,1]+Q*[0]
while n not in h:h+=[n];n=[0]+[n[d]^n[d+2] for d in range(Q)]+[0]
print len(h)-h.index(n)

Sostanzialmente uguale alla mia risposta Pyth , ma adattata in qualche modo a causa della mancanza di alcune funzioni integrate in Python.

Versione non golfata:

length = input()
history = []
new = [0] + [1] + length*[0]
while new not in history:
    history += [new]
    new = [0] + [new[cell]^new[cell+2] for cell in range(length)] + [0]
print len(history) - history.index(new)

4

Pyth, 39 36 byte

L++Zmx@bd@bhhdQZ-lJ.uyN.[,Z1ZQ)xJyeJ

Utilizza la funzione "punto fisso cumulativo" per iterare fino a poco prima che una configurazione ricorra e restituisce tutte le configurazioni intermedie come un elenco di elenchi. Questo funziona perché le regole sono deterministiche e la configurazione della prossima generazione è una funzione della configurazione corrente. Ciò significa che una volta che appare di nuovo la stessa configurazione, gli automi hanno completato un ciclo.

Dopo aver raggiunto quella (l'ultima iterazione del ciclo), chiama la funzione next-gen un'ultima volta sull'ultimo elemento dell'elenco "history", per ottenere la configurazione successiva (che è la configurazione iniziale di un ciclo), e trova il suo indice nella storia. Ora il periodo è semplicemente la lunghezza (1 + indice di fine ciclo) meno l'indice di inizio ciclo.

In pseudocodice pythonic:

                  Z = 0
                  Q = eval(input())
L                 def y(b):                # generates next-gen from current(param)
  ++Zm                return [Z] + map(    # adds head zero padding
    x@bd@bhhd             lambda d: b[d] ^ b[1+ 1+ d],  # xor the states of adjacent cells
    Q                     range(Q))        # implicit range in map
    Z                     + [Z]            # adds end zero padding
-lJ.uyN.[,Z1ZQ)   J = repeatTilRecur(lambda N,Y:y(N), padRight([Z,1],Z,Q)); print( len(J) -
                  # N:value; Y:iteration count
  JxJyeJ              J.index( y( J[-1] ) ) )

La suite di test impiega troppo tempo affinché il server lo uccida, quindi dovrai usare il programma normale e testarlo uno per uno, o installare Pyth (se non l'hai fatto) e usare uno script per testarlo.


4

Gelatina, 19 18 17 byte

H^Ḥ%®
2*©Ç‘СUµiḢ

Questo codice calcola i primi 2 stati n , quindi non è particolarmente veloce o efficiente in termini di memoria ...

Provalo online! oppure verifica i primi 16 casi di test .

Versione alternativa, 13 byte (non competitiva)

Le versioni di Jelly che superano questa sfida hanno il rilevamento di loop integrato, consentendo una soluzione che è sia più breve che più efficiente.

H^Ḥ%®
2*©ÇÐḶL

Questo gestisce facilmente l'ultimo caso di test. Provalo online!

Come funziona

2*©Ç‘СUµiḢ    Main link. Input: n (integer)

2*             Compute 2 ** n.
  ©            Store the result in the register.
     С        Do the following:
   Ç             Apply the helper link, which updates the state, ...
    ‘            2 ** n + 1 times.
               Collect all 2 ** n + 2 intermediate results in a list.
       U       Upend; reverse the list of results.

        µ      Begin a new, monadic chain. Argument: R (list of results)
          Ḣ    Yield and remove the first element of R (final state).
         i     Find its first index in the remainder or R.
               This is the length of the loop.

H^Ḥ%®        Helper link. Argument: s (state, integer)

H            Halve s. This yields a float, but ^ will cast to integer.
  Ḥ          Double s.
 ^           Compute (s ÷ 2) ^ (s × 2).
    ®        Retrieve the value stored in the register (2 ** n).
   %         Compute ((s ÷ 2) ^ (s × 2)) % (2 ** n).

Si noti che il collegamento helper viene applicato a 2 n nella prima iterazione, che non codifica uno stato valido. Tuttavia, ((2 n ÷ 2) ^ (2 n × 2))% 2 n = (2 n - 1 + 2 n + 1 )% 2 n = 2 n - 1 , che è uno dei possibili stati iniziali.

Dato che eseguiamo il loop 2 n + 1 volte, ci viene garantito uno stato due volte, rendendo efficace il rilevamento del loop.


3

CJam, 41 34 31 27 25 byte

Grazie a Dennis per aver salvato 3 byte. Prendere in prestito un'idea dalla sua risposta di Jelly ne ha salvate altre 4.

2ri#_){__4*^2/W$%}*]W%(#)

Provalo qui.

Spiegazione

Sto rappresentando il filo semplicemente come un numero intero (i cui bit indicano le posizioni degli elettroni) invece di utilizzare un elenco effettivo di bit. Lo stato è aggiornato tramite calcoli bit per bit abbastanza semplici.

Per trovare il periodo, raccogliamo tutti i risultati intermedi nello stack, eseguiamo la simulazione per 2 passi n-1 +1, quindi determiniamo il periodo come numero di elementi dall'ultima occorrenza dello stato finale (più 1).

Ecco una ripartizione del codice:

2ri#   e# Compute 2^n. This has a 1 in the n+1-th bit and zeroes below it. This is
       e# itself not a valid state but will be turned into 2^(n-1) by the first
       e# update.
_)     e# Duplicate and increment to get number of steps to simulate.
{      e# Repeat that many times...
  __   e#   Duplicate the last state twice.
  4*   e#   Multiply by 4, shifting all bits to the left by two positions.
  ^    e#   XOR - we only keep keep those cells where we have exactly one 1-bit
       e#   between both copies, i.e. those that neighboured a single electron
       e#   but shifted up by one position. We don't need handle the survival rule
       e#   explicitly, since electrons can never be adjacent in the first place.
  2/   e#   Divide by 2 shifting all bits back to the right again.
  W$   e#   Copy the initial number 2^n.
  %    e#   Modulo - this simply sets the first bit to 0.
}*
]      e# Wrap all states in an array.
W%     e# Reverse it.
(      e# Pull off the latest state.
#      e# Find its position in the remainder of the array.
)      e# Increment.

2

JavaScript (ES6) 99 104

n=>eval("a=[...Array(n)];k={};for(a[0]=i=1;!k[a=a.map((v,i)=>v?0:a[i-1]^a[i+1])];k[a]=i++);i-k[a]")

Test

f = n=>eval("a=[...Array(n)];k={};for(a[0]=i=1;!k[a=a.map((v,i)=>v?0:a[i-1]^a[i+1])];k[a]=i++);i-k[a]")

console.log = x => O.textContent += x + '\n';

;[...Array(45)].map((_, i) => console.log(++i + ' ' + f(i)))
<pre id=O></pre>


2

Haskell, 170 byte

x!pfornisce l'elemento all'indice p se in limiti, altrimenti 0. ncalcola il passaggio successivo. g idà il ipasso. c xindica il periodo, se si inizia con x. favvolge tutto insieme.

n x|l<-length x-1=[mod(x!(p-1)+x!(p+1))2|p<-[0..l],let y!q|q<0=0|q>=l=0|1<2=y!!p]
c x=[i-j|i<-[1..],j<-[0..i-1],let g k=iterate n x!!k,g i==g j]!!0
f n=c$1:map(*0)[2..n]

(Nota: pubblicato dal telefono che ha l'interprete degli abbracci, che non è completo, quindi potrebbe avere errori di battitura.)


2

MATL , 38 37 36 35 byte

1Oi(`t0Y)5BX+8L)1=vt6#Xut0)=fdt?w}A

Questo utilizza un ciclo che continua a calcolare i nuovi stati fino a quando il nuovo stato è uguale a uno dei precedenti. Ogni stato è un vettore di zeri e uno. Questi vettori sono memorizzati come file di un array 2D in crescita.

Il calcolo di ogni nuovo stato viene fatto contorcendo lo stato corrente con la sequenza [1,0,1], mantenendo solo la parte centrale e impostando 0qualsiasi voce che non lo è 1.

EDIT (13 maggio 2016) Il codice nel seguente link è stato leggermente modificato in base alle modifiche introdotte nella lingua dopo che questa risposta è stata scritta

Provalo online!

1Oi(            % create initial vector [1,0,0,...,0], with size equal to input
`               % do...while loop
  t0Y)          %   duplicate. Get last row of array: most recent vector
  5BX+8L)       %   compute new vector by convolving the most recent one
                %   with [1,0,1] and keeping only the central part
  1=            %   set ones to 1, rest to 0
  v             %   append to 2D array
  t6#Xu         %   compute vector of unique numeric labels, so that equal rows
  t0)=f         %   indices of entries whose value equals that of the last entry.
                %   This will contain the index of the last entry and possibly
                %   another index, in which case we've found a repetition
  d             %   this will either be empty (which is falsy) or contain the
                %   period, which is a nonzero number (and thus truthy)
  t?            %   duplicate. If non-empty (and nonzero)
    w           %     swap to put the 2D-array at the top of the stack. This is
                %     falsy, because it contains at least one zero, even in the
                %     n=1 case (the array is initiallized to 0 in that case)
                %     So the loop will terminate, with the period left on the stack
  }             %   else
    A           %     this transforms the empty array at the top of the stack
                %     into a true value, so that the loop will continue
                %   implicitly end if
                % implicitly end loop
                % implicitly display stack contents (period)

1

Perl 6, 81 byte

{my@h=my$w=2;@h.push($w=$w/2+^$w*2%2**$_)while 2>@h.grep($w);[R-] @h.grep($w,:k)}

Espanso e ungolfed un po '

-> $n {
    my @history = my $wire = 2;
    while 2 > @history.grep($wire) {
        @history.push($wire = $wire/2 +^ $wire*2 % 2**$n)
    }
    [R-] @history.grep($wire,:k)
}

Un po 'di spiegazione:

  • [op]riduce l'elenco usando op. Ad esempio [+] @listsommerà@list
  • Rè una meta-op che inverte gli argomenti dati a un'op. Ad esempio 1 R- 3si tradurrà in 2.

1

C ++, 211 byte

golfed

#include <bitset>
#include <cstdio>
#define B std::bitset<1<<10>
B m,t(1),h(2);int main() {int p,l;for(scanf("%d",&p);p--;m.set(p));
for(p=l=1;t!=h;h=(h>>1^h<<1)&m,l++)p==l?t=h,p*=2,l=0:0;return !printf("%d",l);}

Con spazio bianco aggiunto per la leggibilità

#include <bitset>
#include <cstdio>
#define B std::bitset<1<<10>
B m,t(1),h(2);
int main() {    
    int p,l;
    for(scanf("%d",&p);p--;m.set(p));
    for(p=l=1;t!=h;h=(h>>1^h<<1)&m,l++)p==l?t=h,p*=2,l=0:0;    
    return !printf("%d",l);
}

Buone pratiche per il bitset di C ++; e una grande istruzione sull'algoritmo di rilevamento del ciclo di Brent (usato da @orlp)


0

Pyth, 95 byte

J.[ZQ[1)K_1=bYW<K0=NY aN?hJZ?htJ1ZFTr1tlJ aN?@JTZ?x@JhT@JtT1Z) aN?eJZ?@J_2 1Z=JN=KxbJ abJ;-tlbK

Puoi provarlo qui .



0

Rubino, 72 byte

Funzione anonima.

->n{s=[w=1];c=p
(j=s.index w=w*2%2**n^w/2
j ?c=s.size-j:s<<w)while !c
c}
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.