Simuler un système d'étiquettes cycliques

14

Un système d'étiquettes cycliques est un minuscule modèle de calcul complet de Turing composé d'un alphabet à deux symboles (je vais utiliser {0,1}), d'une liste cyclique finie et non vide de productions qui se composent de ces deux symboles, et d'un mot illimité qui se compose également de ces deux symboles.

À chaque étape:

  • le premier élément du mot est supprimé
  • si c'était 0la production actuelle est sautée
  • si c'était le cas, 1la production actuelle est ajoutée à la fin du mot .
  • la prochaine production devient active. S'il s'agissait de la dernière production, revenez à la première.

Le système s'arrête lorsque le mot devient vide.

Un exemple (de Wikipedia):

Productions: (010, 000, 1111)
Initial word: 11001

Generation  Production   Word (before)            Word (after)
   0           010           11001             →     1001010       
   1           000            1001010          →      001010000
   2           1111            001010000       →       01010000
   3           010              01010000       →        1010000
   4           000               1010000       →         010000000
   5           1111               010000000    →          10000000
   6           010                 10000000    →           0000000010
   7           000                  0000000010 →            000000010
   8           1111                  000000010 →             00000010
   9           010                    00000010 →              0000010

Votre tâche, si vous choisissez de l'accepter, est d'écrire un programme ou une fonction qui prend:

  • une liste de productions,
  • le mot initial, et
  • une génération,

et imprime ou renvoie le mot à cette génération.

Par exemple,

cyclic_tag(
      prod=[[0,1,0],[0,0,0],[1,1,1,1]], 
      word=[1,1,0,0,1], 
      gen=4) => [1,0,1,0,0,0,0]

Détails d'implémentation:

  • L'alphabet n'a pas d'importance. Vous pouvez utiliser 0et 1, Trueet False, Tet NIL, Aet B, ou même 1et 0, ou tout ce que vous pouvez proposer, tant que vous êtes cohérent. Toutes les entrées et sorties doivent utiliser le même alphabet et vous devez indiquer ce que vous utilisez 0et pour quoi 1.

  • La longueur du mot doit être théoriquement illimitée. Autrement dit, vous ne pouvez pas coder en dur une longueur de mot maximale. Si j'exécute votre programme sur un ordinateur idéal avec une quantité infinie de mémoire, votre programme doit théoriquement pouvoir l'utiliser. (Vous pouvez ignorer les limites de votre interprète / compilateur.)

  • Si le système donné s'arrête avant que la génération donnée ne soit atteinte, vous devez retourner ou imprimer le mot vide.

  • La production vide existe et vous devez pouvoir la gérer. Si vous écrivez un programme complet, vos E / S doivent également pouvoir le gérer.

Edit : j'avais initialement prévu que la génération 0soit le mot d'entrée lui-même, et la génération 1soit le résultat de la première étape. C'est-à-dire que j'avais prévu que vous retourniez la colonne précédente . Cependant , comme je n'ai pas été suffisamment clair pour le dire, j'accepterai les deux options ; pour chaque génération, vous pouvez renvoyer la valeur dans la colonne avant ou après . Vous devez indiquer que vous suivez la colonne après , si vous le faites. Vous devez également être cohérent dans la colonne que vous choisissez.

J'attribuerai le plus petit code d'ici une semaine (27/10/2014).

marinus
la source
Êtes-vous sûr que votre sortie dans l'exemple est correcte? Sur la base de l'autre exemple que vous avez donné, je pense que c'est la génération 5 ...
FryAmTheEggman
Pouvons-nous prendre l'entrée dans un ordre différent?
Martin Ender
1
@FryAmTheEggman: C'est correct, je voulais dire la colonne 'avant'. Si plus de gens ont fait cette erreur, je changerai ma question pour accepter l'un ou l'autre. J'avoue que je n'étais pas très clair.
marinus
@ MartinBüttner: tant que vous spécifiez la commande, cela n'a pas d'importance.
marinus

Réponses:

4

