I nastri circolari sono eccitanti?


32

Un derivato Brainfuck

Definiamo un semplice linguaggio di programmazione simile a Brainfuck . Ha un nastro bidirezionale di celle e ogni cella contiene un bit. Tutti i bit sono inizialmente 0. C'è una testa mobile sul nastro, inizialmente nella posizione 0. Un programma è una stringa sopra i caratteri <>01!, eseguita da sinistra a destra, con la seguente semantica:

  • < sposta la testa di un passo verso sinistra.
  • > sposta la testa di un passo verso destra.
  • 0 mette 0 nella cella corrente.
  • 1 mette 1 nella cella corrente.
  • ! capovolge la cella corrente.

Non ci sono loop, quindi un programma di n caratteri termina dopo esattamente n passaggi. Un programma è noioso se tutte le celle contengono 0 alla fine dell'esecuzione ed entusiasmante se ne esiste almeno una 1. Notare che la dimensione del nastro non è specificata, quindi a seconda dell'implementazione, può essere infinita a due vie o circolare.

Un programma di esempio

Considera il programma 1>>>!<<<<0>!>>>!. Su un nastro infinito, l'esecuzione procede come segue:

     v
00000000000000  Put 1
     v
00000100000000  Move by >>>
        v
00000100000000  Flip
        v
00000100100000  Move by <<<<
    v
00000100100000  Put 0
    v
00000100100000  Move by >
     v
00000100100000  Flip
     v
00000000100000  Move by >>>
        v
00000000100000  Flip
        v
00000000000000

Alla fine, tutte le celle sono 0, quindi questo programma è noioso. Ora eseguiamo lo stesso programma su un nastro circolare di lunghezza 4.

v
0000  Put 1
v
1000  Move by >>>
   v
1000  Flip
   v
1001  Move by <<<< (wrapping around at the edge)
   v
1001  Put 0
   v
1000  Move by > (wrapping back)
v
1000  Flip
v
0000  Move by >>>
   v
0000  Flip
   v
0001

Questa volta, c'è una cella con valore 1, quindi il programma è eccitante! Vediamo che se un programma è noioso o eccitante dipende dalle dimensioni del nastro.

L'obiettivo

Il tuo input è una stringa non vuota <>01!che rappresenta un programma nel linguaggio di programmazione sopra. Una matrice di caratteri è anche un formato di input accettabile. È garantito che il programma sia noioso quando viene eseguito su un nastro infinito. L'output deve essere l'elenco delle lunghezze del nastro su cui il programma è entusiasmante. Si noti che è necessario testare il programma solo su nastri più corti della lunghezza del programma.

La soluzione con il numero di byte più basso in ogni lingua è la vincitrice. Si applicano le regole standard del .

Casi test

> : []
110 : []
1>0<! : [1]
0>>1>0<<>! : [1]
1>>>!<<<<0>!>>>! : [2, 4]
!<!<><<0>!>!<><1!>>0 : [2]
>>!>><>001>0<1!<<!>< : [1, 2, 3]
1!><<!<<<!!100><>>>! : [1, 3]
!!1>!>11!1>>0<1!0<!<1><!0<!<0> : [3, 4]
<><<>>!<!!<<<!0!!!><<>0>>>>!>> : [1, 2, 4]
0>>><!<1><<<0>!>>!<<!!00>!<>!0 : [3]
0000!!!!><1<><>>0<1><<><<>>!<< : []
!>!>!>!>!>1>!>0<!<!<!<0<!<0<!<!<!<1>!>0<<! : [1, 2, 5, 7]
<!!>!!><<1<>>>!0>>>0!<!>1!<1!!><<>><0<<!>><<!<<!>< : [1, 2, 4, 5]
!>1<<11<1>!>!1!>>>0!!>!><!!00<><<<0<<>0<<!<<<>>!!> : [1, 2, 3, 5, 6]

1
Possiamo scegliere caratteri distinti e coerenti anziché <>01!?
Mr. Xcoder,

1
Un array di istruzioni è un input accettabile?
Arnauld,

@ Mr.Xcoder No, dovresti usare questi caratteri esatti.
Zgarb,

@Arnauld Un array di caratteri è abbastanza vicino a una stringa, lo permetterò.
Zgarb,

Risposte:


6

Haskell, 119 byte

