99 (prononcé "quatre-vingt-dix-neuf") est un tout nouveau langage de programmation ésotérique (à ne pas confondre avec 99 , notez les italiques). Votre tâche dans ce défi consiste à écrire un interprète pour 99 aussi court que possible. La soumission avec le moins d'octets gagne. Tiebreaker va à la soumission postée en premier.
Étant donné que cette question est un peu plus approfondie que d'habitude et que j'ai hâte de voir de bonnes réponses, j'attribuerai une récompense de 250 représentants à ma réponse préférée (pas nécessairement le gagnant).
99 Spec
99 est un langage impératif . Chaque ligne d'un programme 99 est une instruction unique et, au cours de l'exécution, le pointeur d'instruction commence à la ligne supérieure et parcourt chacune des lignes suivantes dans l'ordre, en les exécutant en cours de route. Le programme se termine lorsque la dernière ligne a été exécutée. Les instructions Goto peuvent rediriger le chemin du pointeur d'instruction.
Newline, space et 9
sont les trois seuls personnages importants dans un programme 99 . Tous les autres personnages sont complètement ignorés. En outre, les espaces de fin sur chaque ligne sont ignorés et plusieurs espaces d'une ligne sont lus comme un seul espace. ("Newline" désigne tout codage de saut de ligne courant . Peu importe celui que votre interprète utilise.)
Donc ce programme:
9 BLAH 99 9a9bb9c9
9 this line and the next have 6 trailing spaces 9
Est identique à ce programme:
9 99 9999
9 9
Variables
Les variables dans 99 ont toutes des noms qui sont un ou plusieurs 9
chaînons ( 9+
en regex). Par exemple, 9
, 99
et 9999999999
sont toutes les variables distinctes. Naturellement, il y en a infiniment beaucoup (sauf limitations de mémoire).
La valeur de chaque variable est un entier signé, de précision arbitraire . Par défaut, chaque variable est affectée à sa propre représentation numérique. Donc, sauf si elle a été réaffectée, la valeur de la variable 9
est le nombre 9 et la valeur de la variable 99
est le nombre 99, et ainsi de suite. Vous pourriez penser que les variables sont traitées comme des nombres simples jusqu'à leur affectation explicite.
Je vais utiliser V
pour faire référence à un nom de variable arbitraire ci-dessous.
Chaque instance de V
pourrait être remplacé par 9
, 99
, 999
, 9999
, etc.
Les déclarations
Il existe cinq types d’énoncés différents dans 99 . Chaque ligne d'un programme 99 contient exactement une déclaration.
La syntaxe décrite ici suppose que tous les caractères superflus ont été supprimés, tous les espaces finaux ont été supprimés et que toutes les séquences d'espaces multiples ont été remplacées par des espaces simples.
1. Pas d'opération
Une ligne vide est un no-op . Cela ne fait rien (à part l'incrémentation du pointeur d'instruction).
2. sortie
V
Une seule variable V
sur une ligne imprime cette variable sur stdout.
Si V
a un nombre impair de 9
l »( 9
, 999
, etc.) , alors la valeur entière de V
divisé par 9 à imprimer (en décimal).
Si V
a un nombre pair de 9
« s ( 99
, 9999
, etc.), le ASCII caractère avec le code V
divisé par 9, mod 128 est imprimé. (C'est (V / 9) % 128
une valeur de 0 à 127.)
Exemple : le programme
9
9999
serait imprimer 1W
. La première ligne est imprimée 1
car 9/9 correspond à 1. La deuxième ligne est imprimée W
car 9999/9 correspond à 1111, et 1111 mod 128 à 87, et 87 correspond au code de caractère W
.
Notez que les sauts de ligne ne sont pas imprimés entre les jetons de sortie. \n
doit être explicitement imprimé pour un saut de ligne.
3. entrée
V
Une seule variable V
sur une ligne avec un espace de début prend l'entrée de stdin et la stocke dans cette variable.
Si V
a un nombre impair de 9
', l'utilisateur peut taper n'importe quel entier signé et V
sera défini sur 9 fois cette valeur.
Si V
a un nombre pair de 9
, l'utilisateur peut saisir n'importe quel caractère ASCII et V
sera défini sur 9 fois son code de caractère.
Exemple : donné -57
et A
en entrée, ce programme
9
9
99
99
serait sortie -57A
. En interne, la variable 9
aurait la valeur -513 et 99
la valeur 585.
Votre interprète peut supposer que les entrées sont toujours syntaxiquement valables.
4. Cession
Cette déclaration peut être arbitrairement longue. Il y a deux variables ou plus sur une ligne, séparées par des espaces:
V1 V2 V3 V4 V5 ...
Ceci assigne à la somme de tous les 'avec des indices pairs, moins la somme des ' avec des indices impairs (excluant ). Les assignations sont par valeur, pas par référence.V1
V
V
V1
Il pourrait être traduit dans la plupart des langues par .V1 = V2 - V3 + V4 - V5 + ...
Donc, s’il n’ya que deux variables, l’affectation normale est la suivante:
V1 V2
→ V1 = V2
S'il y en a trois, alors c'est une soustraction:
V1 V2 V3
→ V1 = V2 - V3
Et le signe +
/ -
continue à basculer avec chaque variable supplémentaire:
V1 V2 V3 V4
→ V1 = V2 - V3 + V4
Exemple : Ce programme afficherait 1110123
:
999 Prints triple-nine divided by nine (111).
999 9 9 Assigns triple-nine to zero (nine minus nine).
999 Prints triple-nine divided by nine (0)
9 999 9 Assigns single-nine to negative nine (zero minus nine).
999 999 9 Adds nine to triple-nine (really subtracts negative nine).
999 Prints triple-nine divided by nine (1).
999 999 9 Adds nine to triple-nine (really subtracts negative nine).
999 Prints triple-nine divided by nine (2).
999 999 9 Adds nine to triple-nine (really subtracts negative nine).
999 Prints triple-nine divided by nine (3).
5. Aller à (sauter si tout à zéro)
Cette déclaration peut aussi être arbitrairement longue. Il y a deux variables ou plus sur une ligne, séparées par des espaces, avec un espace de gauche :
V1 V2 V3 V4 V5 ...
Si certaines des valeurs sont non nulles, cela se comporte comme un non-op. Le pointeur d'instruction est déplacé vers la ligne suivante comme d'habitude.V1
Si toutes les valeurs sont égales à zéro, le pointeur d'instruction est déplacé vers le numéro de ligne . Les lignes sont indexées à zéro. Par conséquent, si la valeur est zéro, le pointeur se déplace vers la ligne supérieure. Le programme se termine (normalement, sans erreur) s'il est négatif ou supérieur à l'indice le plus élevé possible (nombre de lignes moins une).V1
V1
V1
V1
Notez que ce n'était pas divisé par 9 ici. Et comme il est impossible d'avoir une variable qui ne soit pas un multiple de 9, seuls les numéros de ligne qui sont des multiples de 9 peuvent être sautés.V1
Exemples:
Ce programme imprimera 1
pour toujours:
9 Prints single-nine divided by nine (always 1).
99 9 9 Assigns double-nine to zero.
99 99 Jumps to line zero (top line) if double-nine is zero.
Ce programme
99999999 Print G.
999 99 Set triple-nine to ninety-nine.
9999999999 9999999999 9999999999 99 99 9 9 999 999 Set 10-nine to zero.
99999999999 9999999999 Set 11-nine to zero.
999 Print triple-nine's value divided by nine. (This is the ninth line.)
99999999 Print G.
999 999 9 Subtract nine from triple-nine.
99999 999 Jump to line 5-nines if triple-nine is zero (ends program).
9 99999999999 9999999999 Jump to line nine if 10-nine and 11-nine are zero (always jumps).
affichera les nombres 11 à 1, par ordre décroissant, entourés de G
:
G11G10G9G8G7G6G5G4G3G2G1G
Détails supplémentaires
L'interpréteur idéal s'exécutera à partir de la ligne de commande avec le nom de fichier de programme 99 en tant qu'argument. Les E / S seront également effectuées à la volée dans la ligne de commande.
Cependant, vous pouvez simplement écrire une fonction interpréteur qui prend le programme sous forme de chaîne, ainsi qu'une liste des jetons d'entrée (par exemple ["-57", "A"]
). La fonction doit imprimer ou renvoyer la chaîne de sortie.
Des méthodes légèrement différentes d’exécution de l’interprète et de gestion des E / S conviennent si ces options sont impossibles dans votre langue.
Bonus: écrivez quelque chose de cool dans 99 et je le mettrai volontiers dans cet article à titre d'exemple.
- Voici un exemple d'un programme "99 Bouteilles de bière" de Mac's answer .
J'espère que vous avez apprécié mon 99ème défi! :RÉ
la source
Réponses:
CJam, 157 octets
Essayez-le en ligne:
Explication
Essayer de formater ceci avec l'indentation et les commentaires appropriés prendrait probablement une éternité, je vais donc vous donner un résumé algorithmique.
Le code est un bloc, l'analogue de CJam aux fonctions anonymes. Le bloc attend la chaîne de programme et la liste des entrées de la pile lors de son exécution.
L'initialisation comprend trois étapes. Tout d'abord, la liste de saisie est enregistrée. Ensuite, chaque caractère du programme qui n'a pas de sens est supprimé et le résultat est divisé en une liste de lignes et enregistré. Enfin, la liste de variables est initialisée. Cette liste mappe chaque variable, indexée par la longueur du nom, sur sa valeur divisée par 9 (une variable ne peut jamais contenir une valeur qui n'est pas un multiple de 9, et toutes les opérations sauf celle qui permet de tirer parti de cette modification). La liste est initialisée jusqu'à la longueur de la ligne la plus longue, ce qui correspond à la limite supérieure du nom le plus long présent. Il existe également un peu d'initialisation implicite due aux valeurs initiales des variables: le numéro de ligne est 0 et l'index d'entrée est -1.
L'interpréteur est implémenté comme on pourrait s'y attendre: une boucle qui lit la ligne suivante, incrémente le numéro de ligne et exécute la ligne pendant que le numéro de ligne pointe sur une ligne existante. L'analyse de ligne vérifie d'abord que la ligne n'est pas vide, puis branche en fonction de si l'arité est 1 ou> 1, puis en fonction de l'existence ou non d'un espace. Ces quatre branches imitent les quatre opérations (à l’exclusion des opérations sans opposition) de manière généralement simple, bien qu’elles jouent au golf de manière agressive comme tout le reste. L’une des optimisations de la note est peut-être que, puisqu’une séquence d’entrée valide doit toujours produire un élément de type attendu par le programme, j’ai omis de créer des observations séparées en fonction de la longueur du nom de la variable. On suppose simplement que l'élément lu dans la liste d'entrée est du type attendu.
la source
128%
par128,=
.Python 3,
421414410404388395401 octetsGolfé:
Ungolfed:
Presque juste une mise en œuvre littérale de la spécification, mise en échec aussi loin que je peux l’obtenir.
Exécutez à partir de la ligne de commande en fournissant un fichier de code source 99 comme seul argument (par exemple, le dernier exemple de l'OP):
En prime, voici une implémentation (plutôt médiocre) de "99 bouteilles" dans 99 : http://pastebin.com/nczmzkFs
la source
else
qu’après un numéro pourrait être supprimé, mais lorsque j’ai essayé plus tôt, j’ai eu une erreur de syntaxe. Vos autres conseils sont toutefois très appréciés!goto
routine et lors de l'obtention de la valeur par défaut de la variable). Pour un utilisateur de la langue, cela ne fait aucune différence.else
soi, juste l'espace avant. Par exemple3*n+1if n%2else n//2
.else
. Par exemple, j'ai essayé de remplacerprint(w if L(e)%2 else chr(w%128))
parprint(w if L(e)%2else chr(w%128))
et une exception de syntaxe a été obtenue.e
ouE
, et (d'après les commentaires), ni pour l'un0or
ni pour l' autre.Common Lisp,
1180857837836 octetsJe sais que cela ne va pas gagner, mais je me suis amusé à jouer au golf celui-ci. J'ai réussi à supprimer 343 octets, ce qui représente plus de deux interpréteurs 99 écrits en CJam.
Aussi, assez amusant, plus j'essaie de le compresser, plus je suis persuadé que pour Common Lisp, il est plus rapide de compiler le code que d'essayer de l'interpréter à la volée.
il y en a un
tagbody
pour effectuer 2 boucles:les variables locales sont déclarées dans
&aux
Ungolfed, commenté
Nous utilisons des entrées / sorties standard lors de l'évaluation, ce qui signifie que nous utilisons standard
read
et desprinc
fonctions. Par conséquent, le code résultant peut être rendu exécutable sur la ligne de commande, comme indiqué ci-dessous.Les entrées ne sont pas complètement correctement filtrées lors de l'exécution de 99 programmes: on suppose que l'utilisateur sait quel type de valeurs est attendu.
Le seul surcoût d' exécution possible peut survenir lors du saut, car nous devons évaluer la valeur d'une variable et faire correspondre cette valeur à une étiquette. Sauf que, l'interprète doit être assez efficace.
Basé sur l' obseravtion astucieuse de Mac, qui ne nécessite pas de division et de multiplication par 9 à chaque fois, la version actuelle parvient à ne jamais diviser ni multiplier par 9 lors de l'exécution.
Exemple
Si nous remplaçons
defmacro
pardefun
, nous voyons le code généré. Par exemple:Voici le code résultant:
Une fois exécuté, imprime "G11G10G9G8G7G6G5G4G3G2G1G"
Ligne de commande
Nous pouvons construire un exécutable en vidant un noyau et en spécifiant la
toplevel
fonction. Définissez un fichier nomméboot.lisp
où vous avez placé ledefmacro
, puis écrivez ce qui suit:En cours d'exécution
sbcl --load boot.lisp
donne la sortie suivante:Ensuite, exécutez le programme compilé 99 :
99 bouteilles
Si vous êtes intéressé, voici le code compilé pour le programme de 99 bouteilles écrit dans la réponse de Mac : http://pastebin.com/ZXe839CZ (il s'agit de l'ancienne version où nous avons
jmp
et desend
étiquettes, un lambda environnant et une arithmétique plus jolie).Voici une exécution avec la nouvelle version, pour prouver que cela fonctionne toujours: http://pastebin.com/raw.php?i=h73q58FN
la source
TI-84 Basic (Script de calculatrice),
376373377381 octetsSi elle fonctionne sur une calculatrice TI-84, vous pourrez l’utiliser pour un test standardisé… donc utile;)
Version minimale du système d'exploitation - 2.53MP (MathPrint) en raison de la somme sigma
Les instructions PS ASCII ne peuvent pas être suivies à la lettre, mais TI-Basic
:
est une nouvelle ligne. Ainsi, tous les sauts de ligne réels du code signifient que le:
ou#
au début de chaque ligne ne sont pas nécessaires. Les jetons de début:
et#
juste différencient les commentaires et le code.Décharge hexadécimale originale (376 octets)
Éditer # 1 - Optimisé 3 octets en utilisant l'observation de Mac Edits # 2 & # 3 - Correction de bugs repérés par Runer112.
la source
#
, pour les commentaires? (NB: les commentaires dans le code actuel sont implémentés sous la forme d'une ligne comportant uniquement une chaîne non fermée, qui enchaîne Ans.)Ans
entrée est écrasée, doncAns->Str0
sur la ligne 6 une erreur se produit, l'argument de longueur d'unesub()
commande peut être égal à zéro, ce qui entraîne une erreur;Ans
sur la ligne 11, il s'agira d'une chaîne de même queAns-J
l'erreur ... Et je n'ai regardé que la première moitié du programme.sub()
commande peut avoir une longueur de zéro et générer une erreur. Et une fois que lessub()
invocations sont corrigées, je crains que cela ne révèle plus de problèmes.9
est le nombre 9 et la valeur de la variable99
est le nombre 99, etc." Et des chaînes de longueur 0 peuvent être produites de différentes manières""
, mais c’est en quelque sorte un bug qu’aucune commande de manipulation de chaîne ne peut consommer ou produire une chaîne vide, y comprissub()
.C 426
458 481 497Edit Peut-être que je vais trop loin, mais cela fonctionne avec Visual C: stdio.h supprimé, en utilisant int au lieu de FILE * pour fopen et getc
Éditer 2 Réordonne l'étape d'exécution, plus d'encombrement, 32 caractères sauvegardés
Programme console autonome, nom du programme pris sur la ligne de commande et entrée / sortie via la console.
Ancien style K & R, type par défaut int pour les vars et paramètres globaux. En supposant que EOF soit défini sur -1 (comme dans chaque implémentation C que je connais)
Compile avec des avertissements avec Visual Studio 2010 (projet C ++ de la console Win32, compilation en tant que C) Compile sur Ideone, mais ne peut pas s'exécuter car il a besoin d'un fichier.
Lors de la première étape, le code source est lu et analysé, chaque ligne est stockée sous la forme d’une séquence d’entiers basée sur le nombre de 9. S'il y a un blanc au début, le premier nombre est négatif. Donc:
9 BLAH 99 9a9bb9c9
(9 99 9999
) devient-1,2,4
Il existe un raccourci - pas si légal: tous les codes ascii inférieurs à '' sont considérés comme des sauts de ligne.Dans cette étape, toutes les variables utilisées sont pré-initialisées.
L'étape d'exécution suit les spécifications, sans fioritures, enregistrez les numéros de stockage divisés par 9.
Code même plus lisible (j'espère), espaces et nouvelles lignes ajoutés
la source
Haskell, 550 octets
Exemple exécuté avec le programme "compte à rebours" stocké dans le fichier
i.99
Version non-golfée:
la source
JavaScript (ES6) 340
352Une fonction avec 2 paramètres
Le troisième paramètre facultatif (10k par défaut) est le nombre maximal d'itérations - je n'aime pas les programmes qui fonctionnent à l'infini
JSFiddle Pour tester
la source
q / k,
490469.
Le script est un mélange de q et k, donc d’abord, je définis quelques mots-clés q que je veux utiliser plusieurs fois dans k fonctions. (essentiellement des macros #define)
f
lit le fichier transmis au programme et supprime les caractères inutilesm
prend une liste / un vecteur et multiplie les indices impairs par -1b
est juste une fonction vide, utilisée pour les lignes sans opérationp
est la fonction d'impression.K
est une fonction qui examine une variable. Si la variable existe, elle la renvoie, sinon elle renvoie simplement le littéral.v
est la fonction d'affectation.g
est la fonction goto.r
prend une chaîne et décide quelle opération doit être appliquée.Et puis finalement, je viens de parcourir la
f
liste des chaînes, avecn
comme itérateur. La fonction goto sera misen
à jour si nécessaire.la source
Perl,
273 266 255 244238Les sauts de ligne ont été ajoutés pour plus de clarté.
Nom du programme pris en ligne de commande:
Chaque ligne du programme est convertie en code Perl, par exemple:
Plus de détails
la source