GolfScript (17 à 19 octets selon le format d'entrée et le format de sortie accepté)

18 octets:

~.@*<{\1,or(@*+}/`

Prend l'entrée dans le formulaire [1 1 0 0 1] [[0 1 0] [0 0 0] [1 1 1 1]] 4et donne la sortie dans le formulaire [1 0 1 0 0 0 0]. (Peut être 17 octets sans le dernier `si la sortie est1010000 est acceptable).

Démo en ligne

19 octets:

~.@*<{\0`or(1&@*+}/

Prend la saisie dans le formulaire "11001" ["010" "000" "1111"] 4.

Démo en ligne

Dissection

~        # Evaluate input: stack: word productions gen
.@*<     # Produce a list of the right number of productions with suitable repetition
{        # For each of those productions:
  \      #   Bring the word to the top
  0`or   #   Ensure that we don't get an error if the word is empty
  (1&    #   Pop the first char from the word and evaluate it
  @*     #   Repeat the production that many times
  +      #   Concatenate 0 or 1 copies of the production to the rest of the word
}/       # Endforeach

Crédit Martin Büttner de solution CJAM pour l'idée de générer la liste des productions par la répétition et la troncature.

Peter Taylor
la source
Vous êtes lié à la solution CJam que vous citez, j'ai donc choisi cette réponse. Si vous vous rasez un autre octet, je reconsidérerai :)
marinus
@marinus, acceptez-vous la version de 17 octets à laquelle je fais référence dans le texte de ma réponse?
Peter Taylor
Je n'avais pas vu ça, mais ça a l'air valable. Vous devriez peut-être le marquer un peu plus clairement.
marinus
5

Haskell, 55 53 51

(t:w)%p|t=w++p|0<1=w
x%_=x
e w=(!!).scanl(%)w.cycle

cela utilise au Truefur 1et à Falsemesure 0. exemple d'exécution:

*Main> let t=True ; f=False
*Main> e [t,f,t] [[f,f,f],[t,t,t]] 4
[False,False,False,False,False]
fier haskeller
la source
3

CJam, 31 30 28 27 24 18 octets

{_@*<{\_0a?(@*+}/}

Cela définit un bloc (la chose la plus proche d'une fonction), qui s'attend à ce que l'entrée réside sur la pile comme ceci

[1 1 0 0 1] [[0 1 0] [0 0 0] [1 1 1 1]] 9

Il laissera également un tableau de 0s et 1s sur la pile.

Testez-le ici. Collez l'entrée sur la première ligne, le code sur la troisième ligne et ajoutez un ~pour évaluer réellement le bloc. Par exemple

[1 1 0 0 1] [[0 1 0] [0 0 0] [1 1 1 1]] 9
{_@*<{\_0a?(@*+}/}~

Si la sortie n'a pas besoin d'avoir la même forme que l'entrée

Explication:

_@*<{\_0a?(@*+}/
_@               "Duplicate the generation and pull the productions to the top.";
  *<             "Repeat the productions N times and take the first N elements.";
    {         }/ "For each element in that list, run this block.";
     \           "Swap production and current word W.";
      _0a?       "W = (W != []) ? W : [0]. This is to ensure we can unshift an element.";
          (      "Unshift the first 0 or 1 from the word.";
           @     "Rotate the stack, pulling the production to the top.";
            *    "Repeat it 0 or 1 times.";
             +   "Append to the word.";

L'état final du mot est laissé sur la pile.

Merci à Peter Taylor de m'avoir fait revisiter cela.

Martin Ender
la source
1
l~{_,g{('1=@(:Pa+@@P*+}*}*\;28 et encore des possibilités d'amélioration (en particulier la (:Ppartie), mais l'heure du déjeuner
Optimizer
@Optimizer Ah, bonne idée. Je vous remercie. Et oui, :Pça m'ennuie aussi: D
Martin Ender
l~{_,g{(si@(:Pa+@@P*+}*}*\;: 27 et après y avoir réfléchi, :Pest en fait efficace: P
Optimizer
_,gpeut également être remplacé par les _!!mêmes octets.
Optimizer
@Optimizer Je pourrais aussi bien l'utiliser _{...}{}?.
Martin Ender
2

Mathematica, 84 80 77 caractères

f[_,w_,_]=w;f[p_,{x_,y___},n_/;n>0]:=f[RotateLeft@p,Flatten@{y,p~Take~x},n-1]

Exemple:

f[{{0, 1, 0}, {0, 0, 0}, {1, 1, 1, 1}}, {1, 1, 0, 0, 1}, 4]

{1, 0, 1, 0, 0, 0, 0}

alephalpha
la source
2

Pyth 22

Requiert les 3 arguments comme entrées séparées.

#Vvw=z+tz*@Q%NlQshz)zq

Prend des arguments comme:

11001
["010","000","1111"]
4

Explication:

                        : Implicit: z = input(); Q=eval(input())
#                       : Loop until an exception is thrown
 Vvw               )    : for N in range(eval(input()))
    =z                  : assign to z
      +tz               : the sum of the tail of z and
         *@Q%NlQ        : Q[N%len(Q)] times
                shz     : the numeric value of the first character in z
                    zq  : print z then throw exception

Python 2 - 61 67 91 105 124

c=lambda p,w,g:g*w and c(p[1:]+p[:1],w[1:]+w[0]*p[0],g-1)or w

Jolie réponse Joe-Basic. Suppose que la production vide est[[]] .

Merci à @xnor d'avoir souligné que jouer au golf à 2h du matin est une mauvaise décision.

Remerciements supplémentaires à @xnor, à qui je semble devoir 50% de mon score.

Échantillon:

>>> c([[0,1,0],[0,0,0],[1,1,1,1]],[1,1,0,0,1],4)
[1, 0, 1, 0, 0, 0, 0]
FryAmTheEggman
la source
1
Certes, il est plus court d'utiliser un lambda et d'écrire juste g and wpour x? En outre, je pense que cela g*wdevrait fonctionner pour donner une valeur vraie lorsque les deux gsont non nuls et wnon vides.
xnor
De plus, je ne comprends pas l'intérieur if x else w. Ce ne sera pas xtoujours vrai parce que ce code est uniquement exécuté if x, ou manque-t-il quelque chose?
xnor
@xnor Certes, vous avez tout à fait raison :)
FryAmTheEggman
1
Un peu plus de golf avec le and/ ortrick et la rotation pau lieu de l'incrémentation n:c=lambda p,w,g:g*w and c(p[1:]+p[:1],w[1:]+w[0]*p[0],g-1)or w
xnor
@xnor Merci :) Aussi, maintenant que vous en avez fait une fonction de 3 variables, je pense que je le traduis en Pyth ...
FryAmTheEggman
1

Javascript ES6 - 88 octets

f=(p,w,g,n)=>g?w.replace(/(.)(.*)/,(_,a,b)=>f(p,a*1?b+p[(n=n||0)%p.length]:b,g-1,n+1)):w

Ressemble étrangement à la réponse de Fry qui vient d'apparaître dans mon navigateur. (Pas de copie, je le jure solennellement.)

Il semblerait cependant qu'il ait suivi la route du tableau tandis que je suis allé la route chaîne / expression régulière.

Étendu:

f = (p,w,g,n) =>
    g ?
        w.replace( /(.)(.*)/, (_,a,b) =>
            f( p, a*1 ? b + p[(n=n||0)%p.length] : b, g-1, n+1 )
        )
    :
        w

Exemple de sortie

f(['010','000','1111'],'11001',4)
"1010000"

Maintenant, regardez les langues du golf entrer et massacrez-nous tous les deux. :RÉ

COTO
la source
J'ai en fait supprimé mon message parce que j'obtenais des réponses différentes pour les deux exemples. Avez-vous essayé l'exemple où il va de génération en génération? Il semble être un par rapport à l'exemple d'appel complet qu'il a donné ...
FryAmTheEggman
Et ne t'inquiète pas, je crois que tu ne m'as pas copié: P
FryAmTheEggman
@FryAmTheEggman: Mine génère de manière cohérente la colonne "avant" pour la génération numérotée. Ceci est cohérent avec l'exemple de l'OP, et il semble logique que la "génération 0" renvoie simplement l'entrée sans la traiter, ce qui est cohérent avec cette interprétation. Soit dit en passant, j'ai ajouté l'avertissement "copie" parce que les solutions étaient étrangement similaires à certains égards. Nous avons utilisé les mêmes noms d'argument, la même structure récursive de base, et nous avons même ajouté le même fantôme quatrième argument, n. Grands esprits, hein? : D
COTO
Ok, je suppose que si l'un de nous a tort, nous avons tous les deux tort! Unis nous sommes.
FryAmTheEggman
@FryAmTheEggman: Vous ne vous trompiez pas sur M. Peppe. ;)
COTO