Il existe de nombreux formalismes, alors même si vous pouvez trouver d'autres sources utiles, j'espère le préciser suffisamment pour qu'elles ne soient pas nécessaires.
Un RM se compose d'une machine à états finis et d'un nombre fini de registres nommés, dont chacun contient un entier non négatif. Pour faciliter la saisie textuelle, cette tâche nécessite que les états soient également nommés.
Il existe trois types d'état: incrément et décrément, qui font tous deux référence à un registre spécifique; et terminer. Un état d'incrémentation incrémente son registre et passe le contrôle à son seul successeur. Un état de décrémentation a deux successeurs: si son registre est différent de zéro, il le décrémente et passe le contrôle au premier successeur; sinon (c'est-à-dire que le registre est nul), il passe simplement le contrôle au deuxième successeur.
Pour la "gentillesse" en tant que langage de programmation, les états de terminaison prennent une chaîne codée en dur à imprimer (vous pouvez donc indiquer une terminaison exceptionnelle).
L'entrée provient de stdin. Le format d'entrée se compose d'une ligne par état, suivie du contenu du registre initial. La première ligne est l'état initial. BNF pour les lignes d'état est:
line ::= inc_line
| dec_line
inc_line ::= label ' : ' reg_name ' + ' state_name
dec_line ::= label ' : ' reg_name ' - ' state_name ' ' state_name
state_name ::= label
| '"' message '"'
label ::= identifier
reg_name ::= identifier
Il y a une certaine flexibilité dans la définition de l'identifiant et du message. Votre programme doit accepter une chaîne alphanumérique non vide comme identifiant, mais il peut accepter des chaînes plus générales si vous préférez (par exemple, si votre langue prend en charge les identificateurs avec des traits de soulignement et c'est plus facile pour vous de travailler avec). De même, pour le message, vous devez accepter une chaîne non vide d'alpha et d'espaces, mais vous pouvez accepter des chaînes plus complexes qui autorisent les sauts de ligne et les guillemets doubles si vous le souhaitez.
La dernière ligne d'entrée, qui donne les valeurs initiales du registre, est une liste séparée des espaces d'affectations identificateur = int, qui doit être non vide. Il n'est pas nécessaire d'initialiser tous les registres nommés dans le programme: tous ceux qui ne sont pas initialisés sont supposés être 0.
Votre programme doit lire l'entrée et simuler la RM. Lorsqu'il atteint un état de fin, il doit émettre le message, une nouvelle ligne, puis les valeurs de tous les registres (dans n'importe quel format pratique, lisible par l'homme, et dans n'importe quel ordre).
Remarque: formellement, les registres doivent contenir des entiers non bornés. Cependant, vous pouvez, si vous le souhaitez, supposer qu'aucune valeur de registre ne dépassera jamais 2 ^ 30.
Quelques exemples simples
a + = b, a = 0s0 : a - s1 "Ok"
s1 : b + s0
a=3 b=4
Résultats attendus:
Ok
a=0 b=7
b + = a, t = 0
init : t - init d0
d0 : a - d1 a0
d1 : b + d2
d2 : t + d0
a0 : t - a1 "Ok"
a1 : a + a0
a=3 b=4
Résultats attendus:
Ok
a=3 b=7 t=0
Cas de test pour des machines plus difficiles à analyser
s0 : t - s0 s1
s1 : t + "t is 1"
t=17
Résultats attendus:
t is 1
t=1
et
s0 : t - "t is nonzero" "t is zero"
t=1
Résultats attendus:
t is nonzero
t=0
Un exemple plus compliqué
Tiré du défi de code de problème Josephus du DailyWTF. L'entrée est n (nombre de soldats) et k (avance) et la sortie en r est la position (indexée zéro) de la personne qui survit.
init0 : k - init1 init3
init1 : r + init2
init2 : t + init0
init3 : t - init4 init5
init4 : k + init3
init5 : r - init6 "ERROR k is 0"
init6 : i + init7
init7 : n - loop0 "ERROR n is 0"
loop0 : n - loop1 "Ok"
loop1 : i + loop2
loop2 : k - loop3 loop5
loop3 : r + loop4
loop4 : t + loop2
loop5 : t - loop6 loop7
loop6 : k + loop5
loop7 : i - loop8 loopa
loop8 : r - loop9 loopc
loop9 : t + loop7
loopa : t - loopb loop7
loopb : i + loopa
loopc : t - loopd loopf
loopd : i + loope
loope : r + loopc
loopf : i + loop0
n=40 k=3
Résultats attendus:
Ok
i=40 k=3 n=0 r=27 t=0
Ce programme comme une image, pour ceux qui pensent visuellement et trouveraient utile de saisir la syntaxe:
Si vous avez aimé ce golf, regardez la suite .
la source
Réponses:
Perl, 166
Courez avec
perl -M5.010 file
.Cela a commencé très différemment, mais je crains qu'elle ne converge avec la solution Ruby dans de nombreux domaines vers la fin. On dirait que l'avantage de Ruby est «pas de sceaux» et «une meilleure intégration regex» de Perl.
Un petit détail des entrailles, si vous ne lisez pas Perl:
@p=<>
: lire la description complète de la machine pour@p
/=/,$_{$`}=$' for split$",pop@p
: pour chaque (for
) affectation (split$"
) dans la dernière ligne de description de la machine (@p
), recherchez le signe égal (/=/
) puis affectez une valeur$'
à la%_
clé de hachage$`
$o='\w+'
: l'état initial serait le premier à correspondre aux «caractères de mots» de l'expression rationnelle de Perluntil/"/
: boucle jusqu'à ce que nous atteignions un état de terminaison:map{($r,$o,$,,$b)=$'=~/".*?"|\S+/g if/^$o :/}@p
: boucle sur la description de la machine@p
: lorsque nous sommes sur la ligne correspondant à l'état actuel (if/^$o :/
), jetons (/".*?"|\S+/g
) le reste de la ligne$'
aux variables($r,$o,$,,$b)
. Astuce: la même variable$o
si elle est utilisée initialement pour le nom de l'étiquette et ensuite pour l'opérateur. Dès que l'étiquette correspond, l'opérateur la remplace et comme une étiquette ne peut pas (raisonnablement) être nommée + ou -, elle ne correspond plus.$_=$o=($_{$r}+=','cmp$o)<0?do{$_{$r}=0;$b}:$,
:- ajustez le registre cible
$_{$r}
vers le haut ou vers le bas (magie ASCII:','cmp'+'
vaut 1 alors que','cmp'-'
-1);- si le résultat est négatif (
<0?
, ne peut se produire que pour -)- alors restez à 0 (
$_{$r}=0
) et retournez la deuxième étiquette$b
;- sinon retourner la première (éventuellement la seule) étiquette
$,
$,
lieu de$a
donc il peut être collé au jeton suivantuntil
sans espace blanc entre les deux.say for eval,%_
: vidage du rapport (eval
) et du contenu des registres dans%_
la source
/^$o :/
. Le simple signe d'insertion suffit à garantir que vous ne regardez que les étiquettes.$'
. C'est un personnage dans l'expression régulière, ce serait trois$c,
à rendre compte de l'extérieur. Alternativement, certains plus gros encore changent en expression rationnelle symbolique.Python + C, 466 caractères
Juste pour le plaisir, un programme python qui compile le programme RM en C, puis compile et exécute le C.
la source
main
', 'if
', etc.Haskell, 444 caractères
C'était dur! La bonne gestion des messages contenant des espaces coûte plus de 70 caractères. Le formatage de sortie doit être plus "lisible par l'homme" et correspondre aux exemples coûte encore 25.
la source
where
sur une seule ligne séparée par des points-virgules pourrait vous faire économiser 6 caractères. Et je suppose que vous pouvez enregistrer certains caractères dans la définition deq
en changeant le si-alors-sinon verbeux en garde de modèle."-"
dans la définitionq
et utilisez un trait de soulignement à la place.q[_,_,r,_,s,z]d|maybe t(==0)$lookup r d=n z d|t=n s$r%(-1)$d
. Mais de toute façon, ce programme est extrêmement bien joué.lex
Prélude. Par exemple, quelque chose commef[]=[];f s=lex s>>= \(t,r)->t:f r
divisera une ligne en jetons tout en gérant correctement les chaînes entre guillemets.Ruby 1.9,
214212211198195192181175173175la source
Delphi, 646
Delphi n'offre pas grand-chose en ce qui concerne le fractionnement de chaînes et d'autres choses. Heureusement, nous avons des collections génériques, ce qui aide un peu, mais c'est toujours une solution assez large:
Voici la version échancrée et commentée:
la source
PHP,
446441402398395389371370366 caractèresNon golfé
Changelog
446 -> 441 : Prend en charge les chaînes pour le premier état, et une légère compression
441 -> 402 : Compression if / else et instructions d'affectation autant que possible
402 -> 398 : Les noms de fonction peuvent être utilisés comme constantes pouvant être utilisées comme chaînes
398 -> 395 : Utilise des opérateurs de court-circuit
395 -> 389 : Pas besoin de la partie else
389 -> 371 : Pas besoin d'utiliser array_key_exists ()
371 -> 370 : Suppression de l'espace inutile
370 -> 366 : Suppression de deux espaces inutiles dans le foreach
la source
Groovy, 338
la source
.sort()
)println
- ah bien!Clojure (344 caractères)
Avec quelques sauts de ligne pour la "lisibilité":
la source
Postscript () ()
(852)(718)Pour des vrais cette fois. Exécute tous les cas de test. Il nécessite toujours que le programme RM suive immédiatement le flux du programme.
Edit: plus d'affacturage, noms de procédures réduits.
Indenté et commenté avec programme annexé.
la source
regline
? Tu ne peux pas économiser beaucoup en les appelant des choses commeR
?AWK - 447
Voici la sortie du premier test:
la source
Stax ,
115100 bytesExécuter et déboguer
la source