t#'<'=last t:init t
(h:t)#c|c<'#'=1-h:t|c>'='=t++[h]|1<2=read[c]:t
f p=[n|n<-[1..length p],sum(foldl(#)(0<$[1..n])p)>0]

Provalo online!

La funzione #è l'interprete per un singolo comando c. L'intero programma pviene eseguito folding #con il nastro iniziale in p. fesegue pper ogni nastro e mantiene quelli in cui la somma delle celle è almeno 1.


n<-[1..length p] ... 0<$[1..n]sembra piuttosto lungo, deve esserci un modo più breve.
nimi,

Non riesco a vedere un modo più breve. Il problema che vedo è che in realtà hai bisogno del valore di ncome risultato, quindi se hai costruito 0<$[1..n]un modo diverso (diciamo con scanr(:)), dovresti prenderlo length. (Ho anche provato a usare 1(per sostituire lengthcon sum) o False(per usare orper il test) invece di 0, ma non è risultato più breve.)
Ørjan Johansen

@ ØrjanJohansen: sì, ho provato n<-init$scanr(:)[]$0<$p ... nche è più corto di 2 byte, ma restituisce un elenco di nastri iniziali invece della loro lunghezza, ad es [[0],[0,0,0]]. Con un po 'di piega delle regole, potrei vedere i nastri come numeri unari, quindi forse va bene.
nimi,

init$può essere sostituito inserendo un [0]elenco iniziale, ma non è ancora abbastanza breve. Penso che l'unario sia consentito solo per le lingue senza una rappresentazione numerica più naturale .
Ørjan Johansen,

4

Stax , 56 54 43 38 35 byte CP437

è¥%►BΣ░ÜY⌂y(â&.═ªê►V½▲y▌)▀♫♂╣ª?√»!#

42 byte quando decompresso,

%fz(y{{|(}{|)}{B!s+}{0_]e&}4ls"><! "I@!F|a

Esegui ed esegui il debug online!

-2 byte per commento di @recursive

Spiegazione

Userò la versione con un prefisso i(cioè i%fz(y{{|(}{|)}{B!s+}{0_]e&}4ls"><! "I@!F|a) per spiegare e spiegherò perché ipuò essere rimosso

i               Suppress implicit eval
                    This prevents the test case "110" from being interpreted as a number
                    However, this can be removed because a program containing only numbers cannot be exciting and the output will be empty anyway.
                    This is based on the fact that the program is boring on non-circular tapes
 %f             Filter range [1..n] with the rest of this program
                    Where n is the length of the input
                    Implicit output the array after filtering, one element per line
   z(           Initialize the tape
     y{  F      Run the program
          |a    Any cell is non-zero

Codice per l'esecuzione del programma:

{|(}                                 Block to rotate left by one element
    {|)}                             Block to rotate right by one element
        {B!s+}                       Block to perform logical not on the element at index 0
              {0_]e&}                Block to obtain current instruction,
                                         Convert it to a number
                                         And assign to element at index 0

                     4l              Pack the 4 blocks in an array
                       s"<>! "I      Find the index of current instruction in string, if not found, the index will be -1
                                         And when indexed with -1, it wraps around to the 4th element.

                               @!    And execute the corresponding block.

1
Ho aggiunto un caso di prova di tutte le cifre per convalidare il tuo icontrollo.
Zgarb,

0]*può essere sostituito con z(. Inoltre, se si modifica la stringa in "<>!", Quindi 0e 1verrà fornito l'indice -1, quindi in questo modo l'elenco di blocchi necessita solo di 4 blocchi, anziché di 5. Questo funzionerà poiché i gestori 0e 1sono identici comunque.
ricorsivo il

@recursive Buon punto preso.
Weijun Zhou,




2

Rosso , 243 byte

func[p][repeat n length? p[b: copy[]insert/dup b 0 n i: 1
parse p[any["<"(i: i - 1 if i < 1[i: n])|">"(i: i + 1 if i > n[i: 1])|"0"(b/(i): 0)|"1"(b/(i): 1)|"!"(b/(i): either b/(i) = 0[1][0])|
skip]]s: 0 foreach c b[s: s + c]if s > 0[print n]]]

Provalo online!

Implementazione dettagliata e diretta. L'indicizzazione 1 di Red non mi consente di ridurre il conteggio dei byte utilizzando l'aritmetica modulare per scorrere ciclicamente i nastri circolari.

Ungolfed

f: func[p][ 
    repeat n length? p[
        b: [] 
        insert/dup b 0 n
        i: 1
        parse p[
            some [
                 "<" (i: i - 1 if i < 1[i: n])
               | ">" (i: i + 1 if i > n[i: 1])
               | "0" (b/(i): 0)
               | "1" (b/(i): 1)
               | "!" (b/(i): either b/(i) = 0 [1][0])
               | skip 
            ]
        ]
        s: 0
        foreach c b[s: s + c]
        if s > 0 [print n]
    ]
]


2

Retina , 121 byte

.+
$.&*0¶$&
\G0
0$`¶
{ms`^.(?=.*¶¶(0|1))
$1
"¶¶!"&mT`d`10`^.
"¶¶>"&`(.)(.*)¶
$2$1¶
"¶¶<"&`(.*)(.)¶
$2$1¶
)`¶¶.
¶¶
G`1
%`.

Provalo online! Spiegazione:

.+
$.&*0¶$&
\G0
0$`¶

Creare una matrice di nastri di ogni lunghezza fino alla lunghezza del programma di input.

{

Ripeti fino a quando il programma non viene consumato.

ms`^.(?=.*¶¶(0|1))
$1

Se il carattere successivo nel programma è 0 o 1, cambia il primo carattere su ogni riga in quel carattere.

"¶¶!"&mT`d`10`^.

Se è un, !allora attiva / disattiva il primo carattere su ogni riga.

"¶¶>"&`(.)(.*)¶
$2$1¶
"¶¶<"&`(.*)(.)¶
$2$1¶

Se è un >o <quindi ruotare la linea. (Più facile che muovere la testa.)

)`¶¶.
¶¶

Elimina l'istruzione e termina il ciclo.

G`1

Mantieni solo le linee emozionanti.

%`.

Conta la lunghezza di ogni riga.


2

JavaScript (ES6), 126 118 byte

3 byte salvati grazie a @ user71546

Accetta l'input come una matrice di stringhe di 1 carattere.

f=(s,l=0,p=0,t=[])=>s[l++]?s.map(c=>1/c?t[p%l]=+c:c>'='?p++:c>';'?p+=l-1:t[p%l]^=1)&&+t.join``?[l,...f(s,l)]:f(s,l):[]

Provalo online!


Sostituzione t.some(x=>x)?da +t.join``?invece controllare la matrice come cifre (e 0 indica un all zero nastro), ma 3 byte meno.
Shieru Asakoto,

2

APL (Dyalog Unicode) , 79 64 54 byte ( Adám's SBCS )

⍸⊂{∨/⍎⍕(↓',',⍨5 3'0@11@1~@1 1⌽¯1⌽')['01!<'⍳⌽⍺]⍵}¨0=,\

Provalo online!

-15 grazie ad Adám (dimenticato di monadic ).
-10 grazie a ngn .



@ Adám Hm, sembra che non sia ottimale (ad esempio non è necessario ). Lo esaminerò e aggiornerò. :)
Erik the Outgolfer

Ma se lo rimuovi avrai bisogno di un ;, no?
Adám,

@ Adám no , perché dovresti?
Erik the Outgolfer


1

MATL , 46 39 byte

f"@:~G"@59>?@61-YS}@33=?t1)~}@U]1(]]a?@

Provalo online! Oppure verifica tutti i casi di test .

Come funziona

f             % Push indices of nonzero chars of (implicit) input string: gives
              % [1 2 ... n] where n is input length
"             % For each k in [1 2 ... n]. These are the possible tape lengths
  @:~         %   Push array of k zeros. This is the tape, in its initial state
  G           %   Push input string
  "           %   For each char in the input string
    @59>?     %     If code point of current char exceeds 59 (so it is '<' or '>')
      @61-    %       Push code point minus 61: gives -1 for '<', or 1 for '>'
      YS      %       Circularly shift the tape by that amount. Instead of moving
              %       the head, we shift the tape and keep the head at entry 1
    }         %     Else
      @33=?   %       If code point of current char is 33 (so it is '!')
        t1)   %         Duplicate the array representing the tape, and get its
              %         first entry
        ~     %         Logical negate
      }       %       Else
        @U    %         Push current char (it is '0' or '1') converted to number
      ]       %       End
      1(      %       Write (either 0, 1 or old value negated) at entry 1
    ]         %     End
  ]           %   End
  a?          %   If the tape contains at least a nonzero value
    @         %     Push tape length, k
              %   End (implicit)
              % End (implicit)
              % Display (implicit)

1

APL (Dyalog Unicode) , 192 78 byte

⊂{t/⍵⊣⍵{t[m]←('01!'⍳⍵)⊃0 1,e,⍨~et[m←⍺|ii+←¯1 1 0⊃⍨'<>'⍳⍵]}¨⍺⊣i←⊃t←⍬⍳⍺}¨1+⍳∘≢

Provalo online! (risultato non appiattito)

Provalo online! (Appiattito)

Dopo un po 'di tempo passato a sbattere la testa contro il muro, ho deciso di fare un Tradfn invece di un Dfn. Questo è il risultato. Le persone più intelligenti di me potrebbero essere in grado di giocare a golf.

Sorpresa, sorpresa, qualcuno più intelligente di me ha fatto golf. Grazie Adám per 114 byte.

Egli ha detto:

Si noti che si tratta del programma esatto, ad eccezione dell'utilizzo dell'indicizzazione anziché dell'interiore: Ifs e collasso: For-loop a {_} ¨ mentre si fornisce un argomento sinistro per sostituire il globale.

La funzione presuppone ⎕IO←0.


Come?

(Questa spiegazione usa una versione "ungolfed" per facilitare la lettura)

⊂{                                   Enclose
      i←⊃t←⍬⍳⍺                       Assign a vector of 0s to t (the tape), then assign the first 0 to i.
      t/⍵⊣⍵{                         Use  as left argument for the nested function, then compress the result into t. If there is a 1 anywhere in t, the result will be a vector of the result. If not, the result is an empty vector.
          i+←¯1 1 0⊃⍨'<>'⍳⍵          Map the string '<>' to the argument (which is the BF program). That yields 0 for <, 1 for >, and 2 for anything else.
                                     The resulting vector will then be used as the argument for  to add -1 (index 0), 1 (index 1) or 0 (index 2) to the variable i.
          et[m←⍺|i]                 Assign i mod  (left arg) to m, and use it to index t. Then, assign the value to e.
          t[m]←('01!'⍳⍵)⊃0 1,e,⍨~e   Map the string '01!' to ⍵. As before, this yields 0 for 0, 1 for 1, 2 for ! and 3 for anything else.
                                     Then, concatenate (not e) with e, then concatenate that with the vector 0 1. This is used as argument to be picked from, and it is assigned to t[m].
      }¨⍺                            Do that for each argument
  1+⍳∘≢                            And do that for each possible tape length from 1 to the length of the input.

1
Salvare un byte facendo t←l⍴0be t←l⍴i←0e rimuovendo la linea sopra di esso. Puoi anche salvarne un altro cambiando t[i|⍨≢t]←1-t[i|⍨≢t]in t[i|⍨≢t]←~t[i|⍨≢t].
Zacharý

2
@ Zacharý giusto, e salva ulteriormente altri 112 byte . Esattamente lo stesso codice, ho solo giocato un po 'a golf.
Adám,

Sì, ha solo segnato "un po '". Non hai bisogno della s?
Zacharý

@ Zacharý What s? È una funzione tacita.
Adám,

@ Zacharý Considererei questo grazioso Adám'd, vero?
J. Sallé,


0

C (clang) , 171 byte

l,i;f(S){for(char*p,t[l=strlen(S)];l;memchr(t,1,l)&&printf("%d ",l),l--)for(memset(t,i=0,l),p=S;*p;p++)*p==60?i=i?i-1:l-1:*p==62?i=i^l-1?i+1:0:*p^33?t[i]=*p-48:(t[i]^=1);}

Provalo online!

Ho dovuto usare clang, dato che l'uso char*p,t[l=strlen(S)]come espressione di inizializzazione per qualche motivo fa pensare a GCC che io voglia dichiarare strleninvece di chiamarlo.

Abbastanza diretto: esegue il programma su nastri circolari di lunghezza decrescente, producendo qualsiasi lunghezza che abbia provocato un 1 da qualche parte sul nastro.

Provò ad accorciare il groviglio degli operatori ternari, ma alla fine ebbe bisogno di più parentesi di quanto non fosse salutare.


Suggerisci i=0,bzero(t,l)invece di memset(t,i=0,l)e *p-62?t[i]=*p^33?*p-48:t[i]^1:(i=~i+l?i+1:0)invece di*p==62?i=i^l-1?i+1:0:*p^33?t[i]=*p-48:(t[i]^=1)
ceilingcat il
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.