Le fil de défi des voleurs est ici .
Le défi de Cops: concevoir un langage de programmation qui semble inutilisable pour la programmation, mais admet le calcul (ou au moins l'achèvement de la tâche) via un mécanisme non évident.
Vous devriez concevoir un langage de programmation simple qui lit le code à partir d'un fichier d'entrée, puis fait ... quelque chose. Vous devez préparer un programme de solution qui trouve le 3ème plus grand nombre dans l'entrée lorsqu'il est exécuté dans votre interprète. Il faut que les voleurs aient le plus de difficulté possible pour trouver un programme de solution. Notez que les cambrioleurs peuvent publier n’importe quelle solution permettant d’accomplir cette tâche, pas seulement celle que vous aviez à l’esprit.
C'est un concours de popularité. L’objectif des flics est d’obtenir le plus de votes possible tout en survivant 8 jours après avoir posté l’interprète sans se faire craquer. À cette fin, les pratiques suivantes devraient aider:
- Expliquer avec précision la sémantique de votre langue
- Écrire du code lisible
Les tactiques suivantes sont fortement déconseillées:
- Utilisation du cryptage, des hachages ou d'autres méthodes cryptographiques. Si vous voyez une langue qui utilise le chiffrement RSA ou refuse d'exécuter un programme à moins que son hachage SHA-3 soit égal à 0x1936206392306, n'hésitez pas à voter par virement négatif.
Défi des voleurs: écrivez un programme qui trouve le troisième plus grand nombre entier dans l'entrée lorsqu'il est exécuté dans l'interpréteur des flics.
Celui-ci est relativement simple. Afin de déchiffrer une réponse d'un flic, vous devez créer un programme qui termine la tâche lorsqu'il est exécuté dans son interpréteur. Lorsque vous déchiffrez une réponse, postez un commentaire portant la mention "fissuré" dans la réponse du flic qui renvoie à votre message. Celui qui casse le plus de flics gagne le fil des voleurs.
Règles I / O
- Les interprètes doivent utiliser un nom de fichier sur la ligne de commande du programme et utiliser les entrées et les sorties standard lors de son exécution.
- Les données saisies seront unaires et composeront uniquement des caractères
0
et1
(48 et 49 en ASCII). Un nombre N est codé sous la forme N1s
suivi de a0
. Il y en a un0
avant la fin du fichier. Exemple: Pour la séquence (3, 3, 1, 14), l'entrée est11101110101111111111111100
. - L'entrée est garantie d'avoir au moins 3 chiffres. Tous les nombres sont des entiers positifs.
- La sortie sera jugée par le nombre de
1
s imprimés avant l’arrêt du programme. Les autres caractères sont ignorés.
Dans les exemples suivants, la première ligne correspond à l’entrée au format décimal; la seconde est l'entrée réelle du programme; le troisième est un exemple de sortie.
1, 1, 3
101011100
1
15, 18, 7, 2, 15, 12, 3, 1, 7, 17, 2, 13, 6, 8, 17, 7, 15, 11, 17, 2
111111111111111011111111111111111101111111011011111111111111101111111111110111010111111101111111111111111101101111111111111011111101111111101111111111111111101111111011111111111111101111111111101111111111111111101100
111111,ir23j11111111111u
247, 367, 863, 773, 808, 614, 2
<omitted>
<contains 773 1's>
Règles ennuyeuses pour les réponses des flics:
- Pour éviter la sécurité par obscurité, l'interprète doit être écrit dans un langage figurant dans le top 100 de cet index TIOBE et disposer d'un compilateur / interprète disponible gratuitement.
- L'interprète ne doit pas interpréter une langue qui a été publiée avant ce défi.
- L'interprète doit s'intégrer à votre message et ne pas être hébergé à l'extérieur.
- L'interprète doit être déterministe
- L'interprète doit être portable et respecter les normes de sa propre langue. n'utilisez pas de comportement indéfini ou de bugs
- Si le programme de solution est trop long pour tenir dans la réponse, vous devez poster un programme qui le génère.
- Le programme de solution ne doit comporter que des fichiers ASCII et des nouvelles lignes imprimables.
- Vous devez exécuter votre programme de solution en moins d'une heure sur votre propre ordinateur pour chacun des exemples de saisie ci-dessus.
- Le programme doit fonctionner pour tout nombre entier inférieur à 10 6 et tout nombre entier inférieur à 10 6 (pas nécessairement inférieur à une heure), à condition que la longueur totale en entrée soit inférieure à 10 9 .
- Pour être en sécurité, un flic doit modifier le programme de la solution dans la réponse au bout de 8 jours.
Notation
Le flic qui est en sécurité avec le score le plus élevé et un score positif remporte cette question.
Réponses:
Changeling (coffre-fort)
ShapeScript
ShapeScript est un langage de programmation naturel. Les changeurs de forme (ou Changelings , comme ils préfèrent être appelés) peuvent se transformer en un ensemble d'instructions leur permettant de traiter des données.
ShapeScript est un langage basé sur une pile avec une syntaxe relativement simple. Sans surprise, la plupart de ses fonctions intégrées traitent de la modification de la forme des cordes. Il est interprété, caractère par caractère, comme suit:
'
et"
commencez un littéral de chaîne.Jusqu'à ce que la citation correspondante soit trouvée dans le code source, tous les caractères entre ces citations correspondantes sont rassemblés dans une chaîne, qui est ensuite placée dans la pile.
0
pour9
pousser les entiers 0 à 9 sur la pile. Notez que10
pousse deux entiers.!
extrait une chaîne de la pile et tente de l'évaluer en tant que ShapeScript.?
extrait un entier de la pile et pousse une copie de l'élément de pile à cet index.L'index 0 correspond à l'élément de pile le plus haut (LIFO) et l'index -1 à l'élément le plus bas.
_
saute une itérable de la pile et pousse sa longueur.@
sort deux éléments de la pile et les pousse dans l’ordre inverse.$
enlève deux chaînes de la pile et divise la plus basse des occurrences de la plus haute. La liste résultante est poussée en retour.&
ouvre une chaîne (la plus haute) et une variable de la pile, puis la joint, en utilisant la chaîne comme séparateur. La chaîne résultante est poussée en retour.Si ShapeScript est utilisé sur notre planète, car pythons sont les parents les plus proches Changelings sur Terre, tous les autres caractères c pop deux points x et y (supérieure) de la pile, et de tenter d'évaluer le code Python
x c y
.Par exemple, la séquence de caractères est
23+
évaluée2+3
, tandis que la séquence de caractères est"one"3*
évaluée'one'*3
et la séquence de caractères est1''A
évaluée1A''
.Dans le dernier cas, le résultat n'étant pas valide en Python, Changeling se plaindrait de ce que sa forme actuelle n'est pas définie (erreur de syntaxe), car ce n'est pas ShapeScript valide.
Avant d'exécuter le code, l'interprète placera la totalité de l'entrée utilisateur sous la forme d'une chaîne sur la pile. Après avoir exécuté le code source, l’interprète imprimera tous les éléments de la pile. Si une partie entre les deux échoue, le Changeling se plaint que sa forme actuelle est inadéquate (erreur d'exécution).
Changement de forme
Dans leur état naturel, Changelings ne prend pas la forme de ShapeScript. Cependant, certains d'entre eux peuvent se transformer en un code source potentiel (qui n'est pas forcément utile ni même syntaxiquement valide).
Tous les changelings éligibles ont la forme naturelle suivante:
Toutes les lignes doivent avoir le même nombre de caractères.
Toutes les lignes doivent comporter des caractères ASCII imprimables, suivis d'un seul saut de ligne.
Le nombre de lignes doit correspondre au nombre de caractères imprimables par ligne.
Par exemple, la séquence d'octets
ab\ncd\n
est un Changeling éligible.Dans sa tentative de passer à ShapeScript, le Changeling subit la transformation suivante:
Au départ, il n'y a pas de code source.
Voici ce qui se passe pour chaque ligne:
L'accumulateur de Changeling est mis à zéro.
Pour chaque caractère c de la ligne (y compris le saut de ligne de fin), le point de code de c est divisé en deux par l'accumulateur, et le caractère Unicode correspondant au point de code résultant est ajouté au code source.
Ensuite, la différence entre le point de code de c et le point de code d'un espace (32) est ajoutée à l'accumulateur.
Si une partie de ce qui précède échoue, le Changeling se plaint que sa forme actuelle est désagréable.
Une fois toutes les lignes traitées, la transformation de Changeling en ShapeScript (valide, espérons-le) est terminée et le code obtenu est exécuté.
Solution (ShapeScript)
ShapeScript s’est avéré être tout à fait utilisable; il peut même effectuer des tests de primalité ( preuve ) et satisfait donc notre définition du langage de programmation.
J'ai republié ShapeScript sur GitHub , avec une syntaxe légèrement modifiée et de meilleures E / S.
Le code fait ce qui suit:
Solution (Changeling)
Comme tous les programmes Changeling, ce code a un retour à la ligne final.
ShapeScript commettra une erreur immédiate sur n'importe quel caractère s'il ne comprend pas, mais nous pouvons insérer des chaînes arbitraires en tant que charges et les extraire ultérieurement. Cela nous permet de ne mettre qu'une petite quantité de code sur chaque ligne (au début, où l'accumulateur est petit), suivie d'une ouverture
"
. Si nous commençons par la ligne suivante"#
, nous fermons et sautons la chaîne sans affecter le code réel.En outre, nous devons surmonter trois obstacles mineurs:
La longue chaîne dans le code ShapeScript est un simple jeton et nous ne pourrons pas l'ajuster sur une ligne.
Nous allons pousser cette chaîne en morceaux (
'@'
,'1?'
, etc.), que nous allons concaténer plus tard.Le point de code de
_
est assez élevé, et pousser'_'
sera problématique.Cependant, nous pourrons pousser
'_@'
sans effort, suivis par un autre'@'
pour annuler l'échange.Le code ShapeScript que notre Changeling va générer ressemble à ceci 1 :
J'ai trouvé le code Changeling en exécutant le code ShapeScript ci-dessus via ce convertisseur . 2
Interprète (Python 3)
1 Chaque ligne est complétée avec une quantité aléatoire de déchets, et les sauts de ligne ne sont pas réellement présents.
2 Les numéros du bas indiquent les points de code le plus bas et le plus haut du code de Changeling, qui doit rester compris entre 32 et 126.
la source
0"#002?'+'&'0'$'0?2?-@2?>*+00'&!++'1'*'0'+@1?$0?''&@_2-2?*@+@"3*!@#
. J'ai cependant renoncé à trouver un Changelin pour cela. Même entremêlés de déclarations pour la plupart inutiles, je n'ai pas réussi à obtenir plus de 20 octets.Shuffle (écrit en C ++), fissuré! par Martin
Edit Martin a craqué. Pour voir sa solution, cliquez sur le lien. Ma solution a également été ajoutée.
Edit Commande fixe
print-d
pour pouvoir gérer les registres et les piles. Comme il s'agit d'une commande de débogage non autorisée dans une solution, cela ne devrait affecter personne utilisant la version précédente de l'interpréteur.Je suis encore nouveau dans ce domaine, alors s'il y a quelque chose qui ne va pas dans ma réponse ou dans mon interprète, merci de me le faire savoir. S'il vous plaît demander des précisions si quelque chose n'est pas clair.
Je ne pense pas que ce sera trop difficile, mais j'espère que cela constituera un défi. Ce qui rend le mélange assez inutilisable, c'est qu'il n'imprimera que lorsque les choses seront à leur place.
-> Bases:
Il y a 24 piles, nous les appelons
stack1, ... stack24
. Ces piles vivent dans une liste. Au début de tout programme, ces piles sont mises à zéro et commencent à la place qui leur convient, c'est-à-dire que la pile i est à la iième position dans la liste (notez que nous indexerons à partir de 1, contrairement à C ++). Au cours d'un programme, l'ordre des piles dans la liste changera. Ceci est important pour des raisons qui seront expliquées lorsque je discuterai des commandes.Il y a 5 registres disponibles pour utilisation. Ils sont nommés
Alberto
,Gertrude
,Hans
,Leopold
,ShabbySam
. Chacun de ceux-ci est mis à zéro au début d'un programme.Ainsi, au début de tout programme, il y a 24 piles, chacune ayant son numéro correspondant à son index dans la liste des piles. Chaque pile a exactement un zéro en haut. Chacun des cinq registres est initialisé à zéro.
-> Commandes et syntaxe :
Il y a 13 commandes (+1 commande de débogage) disponibles dans Shuffle. Ils sont comme suit
cinpush
cette commande ne prend aucun argument. Il attend une entrée de ligne de commande de la manière décrite dans la question (toute autre entrée entraînera des résultats non spécifiés / non définis). Il divise ensuite la chaîne d'entrée en entiers, par exemple101011100
->1,1,3
. Pour chaque entrée reçue, il effectue les opérations suivantes: (1) permute la liste des piles en fonction de la valeur. Laissez la valeur entière en question être appelée un . Si a est inférieur à 10, il effectue la permutation u . Si a est compris entre 9 et 30 (non inclus), il effectue la permutation d . Sinon, il fait la permutation r . (2) Il pousse ensuite unsur la pile qui est en premier dans la liste. Notez que je ne veux pas direstack1
(bien que cela puisse être le cas quistack1
est en premier dans la liste). Les permutations sont définies ci-dessous. Depuiscinpush
est la seule façon d'obtenir l' entrée d'utilisateur , il doit apparaître dans toute solution.mov value register
Lamov
commande est essentiellement une affectation de variable. Il assignevalue
àregister
.value
peut prendre plusieurs formes: il peut s'agir (1) d' un entier, par exemple47
(2) du nom d'un registre différent, par exempleHans
(3) de l'index d'une pile suivi de "s", par exemple4s
. Notez qu'il s'agit de l'index dans la liste et non du numéro de la pile. En tant que tel, le nombre ne doit pas dépasser 24.Quelques
mov
exemples:movfs index register
Cela signifie "déplacer de la pile". C'est similaire à lamov
commande. Il existe pour que vous puissiez accéder à une pile indexée par un registre. Par exemple, si précédemment, vous définissez Hans sur 4 (mov 4 Hans
), vous pouvezmovfs Hans Gertrude
définir Gertrude sur le haut de la pile 4. Ce type de comportement n'est pas accessible simplement à l'aide demov
.inc register
augmente la valeur du registre de 1.dec register
diminue la valeur du registre de 1.compg value value register
Cela signifie «comparer plus grand». Le registre est égal à la plus grande des deux valeurs.value
peut être un entier, un registre ou un index de pile suivi de 's', comme ci-dessus.compl value value register
'compare less' comme ci-dessus, à l'exception de la valeur la plus petite.gte value1 value2 register
Vérifie sivalue1 >= value2
la valeur booléenne (telle que 1 ou 0) est ensuite placée dansregister
.POP!! index
apparaît en haut de la pile indexée parindex
dans la liste des piles.jmp label
saute inconditionnellement à l'étiquettelabel
. C'est un bon moment pour parler des étiquettes. Une étiquette est un mot suivi de ':'. L'interprète effectue une pré-analyse des étiquettes afin que vous puissiez passer à la fois aux étiquettes et inversement.jz value label
saute àlabel
sivalue
est zéro.jnz value label
saute àlabel
sivalue
est différent de zéro.Exemples d'étiquettes et de sauts:
"shuffle" permutation
Voici la commande de lecture aléatoire. Cela vous permet de permuter la liste des piles. Il y a trois permutations valides qui peuvent être utilisés comme arguments,l
,f
, etb
.print register
Ceci vérifie si toutes les piles sont dans leurs positions initiales, c'est-à-dire que la pile i est à l'index i dans la liste des piles. Si tel est le cas, il affiche la valeur àregister
unaire. Sinon, une mauvaise erreur est imprimée. Comme vous pouvez le constater, pour pouvoir générer quoi que ce soit, les piles doivent toutes se trouver aux bons endroits.done!
cela indique au programme de quitter sans erreur. Si le programme se termine sansdone!
, il imprimera sur la console le numéro au-dessus de chaque pile suivi du numéro de la pile. L'ordre dans lequel les piles sont imprimées correspond à l'ordre dans lequel elles apparaissent dans la liste des piles. Si une pile est vide, elle sera omise. Ce comportement est à des fins de débogage et ne peut pas être utilisé dans une solution.print-d value
Ceci affiche la valeur de la pile, du registre ou de l’entier donné (pour accéder à la pile i , passeris
en argument, comme expliqué ci-dessus). Il s’agit d’un outil de débogage qui ne fait pas partie du langage. En tant que tel, il n’est pas autorisé dans une solution.-> Voici le code de l'interprète
Tout l'analyse se passe dans la fonction principale. C'est ici que vous trouverez l'analyse de commandes spécifiques.
-> Permutations Les permutations permutent les éléments de la liste de pile de la manière suivante:
Où signifie que
(Celles-ci apparaissent également dans le code de l'interprète. En cas de divergence, l'interprète est correct.)
-> Exemple simple
Ces deux programmes simples impriment les nombres de 24 à 1 (unaire) sans espace.
ou
Ils sont le même programme.
Explication et solution:
Martin a également une bonne explication dans sa réponse .
Comme Martin l'a découvert, ce langage a été inspiré par le cube de poche (alias 2x2 Rubik's cube). Les 24 piles sont comme les 24 carrés individuels du cube. Les permutations sont les mouvements de base autorisés: haut, bas, droite, gauche, avant, arrière.
La principale difficulté ici est que, lorsque les valeurs sont poussées, seuls trois mouvements sont utilisés: haut, bas et droit. Cependant, vous n'avez pas accès à ces mouvements lorsque vous "mélangez" les piles. Vous n'avez que les trois autres mouvements.
Il s’avère que les deux séries de trois mouvements s’appliquent à l’ensemble du groupe (c’est-à-dire qu’il s’agit de générateurs), ce qui permet de résoudre le problème. Cela signifie que vous pouvez réellement résoudre n'importe quel cube de Rubik 2x2 en utilisant 3 des mouvements.
Tout ce qui reste à faire est de trouver comment annuler les mouvements haut, bas et droit en utilisant les trois autres. À cette fin, j'ai employé un système de calcul formel appelé GAP .
Après avoir annulé les permutations, trouver le troisième plus grand nombre est assez trivial.
la source
Brian & Chuck , fissuré par cardboard_box
Je suis intriguée depuis un certain temps par l’idée d’un langage de programmation dans lequel deux programmes interagissent (probablement inspiré de ROCB ). Ce défi était une bonne incitation à aborder enfin ce concept tout en essayant de garder le moins de langage possible. Les objectifs de conception étaient de rendre le langage Turing-complet, alors que chacune de ses parties ne le sont pas individuellement. En outre, même les deux ne devraient pas être complets avec Turing sans faire appel à la manipulation du code source. Je pense y être parvenu, mais je n’ai encore prouvé formellement aucune de ces choses. Alors sans plus tarder, je vous présente ...
Les protagonistes
Brian et Chuck sont deux programmes ressemblant à Brainfuck. Un seul d'entre eux est exécuté à un moment donné, à commencer par Brian. Le problème, c'est que la bande mémoire de Brian est également le code source de Chuck. Et la bande mémoire de Chuck est aussi le code source de Brian. En outre, la tête de lecture de Brian est également le pointeur d'instructions de Chuck et inversement. Les bandes sont semi-infinies (c'est-à-dire infinies à droite) et peuvent contenir des entiers signés de précision arbitraire, initialisés à zéro (sauf indication contraire du code source).
Le code source étant également une bande mémoire, les commandes sont définies techniquement par des valeurs entières, mais elles correspondent à des caractères raisonnables. Les commandes suivantes existent:
,
(44
): Lit un octet de STDIN dans la cellule de mémoire en cours. Seul Brian peut le faire. Cette commande est un non-op pour Chuck..
(46
): Écrivez la cellule de mémoire actuelle, modulo 256, sous forme d'octet dans STDOUT. Seul Chuck peut le faire. Cette commande est un non-op pour Brian.+
(43
): Incrémente la cellule de mémoire actuelle.-
(45
): Décrémente la cellule de mémoire actuelle.?
(63
): Si la cellule de mémoire actuelle est à zéro, il s'agit d'un no-op. Sinon, passez le contrôle à l'autre programme. La tête de la bande sur le programme qui utilise?
restera sur le?
. La tête de bande de l'autre programme déplacera une cellule vers la droite avant d'exécuter la première commande (de sorte que la cellule utilisée comme test n'est pas exécutée elle-même).<
(60
): Déplacez la tête de la cassette d'une cellule vers la gauche. Ceci est une opération impossible si la tête de la cassette est déjà à l'extrémité gauche de la bande.>
(62
): Déplacez la tête de la cassette d'une cellule vers la droite.{
(123
): Déplacez à plusieurs reprises la tête de la bande vers la gauche jusqu'à ce que la cellule actuelle atteigne zéro ou que l'extrémité gauche de la bande soit atteinte.}
(125
): Déplacez à plusieurs reprises la tête de la bande vers la droite jusqu'à ce que la cellule en cours devienne zéro.Le programme se termine lorsque le pointeur d'instructions du programme actif atteint un point où il n'y a plus d'instructions à sa droite.
Le code source
Le fichier source est traité comme suit:
```
, le fichier sera divisé en deux parties autour de la première occurrence de cette chaîne. Tous les espaces blancs de début et de fin sont supprimés et la première partie est utilisée comme code source pour Brian et la deuxième partie pour Chuck._
dans les deux programmes sont remplacées par des octets NULL.Par exemple, le fichier source suivant
Donnerait les bandes initiales suivantes:
L'interprète
L'interprète est écrit en rubis. Il faut deux indicateurs de ligne de commande qui ne doivent être utilisés par aucune solution (car ils ne font pas partie de la spécification de langue actuelle):
-d
: Avec ce drapeau, Brian et Chuck comprennent deux autres commandes.!
imprimera une représentation sous forme de chaîne des deux bandes de mémoire, le programme actif étant répertorié en premier (un^
marque les têtes de bande actuelles).@
fera également cela, mais mettra immédiatement fin au programme. Parce que je suis paresseux, aucune de ces méthodes ne fonctionne si elles sont la dernière commande du programme. Si vous souhaitez les utiliser ici, répétez-les ou écrivez un no-op à leur suite.-D
: Ceci est le mode de débogage détaillé. Il imprimera les mêmes informations de débogage!
qu'après chaque tick.@
fonctionne également dans ce mode.Voici le code:
Voici ma propre solution (manuscrite) au problème:
Ce code est exécutable tel quel, car toutes les annotations utilisent no-ops et sont ignorées par
{
et}
.L'idée de base est:
1
s, incrémentons cet élément.Quand on lit un
0
, fais un peu de ménage. Si le nombre résultant était supérieur à zéro, revenez à 1.Nous avons maintenant une liste des numéros saisis à la fin de la bande de Chuck et nous connaissons la longueur de la liste.
Soustrayez 2 de la longueur de la liste (pour que les étapes suivantes ignorent les deux éléments les plus grands), appelez ceci
N
.Pendant que
N > 0
, incrémentez un total cumulé, puis décrémentez tous les éléments de la liste. Chaque fois qu'un élément de la liste atteint zéro, décrémentezN
.A la fin de cela, le total en cours d' exécution contiendra le troisième plus grand nombre dans l'entrée,
M
.Ecrire des
M
copies de.
la fin de la bande de Chuck.1
cassette de Brian, puis exécutez celles générées.
à la fin.Après avoir terminé ceci, j'ai réalisé que je pouvais le simplifier beaucoup à certains endroits. Par exemple, au lieu de garder une trace de ce compteur et de l'écrire
.
sur la bande de Chuck, je pourrais simplement en imprimer un1
immédiatement, chaque fois avant de décrémenter tous les éléments de la liste. Cependant, apporter des modifications à ce code est assez pénible, car il propage d'autres modifications dans tous les sens, je ne me suis donc pas soucié d'apporter ces modifications.Le point intéressant est de savoir comment garder une trace de la liste et comment la parcourir. Vous ne pouvez pas simplement stocker les numéros dos à dos sur la bande de Chuck, car si vous voulez vérifier une condition sur l'un des éléments de la liste, vous risquez d'exécuter le reste de la liste qui pourrait contenir du code valide. Vous ne savez pas non plus combien de temps la liste sera longue, vous ne pouvez donc pas simplement réserver un espace devant le code de Chuck.
Le problème suivant est que nous devons quitter la liste pour la décrémenter
N
pendant que nous la traitons et que nous devons retourner au même endroit que nous étions auparavant. Mais{
et}
juste passer la liste complète.Nous devons donc écrire du code de manière dynamique sur Chuck. En fait, chaque élément de la liste
i
a la forme suivante:1
est un marqueur que nous pouvons mettre à zéro pour indiquer où nous en sommes restés au traitement de la liste. Son but est de rattraper{
ou}
qui ne fera que passer le code et lei
. Nous utilisons également cette valeur pour vérifier si nous sommes à la fin de la liste pendant le traitement. Par conséquent, si ce n’est pas le cas, ce sera le cas1
et le conditionnel?
basculera le contrôle sur Chuck.Code A
est utilisé pour gérer cette situation et déplacer l'IP sur Brian en conséquence.Maintenant, lorsque nous décrémentons,
i
nous devons vérifier sii
est déjà égal à zéro. Bien que ce ne soit pas le cas, nous?
allons encore changer de contrôle, il enCode B
est de même pour gérer cela.la source
HPR, écrit en Python 3 ( fissuré par TheNumberOne )
HPR (le nom ne veut rien dire) est un langage de traitement de listes d'entiers. Il est conçu pour être minimaliste , extrêmement limité et exempt de restrictions "artificielles" . Programmer en HPR est pénible, non pas parce que vous devez résoudre un casse-tête pour empêcher l'interprète de vous crier dessus, mais parce qu'il est difficile de faire en sorte qu'un programme fasse quelque chose d'utile. Je ne sais pas si HPR est capable de quoi que ce soit de beaucoup plus intéressant que de calculer le troisième plus gros élément d'une liste.
Spécification de la langue
Un programme HPR est exécuté dans un environnement , qui est un ensemble d’entiers non négatifs non négatifs et de listes d’entiers non négatifs. Initialement, l'environnement ne contient que la liste d'entrées (l'interpréteur les analyse pour vous). Il existe trois commandes et deux opérateurs de "flux de contrôle" modifiant l'environnement:
*
supprime le premier élément de chaque liste non vide de l'environnement et le place dans l'environnement. Les listes vides ne sont pas affectées. Par exemple, cela transforme-
décrémente tous les nombres de l’environnement, puis supprime les éléments négatifs. Par exemple, cela transforme$
fait pivoter chaque liste de l'environnement d'un pas vers la gauche. Par exemple, cela transforme!(A)(B)
, oùA
etB
sont des programmes, est fondamentalement unewhile
boucle. Il exécute "l'action"A
jusqu'à ce que le "test"B
donne un environnement vide. Cela peut produire une boucle infinie.#(A)(B)
, oùA
etB
sont des programmes, s’appliquentA
etB
à l’environnement actuel et prend la différence symétrique des résultats.Les commandes sont exécutées de gauche à droite. A la fin, la taille de l'environnement est imprimée en unaire.
L'interprète
Cet interpréteur comporte la commande debug
?
, qui affiche l' environnement sans le modifier. Il ne devrait apparaître dans aucune solution à la tâche. Tous les caractères sauf*-$!#()?
sont simplement ignorés, vous pouvez donc écrire des commentaires directement dans le code. Enfin, l'interprète reconnaît l'idiome!(A)(#(A)())
comme "exécuterA
jusqu'à ce que le résultat ne change plus" et l'optimise pour une vitesse supplémentaire (j'en avais besoin pour que ma solution se termine en moins d'une heure sur le dernier cas de test).Ma solution
Ma solution de référence est longue de 484 octets, donc assez courte par rapport au programme de 3271 octets de TheNumberOne. Ceci est probablement dû au système de macros sophistiqué et impressionnant développé par TheNumberOne pour la programmation en HPR. L'idée principale dans nos deux programmes est similaire:
Toutefois, pour autant que je sache, les détails de la mise en œuvre exacte sont assez différents. Voici ma solution:
Et voici le programme Python commenté qui le produit (rien d'extraordinaire ici, juste une manipulation de base des chaînes pour se débarrasser de toutes les répétitions):
la source
TKDYNS (Pour tuer le dragon, vous avez besoin d'une épée) - Cracked by Martin Büttner
EDIT: J'ai ajouté ma solution et explication ci-dessous le post principal.
Contexte
Dans cette langue, vous prenez le contrôle d'un vaillant guerrier qui a été chargé de tuer un terrible dragon. Le dragon vit dans un labyrinthe souterrain, plein de périls et de dangers, et jusqu'à présent, personne n'a été capable de le cartographier et de survivre. Cela signifie que vous devez vous diriger vers le dragon dans l'obscurité, sans autre intuition et courage que de vous guider.
...
Pas tout à fait. Vous avez apporté une quantité presque illimitée de sbires jetables avec vous et ils sont prêts à vous devancer pour découvrir la voie sûre. Malheureusement, elles sont toutes aussi épaisses que deux planches courtes et ne feront que ce que vous leur dites. C’est à vous de trouver une méthode astucieuse pour que vos sbires découvrent le bon chemin.
Quelques détails supplémentaires
Le repaire du dragon se présente sous la forme d'une grille 10x10. Entre certains points adjacents de la grille, il y a une passerelle étroite; entre les autres, il y a un gouffre profond et une mort certaine. Un exemple de mise en page pour une grille 4x4 pourrait être le suivant:
Vous savez qu'il existe toujours un moyen d'aller d'un point à un autre, mais rien de plus que cela ne vous a été révélé.
Pour réussir à vaincre le dragon, vous devez d’abord rassembler des objets que vous pourrez combiner pour créer une lame magique qui tue les dragons. De manière pratique, toutes les pièces de cette arme ont été dispersées dans le repaire du dragon. Vous devez simplement les collecter.
Le problème, c’est que chaque pièce de l’arme a été piégée. À chaque collecte, la disposition des allées change. Des chemins auparavant sûrs pourraient maintenant mener à une mort certaine et vice-versa.
Les commandes
Il n'y a que 5 commandes valides.
<
- Faites un pas à gauche>
- Faites un pas à droite^
- Faites un pas en avantv
- Faites un pas en basc
- Ramassez tous les objets qui traînent à votre position actuelle. S'il y avait des éléments présents, la disposition du repaire change. Avec les positions numérotées en rangées comme ci-dessus, prenez votre position modulo 10. Il existe 10 mises en page codées en dur dans l'interpréteur, et la mise en page devient la mise en page correspondante. Par exemple, si vous êtes en position 13, la mise en page devient:layouts[3]
Les présentations telles qu'elles apparaissent dans l'interpètre ont été codées en entiers de la manière suivante:
La disposition vide est codée à zéro.
Pour chaque bord de la mise en page, prenons
x
la plus petite des deux positions qu’elle joint.Si le pas est horizontal, ajoutez
2^(2*x)
à l'encodage (c'est puissant, pas XOR)Si le pas est vertical, ajoutez
2^(2*x + 1)
à l'encodage.Flux d'exécution
L'interpréteur est exécuté avec le nom d'un fichier source en tant qu'argument de ligne de commande.
Lorsque l’interprète est exécuté, l’utilisateur est invité à fournir une quête. Cette entrée doit être sous la forme décrite dans la question et déterminer les emplacements dans le repaire des composants de l'arme. Plus précisément, chaque entier entré est pris modulo 100 et placé à l'emplacement correspondant dans le repaire.
Chaque programme source est composé de plusieurs lignes, chaque ligne étant composée d’une séquence des 5 caractères valides ci-dessus. Ces lignes représentent vos sbires. Vous, le guerrier, suivez une séquence d'actions connues pour être sûres. Au début, vous ne savez rien du repaire, cette séquence est donc vide. En prenant chaque séide à tour de rôle, on procède comme suit, à partir de la position 0:
Le séide est chargé d'exécuter toutes les actions connues pour être sûres, suivies des actions dans sa propre ligne de code.
Si le séide meurt à un moment donné, vous en êtes averti et le repaire rétablit sa configuration initiale. Tous les articles sont remplacés et les allées reprennent leur position de départ.
Si, à la place, le séide survit, vous le vaporisez quand même - ce n'est qu'un séide, après tout. Comme auparavant, cela déclenche la réinitialisation du repaire à son état initial, mais cette fois-ci, vous ajoutez les actions de la ligne de code du séide à la séquence d'actions connues pour être sûres.
Une fois que tous les sbires ont été épuisés, vous, le guerrier, effectuez toutes les actions connues pour être sûres, toujours à partir de la position 0. Deux résultats sont possibles:
Vous collectez toutes les pièces de l'arme - dans ce cas, vous réussissez à tuer le dragon et un message de victoire excitant est émis. Ce message de victoire contiendra, parmi d'autres caractères,
n
ceux où,n
est le troisième plus grand nombre fourni en entrée.Vous n'avez pas réussi à récupérer certaines pièces de l'arme. Dans ce cas, le dragon continue à vivre et votre quête a échoué.
Code interprète (Python 2)
Bonne chance, vaillant guerrier.
Ma solution et explication
Voici un script Python qui génère du code source pour résoudre le problème. À titre d’intérêt, le code source final de Martin est environ 5 fois plus petit que le code produit par mon script. D'autre part, mon script pour générer le code est environ 15 fois plus petit que le programme Mathematica de Martin ...
Structure basique
Cela génère 990 lignes de code source, regroupées par groupe de 10. Les 10 premières lignes contiennent toutes des instructions qui tentent de déplacer un séide de position
0
en position1
, puis de collecter un élément - un ensemble pour chaque mise en page possible. Les 10 lignes suivantes contiennent toutes des instructions qui tentent de déplacer un séide de position1
en position2
, puis de récupérer un objet. Et ainsi de suite ... Ces chemins sont calculés avec lapath
fonction dans le script - il effectue simplement une recherche en profondeur d'abord.Si nous pouvons nous assurer que, dans chaque groupe de 10, précisément un séide réussit, nous aurons résolu le problème.
Le problème avec l'approche
Il se peut que pas exactement un sous-marin du groupe des 10 réussisse - par exemple, un séide conçu pour passer d’une position
0
à une autre1
pourrait accidentellement réussir à passer d’une position1
à une autre2
(en raison des similitudes dans les dispositions), et que les erreurs de calcul se propagent, entraînant potentiellement une défaillance.Comment le réparer
Le correctif que j'ai utilisé était le suivant:
Pour chaque séide qui essaie de se déplacer de position
n
en positionn+1
, faites-le d'abord marcher de positionn
en position0
(le coin supérieur gauche) et inversement, puis de positionn
en position99
(le coin inférieur droit), et inversement. Ces instructions ne peuvent être exécutées en toute sécurité que depuis une positionn
. Toute autre position de départ et le séide marchera sur le bord.Ces instructions supplémentaires empêchent donc les sbires d’aller accidentellement aux sbires où ils ne sont pas censés aller, ce qui garantit qu’un séide de chaque groupe de 10 réussit. Notez que ce n'est pas nécessairement le séide que vous attendez - il se peut que le séide qui pense être dans la disposition 0 réussisse, même si nous sommes vraiment dans la disposition 7 - mais dans tous les cas, le fait maintenant changé de position signifie que tous les autres membres du groupe mourront nécessairement. Ces étapes supplémentaires sont calculées par la
assert_at
fonction, quisafe_path
retourne un chemin qui est la concaténation de ces étapes supplémentaires avec le chemin ordinaire.la source
Firetype, fissuré par Martin Büttner
Un mélange vraiment étrange de BF et CJam. Et qui sait quoi d'autre! Je suis sûr que ce sera facile, mais c'était amusant quand même. Pour votre information, le nom fait référence à Vermillion Fire de Final Fantasy Type-0 .
REMARQUE : Veuillez me pardonner pour toute ambiguïté dans cette description. Je ne suis pas le meilleur écrivain ...: O
Martin a craqué ça très vite! C'était mon programme original pour résoudre le problème:
Syntaxe
Un script Firetype est essentiellement une liste de lignes. Le premier caractère de chaque ligne est la commande à exécuter. Les lignes vides sont essentiellement des NOP.
Sémantique
Vous avez un tableau d'entiers et un pointeur (pensez BF). Vous pouvez déplacer les éléments à gauche et à droite ou "pousser" des éléments sur le tableau.
Poussant
Lorsque vous "poussez" un élément et que vous êtes à la fin du tableau, un élément supplémentaire sera ajouté à la fin. Si vous n'êtes pas à la fin, l'élément suivant sera remplacé. Quoi qu'il en soit, le pointeur sera toujours incrémenté.
Les commandes
_
Poussez un zéro sur le tableau.
+
Incrémenter l'élément au pointeur actuel.
-
Décrémente l'élément au pointeur actuel.
*
Doublez l'élément au pointeur actuel.
/
Réduisez de moitié l'élément au pointeur actuel.
%
Prenez l'élément au pointeur actuel et avancez de plusieurs lignes, puis déplacez le pointeur vers la gauche. Si la valeur est négative, sautez à la place.
=
Prenez l'élément au pointeur actuel et passez à la ligne + 1. Par exemple, si l'élément en cours est
0
, cela passera à la ligne1
. Cela déplace également le pointeur vers la gauche.,
Lire un caractère de l’entrée standard et indiquer sa valeur ASCII.
^
Prenez l'élément au niveau du pointeur actuel, interprétez-le comme la valeur ASCII d'un caractère et convertissez-le en entier. Par exemple, si la valeur actuelle est
49
(la valeur ASCII de1
), l'élément du pointeur actuel sera défini sur l'entier1
..
Écrivez le numéro actuel à l'écran.
!
Prenez l'élément au pointeur actuel et répétez la ligne suivante à plusieurs reprises. Déplace également le pointeur vers la gauche.
<
Déplacez le pointeur à gauche. Si vous êtes déjà au début, une erreur est générée.
>
Déplacez le pointeur vers la droite. Si vous êtes déjà à la fin, une erreur est générée.
~
Si l'élément en cours est différent de zéro, remplacez-le par
0
; sinon, remplacez-le par1
.|
Place l'élément actuel.
@
Définissez l'élément actuel sur la longueur du tableau.
`
Dupliquer l'élément actuel.
\
Triez les éléments devant et avant le pointeur.
#
Annulez l'élément actuel.
L'interprète
Aussi disponible chez Github .
la source
self.ptr-1
pour l'accès, vous devriez probablementself.ptr>0
ne pas vérifier>=0
. (Cela ne devrait pas invalider les programmes valides, mais certains programmes pourraient travailler accidentellement, ce qui ne devrait pas être le cas.)=
définit la valeurarray() - 1
, la documentation dit+1
?Acc !! (sûr)
C'est baack ...
... et,
espérons-le,définitivement plus résistant aux échappatoires.J'ai déjà lu les Acc! spec. Comment va Acc !! différent?
En Acc !! , les variables de boucle sortent de la portée lorsque la boucle se ferme. Vous ne pouvez les utiliser que dans la boucle. À l'extérieur, vous obtiendrez une erreur "le nom n'est pas défini". Autre que ce changement, les langues sont identiques.
Les déclarations
Les commandes sont analysées ligne par ligne. Il existe trois types de commande:
Count <var> while <cond>
Compte
<var>
à partir de 0 tant que<cond>
non nul, équivalent à C ++for(int <var>=0; <cond>; <var>++)
. Le compteur de boucle peut être n'importe quelle lettre minuscule. La condition peut être n'importe quelle expression, n'impliquant pas nécessairement la variable de boucle. La boucle s'arrête lorsque la valeur de la condition devient 0.Les boucles nécessitent des accolades à la K & R (en particulier la variante Stroustrup ):
Comme mentionné ci-dessus, les variables de boucle ne sont disponibles que dans leurs boucles ; tenter de les référencer par la suite provoque une erreur.
Write <charcode>
Renvoie un seul caractère avec la valeur ASCII / Unicode donnée sur stdout. Le charcode peut être n'importe quelle expression.
Toute expression indépendante est évaluée et attribuée à l'accumulateur (qui est accessible en tant que
_
). Ainsi, par exemple,3
est une déclaration qui définit l'accumulateur sur 3;_ + 1
incrémente l'accumulateur; et_ * N
lit un caractère et multiplie l'accumulateur par son charcode.Remarque: l'accumulateur est la seule variable pouvant être affectée directement. variables de boucle et
N
peut être utilisé dans les calculs mais pas modifié.L'accumulateur est initialement 0.
Expressions
Une expression peut inclure des littéraux entiers, des variables de boucle (
a-z
),_
pour l'accumulateur, ainsi que la valeur spécialeN
, qui lit un caractère et passe à son code de caractère chaque fois qu'il est utilisé. Remarque: cela signifie que vous ne pouvez lire qu'un seul coup par personnage; la prochaine fois que vous utiliserezN
, vous lirez le prochain.Les opérateurs sont:
+
, une addition-
, soustraction; négation unaire*
, multiplication/
, division entière%
, modulo^
, exponentiationLes parenthèses peuvent être utilisées pour imposer la priorité des opérations. Tout autre caractère dans une expression est une erreur de syntaxe.
Espaces et commentaires
Les espaces et les lignes vides sont ignorés. Les espaces blancs dans les en-têtes de boucle doivent être exactement comme indiqué, avec un seul espace entre l'en-tête de la boucle et l'accolade ouverte également. Les espaces dans les expressions sont facultatifs.
#
commence un commentaire d'une seule ligne.Entrée sortie
Acc !! attend une seule ligne de caractères en entrée. Chaque caractère saisi peut être extrait en séquence et son code de caractères traité
N
. Essayer de lire après le dernier caractère de la ligne provoque une erreur. Un caractère peut être généré en transmettant son charcode à l'Write
instruction.Interprète
L'interprète (écrit en Python 3) traduit Acc !! code en Python et
exec
c'est tout.Solution
La chute de l'original Acc! étaient des variables de boucle qui restaient accessibles en dehors de leurs boucles. Cela a permis d’enregistrer des copies de l’accumulateur, ce qui a rendu la solution beaucoup trop facile.
Ici, sans ce trou de boucle (désolé), nous n’avons que l’accumulateur pour stocker des données. Pour résoudre cette tâche, nous devons toutefois stocker quatre valeurs arbitrairement grandes. 1 La solution: entrelacez leurs bits et stockez le numéro de combinaison obtenu dans l'accumulateur. Par exemple, une valeur d'accumulateur de 6437 stockerait les données suivantes (en utilisant le bit de poids faible comme indicateur à un bit):
Nous pouvons accéder à n’importe quel bit d’un nombre quelconque en divisant l’accumulateur par la puissance appropriée de 2, mod 2. Ceci permet également de définir ou de retourner des bits individuels.
Au niveau macro, l'algorithme boucle sur les nombres unaires de l'entrée. Il lit une valeur dans le nombre 0, puis effectue une passe de l'algorithme de tri à bulles pour le placer dans la position appropriée par rapport aux trois autres nombres. Enfin, il supprime la valeur qui reste dans le nombre 0, car il s’agit du plus petit des quatre et ne peut jamais être le troisième. Lorsque la boucle est terminée, le numéro 1 est le troisième plus grand. Nous ignorons donc les autres et les sortons.
La partie la plus difficile (et la raison pour laquelle j'avais des variables globales de boucle dans la première incarnation) consiste à comparer deux nombres pour savoir s'il faut les échanger. Pour comparer deux bits, nous pouvons transformer une table de vérité en une expression mathématique; ma percée pour Acc !! Nous avons trouvé un algorithme de comparaison allant des bits de poids faible aux bits de poids fort, car sans variables globales, il est impossible de parcourir en boucle les bits d’un nombre de gauche à droite. Le bit de poids faible de l'accumulateur stocke un indicateur qui indique s'il faut échanger les deux nombres actuellement à l'étude.
Je soupçonne que Acc !! Turing-complete, mais je ne suis pas sûr de vouloir prendre la peine de le prouver.
Voici ma solution avec des commentaires:
1 Selon la spécification de la question, seules les valeurs inférieures à 1 million doivent être prises en charge. Je suis heureux que personne n’en ait profité pour trouver une solution plus facile, même si je ne suis pas tout à fait sûr de savoir comment vous feriez les comparaisons.
la source
Picofuck (sûr)
Picofuck est similaire à Smallfuck . Il fonctionne sur une bande binaire qui est non liée à droite et liée à gauche. Il a les commandes suivantes:
>
déplace le pointeur vers la droite<
déplacez le pointeur à gauche. Si le pointeur tombe de la bande, le programme se termine.*
retourner le bit au pointeur(
si le point au pointeur est0
, saute au suivant)
)
ne faites rien - les parenthèses dans Picofuck sont desif
blocs, pas deswhile
boucles..
écrivez sur stdout le bit au pointeur en tant qu'ascii0
ou1
.,
lire à partir de stdin jusqu'à ce que nous rencontrions un0
ou1
, et stocker cela dans le bit au pointeur.Le code Picofuck se termine - une fois que la fin du programme est atteinte, elle continue depuis le début.
De plus, Picofuck interdit les parenthèses imbriquées. Les parenthèses apparaissant dans un programme Picofuck doivent alterner entre
(
et)
, en commençant par(
et en terminant par)
.Interprète
Écrit en Python 2.7
usage:
python picofuck.py <source_file>
Solution
Le programme python 2.7 suivant présente ma solution, que vous pouvez trouver ici.
Je pourrai éditer ce post plus tard avec une explication plus détaillée de la façon dont cela fonctionne, mais il s'avère que Picofuck est Turing-complete.
la source
PQRS - Safe! / Solution fournie
Les bases
Toutes les instructions impliquées ont quatre opérandes d'adresse de mémoire:
Où
v
est la taille de la mémoire dans les quatuors.Pᵢ
,Qᵢ
,Rᵢ
,Sᵢ
Sont signés entiers dans la taille native de votre machine (par exemple 16, 32 ou 64 bits) que nous appellerons mots.Pour chaque quartet
i
, l'opération implicite, avec[]
indication d'indirection, est la suivante:Notez que Subleq est un sous-ensemble de PQRS .
Subleq a été prouvé complet, donc PQRS devrait l'être aussi!
Structure du programme
PQRS définit un en-tête initial comme suit:
H₀ H₁ H₂ H₃
est toujours la première instructionP₀ Q₀ R₀ S₀
.H₀
avoirH₃
besoin d'être défini au moment du chargement.PQRS a des E / S rudimentaires, mais suffisantes pour le challenge.
H₄ H₅
: au démarrage du programme, il lit un maximum deH₅
caractères ASCII à partir de l'entrée standard et enregistre les mots àH₄
partir de l' index .H₄
etH₅
doivent être définis au moment du chargement. Après la lecture,H₅
sera défini sur le nombre de caractères lus (et mots sauvegardés).H₆ H₇
: à la fin du programme, à partir de l'indexH₆
, il affiche tous les octets contenant lesH₇
mots à la sortie standard en caractères ASCII.H₆
etH₇
doivent être définis avant la fin du programme. Les octets nuls'\0'
dans la sortie seront ignorés.Résiliation
La résiliation est obtenue en établissant
Sᵢ
des limitesi < 0
oui ≥ v
.Des trucs
Il
Pᵢ Qᵢ Rᵢ Sᵢ
n'est pas nécessaire que les quatuors soient alignés ou séquentiels, des ramifications sont autorisées à des intervalles inférieurs au quartet.PQRS étant indirectionnel, contrairement à Subleq, la flexibilité est suffisante pour implémenter des sous-programmes.
Le code peut être auto-modifiable!
Interprète
L'interprète est écrit en C:
Pour l'utiliser, enregistrez ce qui précède sous pqrs.c puis compilez:
Exemple de programme
Les échos peuvent contenir jusqu'à 40 caractères, précédés de «PQRS-».
Pour exécuter, enregistrez ce qui précède sous
echo.pqrs
, puis:Exécuter les cas de test:
Tous les scénarios de test fonctionnent extrêmement rapidement, par exemple <500 ms.
Le défi
Le PQRS pouvant être considéré comme stable, le défi commence le 2015-10-31 13:00 et se termine le 2015-11-08 13:00, au format UTC.
Bonne chance!
Solution
Le langage est assez similaire à celui utilisé dans "Baby" - le premier appareil numérique électronique à programme enregistré au monde. Sur cette page se trouve un programme permettant de trouver le facteur le plus élevé d’un entier en moins de 32 mots de mémoire (CRT!)!
J'ai trouvé que l'écriture de la solution conformément aux spécifications n'était pas compatible avec le système d'exploitation et la machine que j'utilisais (un dérivé de Linux Ubuntu sur un matériel légèrement plus ancien). Il demandait simplement plus de mémoire que disponible et une sauvegarde de base. Sur les systèmes d'exploitation dotés d'une gestion avancée de la mémoire virtuelle ou sur des machines disposant d'au moins 8 Go de mémoire, vous pouvez probablement exécuter la solution selon les spécifications. J'ai fourni les deux solutions.
Il est très difficile de coder directement dans PQRS , ce qui revient à écrire du langage machine, peut-être même du microcode. Au lieu de cela, il est plus facile d’écrire dans une sorte de langage assembleur que de le "compiler". Vous trouverez ci-dessous un langage d'assemblage annoté pour la solution optimisée pour l'exécution des scénarios de test:
Ce qu'il fait est d'analyser l'entrée en convertissant unaire en binaire, puis un tri en bulle sur les nombres avec les valeurs dans l'ordre décroissant, puis finalement la troisième valeur la plus grande en convertissant le binaire en unaire.
Notez que
INC
(incrément) est négatif etDEC
(décrément) est positif! Où il utiliseL#
ouL#+1
asP-
ouQ-OP
s, ce qui se passe, c'est qu'il met à jour les pointeurs: incrémentation, décrémentation, permutation, etc. L'assembleur a été compilé à la main dans PQRS en substituant les étiquettes aux décalages. Voici la solution optimisée PQRS :Le code ci-dessus peut être enregistré
challenge-optimized.pqrs
pour exécuter les cas de test.Pour être complet, voici la source par spécifications:
Et solution:
Pour exécuter ce qui précède, vous aurez besoin de commenter
#define OPTIMIZED
et ajouter#define PER_SPECS
danspqrs.c
et recompiler.C'était un grand défi - j'ai vraiment apprécié l'entraînement mental! M'a ramené à mes vieux jours d'assembleur 6502 ...
Si je devais implémenter PQRS en tant que «vrai» langage de programmation, j'ajouterais probablement des modes supplémentaires pour l'accès direct et doublement indirect, en plus de l'accès indirect, ainsi que de la position relative et de la position absolue, tous deux avec des options d'accès indirect pour la branche!
la source
Zinc, fissuré! par @Zgarb
Egalement disponible sur GitHub .
Vous avez besoin de Dart 1.12 et Pub. Il suffit de lancer
pub get
pour télécharger la seule dépendance, une bibliothèque d'analyse.En espérant que cela dure plus de 30 minutes! : O
La langue
Le zinc est axé sur la redéfinition des opérateurs. Vous pouvez facilement redéfinir tous les opérateurs de la langue!
La structure d'un programme de zinc typique ressemble à ceci:
Il n'y a que deux types de données: les entiers et les ensembles. Il n'existe pas de littéral d'ensemble, et les ensembles vides sont interdits.
Expressions
Les expressions suivantes sont valides dans le zinc:
Littéraux
Le zinc prend en charge tous les littéraux entiers normaux, comme
1
et-2
.Variables
Le zinc a des variables (comme la plupart des langues). Pour les référencer, utilisez simplement le nom. Encore comme la plupart des langues!
Cependant, il existe une variable spéciale appelée
S
qui se comporte un peu comme celle de PythQ
. Lorsque vous l'utilisez pour la première fois, il lit une ligne à partir d'une entrée standard et l'interprète comme un ensemble de chiffres. Par exemple, la ligne d’entrée1234231
deviendrait l’ensemble{1, 2, 3, 4, 3, 2, 1}
.NOTE IMPORTANTE!!! Dans certains cas, un littéral à la fin d'une substitution d'opérateur est analysé de manière incorrecte. Vous devez donc l'entourer de parenthèses.
Opérations binaires
Les opérations binaires suivantes sont supportées:
+
:1+1
.-
:1-1
.*
:2*2
./
:4/2
.=
:3=3
.De plus, l'opération unaire suivante est également prise en charge:
#
:#x
.La préséance est toujours droite associative. Vous pouvez utiliser des parenthèses pour remplacer ceci.
Seules l'égalité et la longueur travaillent sur les décors. Lorsque vous essayez d'obtenir la longueur d'un entier, vous obtenez le nombre de chiffres dans sa représentation sous forme de chaîne.
Compréhension d'ensemble
Afin de manipuler les ensembles, le zinc a des compréhensions définies. Ils ressemblent à ceci:
Une clause est une clause When ou une clause Sort.
Une clause quand ressemble
^<expression>
. L'expression qui suit le curseur doit donner un entier. L'utilisation de la clause when ne prend que les éléments de l'ensemble pour lesquelsexpression
est non nul. Dans l'expression, la variable_
sera définie sur l'index actuel de l'ensemble. C'est à peu près équivalent à ce Python:Une clause de tri , qui ressemble à
$<expression>
, trie l'ensemble décroissant par la valeur de<expression>
. C'est égal à ce Python:Voici quelques exemples de compréhension:
Ne prenez que les éléments de jeu
s
égaux à 5:Triez l'ensemble
s
par la valeur si ses éléments sont carrés:Les dérogations
Les remplacements d’opérateurs vous permettent de redéfinir les opérateurs. Ils ressemblent à ceci:
ou:
Dans le premier cas, vous pouvez définir un opérateur égal à un autre opérateur. Par exemple, je peux définir
+
de soustraire réellement via:En faisant cela, vous pouvez redéfinir un opérateur en opérateur magique . Il y a deux opérateurs de magie:
join
prend un ensemble et un entier et joint le contenu de cet ensemble. Par exemple, rejoindre{1, 2, 3}
avec4
donnera le nombre entier14243
.cut
prend également un ensemble et un entier et le partitionnera à chaque occurrence de cet entier. Utilisercut
sur{1, 3, 9, 4, 3, 2}
et3
créera{{1}, {9, 4}, {2}}
... MAIS tous les ensembles à élément unique sont aplatis, le résultat sera donc réel{1, {9, 4}, 2}
.Voici un exemple qui redéfinit l'
+
opérateur comme suitjoin
:Dans ce dernier cas, vous pouvez redéfinir un opérateur à l'expression donnée. À titre d'exemple, cela définit l'opération plus d'ajouter les valeurs, puis d'ajouter 1:
Mais quoi
+:
? Vous pouvez ajouter les deux points:
à un opérateur pour toujours utiliser la version intégrée. Cet exemple utilise le+
via intégré+:
pour additionner les nombres, puis ajoute un 1 (rappelez-vous que tout est associatif à droite).Remplacer l'opérateur de longueur ressemble un peu à:
Notez que presque toutes les opérations internes (à l'exception de l'égalité) utiliseront cet opérateur de longueur pour déterminer la longueur de l'ensemble. Si vous l'avez défini comme étant:
chaque partie du zinc qui fonctionne sur des ensembles sauf
=
n'agit que sur le premier élément de l'ensemble qui lui a été attribué.Plusieurs substitutions
Vous pouvez remplacer plusieurs opérateurs en les séparant par des virgules:
Impression
Vous ne pouvez rien imprimer directement dans le zinc. Le résultat de l'expression suivante
in
sera imprimé. Les valeurs d'un ensemble seront concaténées avec séparateur. Par exemple, prenez ceci:Si
expr
est défini{1, 3, {2, 4}}
,1324
sera imprimé à l'écran une fois le programme terminé.Mettre tous ensemble
Voici un programme de zinc simple qui semble s’ajouter
2+2
mais qui donne 5 comme résultat:L'interprète
Cela va dans
bin/zinc.dart
:Et cela entre
pubspec.yaml
:Solution envisagée
la source
join
un ensemble mixte{1,{3,2}}
, y aura-t-il une erreur? Je ne peux pas installer Dart maintenant, je ne peux donc pas me vérifier moi-même.dart bin/zinc.dart test.znc
j'obtiens une erreur de syntaxe:'file:///D:/Development/languages/zinc/bin/zinc.dart': error: line 323 pos 41: unexpected token '?'
...var input = stdin.readLineSync() ?? '';
-2+#:S
quand donnéS
, ce qui a coupé les deux zéros de fin. C'était comme ça que j'espérais que ce serait résolu. Et^
n'est pas censé inverser le décor ... c'était un bug ...Compass Soup ( cracked by cardboard_box )
Interprète: C ++
Compass Soup est un peu comme une machine de Turing avec une bande infinie en 2 dimensions. Le problème principal est que la mémoire d'instructions et la mémoire de données se trouvent dans le même espace et que le programme génère le contenu complet de cet espace.
Comment ça fonctionne
Un programme est un bloc de texte en 2 dimensions. L'espace programme commence par l'intégralité du code source placé avec le premier caractère à (0,0). Le reste de l'espace de programme est infini et est initialisé avec des caractères nuls (ASCII 0).
Deux indicateurs peuvent se déplacer dans l'espace du programme:
!
personnage ou à (0,0) s'il n'existe pas.x
,X
,y
, etY
. Cela commence à l'emplacement du@
personnage ou à (0,0) s'il n'existe pas.Contribution
Le contenu de stdin est imprimé dans l’espace programme en commençant par l’emplacement du
>
caractère ou par (0,0) s’il n’existe pas.Sortie
Le programme se termine lorsque le pointeur d'exécution est irrémédiablement hors limites. La sortie représente tout le contenu de l’espace de programmation à ce moment. Il est envoyé à stdout et 'result.txt'.
Instructions
n
- redirige le pointeur d'exécution Nord (y négatif)e
- redirige le pointeur d’exécution Est (x positif)s
- redirige le pointeur d'exécution Sud (y positif)w
- redirige le pointeur d’exécution Ouest (x négatif)y
- déplace le pointeur de données vers le nord (y négatif)X
- déplace le pointeur de données Est (positif x)Y
- déplace le pointeur de données vers le sud (y positif)x
- déplace le pointeur de données Ouest (négatif x)p
- écrit le caractère suivant rencontré par le pointeur d'exécution au niveau du pointeur de données. Ce personnage n'est pas exécuté comme une instruction.j
- vérifie le caractère suivant rencontré par le pointeur d'exécution par rapport au caractère situé sous le pointeur de données. Ce personnage n'est pas exécuté comme une instruction. S'ils sont identiques, le pointeur d'exécution saute par-dessus le caractère suivant.c
- écrit le caractère nul sur le pointeur de données.*
- point d'arrêt - provoque simplement la rupture de l'interprète.Tous les autres caractères sont ignorés par le pointeur d'exécution.
Interprète
L'interpréteur prend le fichier source comme argument et entrée sur stdin. Il a un débogueur steppable, que vous pouvez appeler avec une instruction de point d'arrêt dans le code (
*
). Lorsqu'il est interrompu, le pointeur d'exécution est représenté par ASCII 178 (bloc ombré plus foncé) et le pointeur de données est représenté par ASCII 177 (bloc ombré plus clair).Exemples
Bonjour le monde
Chat
Parité: accepte une chaîne de caractères terminée par un zéro ('0'). Les sorties
yes
sur la première ligne de la sortie si le nombre de 1 dans l'entrée est impair, sinon sorties|
.Conseils
Vous devez utiliser un bon éditeur de texte, utiliser judicieusement les fonctionnalités de la touche "Insérer" et utiliser "Alt-glisser" pour ajouter ou supprimer du texte sur plusieurs lignes à la fois.
Solution
Voici ma solution. Ce n'est pas aussi bien que cardboard_box parce que je devais faire supprimer le code source lui-même. J'espérais aussi pouvoir trouver un moyen de supprimer tout le code et de ne laisser que la réponse, mais je ne pouvais pas.
Mon approche consistait à scinder les différentes séquences de
1
s en différentes lignes, puis à les trier de manière à ce que1
tous s "tombent" jusqu'à atteindre une autre1
et enfin à tout effacer, sauf la troisième ligne après l'entrée.#A#
lit1
s et les copie à la dernière ligne de la division jusqu'à ce que a0
soit lu.#B#
vérifie pendant une seconde0
et va au nord pour#D#
y en avoir une. Sinon,#C#
commence une nouvelle ligne fractionnée en insérant|
après la dernière et retourne à#A#
.#F#
est le code de gravité. Il se dirige vers le dernier1
rang de la première rangée et le déplace jusqu'à ce qu'il frappe1
ou-
. S'il ne peut pas faire cela, il marque la ligne comme étant terminée en la plaçant+
devant.#G#
efface toutes les divisions inutiles et#H#
efface stdin et tout le code entre les parenthèses.Code:
la source
c
au début qui n'aurait pas dû être là. Je l'ai corrigé. Également ajouté ma solution au problème.Acc! , Cracc'd par ppperry
Ce langage a une structure en boucle, un nombre entier élémentaire, des caractères d’entrée / sortie et un accumulateur (donc son nom). Juste un accumulateur. Ainsi, le nom.
Les déclarations
Les commandes sont analysées ligne par ligne. Il existe trois types de commande:
Count <var> while <cond>
Compte
<var>
à partir de 0 tant que<cond>
est non nul, ce qui équivaut à un style Cfor(<var>=0; <cond>; <var>++)
. Le compteur de boucle peut être n'importe quelle lettre minuscule. La condition peut être n'importe quelle expression, n'impliquant pas nécessairement la variable de boucle. La boucle s'arrête lorsque la valeur de la condition devient 0.Les boucles nécessitent des accolades à la K & R (en particulier la variante Stroustrup ):
Write <charcode>
Renvoie un seul caractère avec la valeur ASCII / Unicode donnée sur stdout. Le charcode peut être n'importe quelle expression.
Toute expression indépendante est évaluée et attribuée à l'accumulateur (qui est accessible en tant que
_
). Ainsi, par exemple,3
est une déclaration qui définit l'accumulateur sur 3;_ + 1
incrémente l'accumulateur; et_ * N
lit un caractère et multiplie l'accumulateur par son charcode.Remarque: l'accumulateur est la seule variable pouvant être affectée directement. variables de boucle et
N
peut être utilisé dans les calculs mais pas modifié.L'accumulateur est initialement 0.
Expressions
Une expression peut inclure des littéraux entiers, des variables de boucle (
a-z
),_
pour l'accumulateur, ainsi que la valeur spécialeN
, qui lit un caractère et passe à son code de caractère chaque fois qu'il est utilisé. Remarque: cela signifie que vous ne pouvez lire qu'un seul coup par personnage; la prochaine fois que vous utiliserezN
, vous lirez le prochain.Les opérateurs sont:
+
, une addition-
, soustraction; négation unaire*
, multiplication/
, division entière%
, modulo^
, exponentiationLes parenthèses peuvent être utilisées pour imposer la priorité des opérations. Tout autre caractère dans une expression est une erreur de syntaxe.
Espaces et commentaires
Les espaces et les lignes vides sont ignorés. Les espaces blancs dans les en-têtes de boucle doivent être exactement comme indiqué, avec un seul espace entre l'en-tête de la boucle et l'accolade ouverte également. Les espaces dans les expressions sont facultatifs.
#
commence un commentaire d'une seule ligne.Entrée sortie
Acc! attend une seule ligne de caractères en entrée. Chaque caractère saisi peut être extrait en séquence et son code de caractères traité
N
. Essayer de lire après le dernier caractère de la ligne provoque une erreur. Un caractère peut être généré en transmettant son charcode à l'Write
instruction.Interprète
L'interprète (écrit en Python 3) traduit Acc! code en Python et
exec
c'est tout.la source
GoToTape (Safe)
(Anciennement connu sous le nom de Simp-plex.)
Ce langage est simple. Le contrôle de flux principal est goto, la forme de contrôle la plus naturelle et la plus utile.
Spécification de la langue
Les données sont stockées sur une bande et dans un accumulateur. Cela fonctionne entièrement avec des intégrations non signées. Chaque personnage est une commande. Voici toutes les commandes:
a
-z
sont des déclarations goto, allant àA
-Z
, respectivement.:
: définit l'accumulateur sur la valeur ASCII pour qu'il soit saisi à partir de l'entrée.~
: affiche le caractère de la valeur ASCII dans l'accumulateur.&
: soustrayez un de l’accumulateur s’il est égal à 1 ou plus, sinon ajoutez-en un.|
: ajouter un à l'accumulateur.<
: mettre le pointeur de données à 0.+
: incrémente la cellule de données au pointeur de données; déplacez le pointeur +1.-
: soustrayez un de la cellule de données au pointeur de données s'il est positif; déplacez le pointeur +1.[...]
: exécuter le code n fois, où n est le numéro sur la bande au pointeur de données (ne peut pas être imbriqué)./
: ignore la prochaine instruction si l'accumulateur est 0.Interprète (C ++)
S'amuser!
Solution
A:+&&&&&&&&&&/gbG&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/a<aB<[|]C[&]-[|]/c<[|]D[&]-[|]/d<[|]+E[&]|||||||||||||||||||||||||||||||||||||||||||||||||~X&/x-[|]/e
la source
calloc
lieu denew char
, a écrit un style C en boucle, utilisée gestion de la mémoire de style C, nous font recompiler le fichier C ++ à chaque fois que nous changeons le code, et utilisé 20 ifs au lieu d'unswitch
? Je ne me plains pas, mais mes yeux saignent maintenant ...: Ostr.c_str()
pour obtenir unchar*
.C'était une mauvaise idée car presque tous les langages ésotériques ont l'air illisibles (regardez Jelly).
Mais voici:
Pylongolf2 beta6
Poussant à la pile
Pousser vers la pile agit différemment dans d'autres langues.
Le code
78
pousse7
et8
dans la pile, mais en Pylongolf il pousse78
.Dans Pylongolf2, cela est interchangeable avec
Ü
.Les commandes
Concaténation de chaînes et suppression d'un motif regex d'une chaîne
Le symbole + concatène des chaînes.
Vous pouvez utiliser le symbole - pour supprimer des caractères suivant un motif d'expression régulière d'une chaîne:
Ce code accepte les entrées et supprime tous les caractères non alphabétiques en supprimant tous les modèles correspondants
[^a-zA-Z]
.L'élément sélectionné doit être l'expression régulière et celui qui précède doit être la chaîne à modifier.
Si les déclarations
Pour faire des déclarations, mettez a
=
pour comparer l’élément sélectionné et celui qui suit.Cela place un
true
ou unfalse
à sa place.La commande
?
vérifie ce booléen.Si c'est le cas,
true
cela ne fait rien et l'interprète continue.Si c'est le cas,
false
l'interprète passe au¿
personnage le plus proche .Tiré de la page Github.
Interprète pour Pylongolf2 (Java):
la source
Rainbow (Note: interprète à venir)
Je sais que ce défi a expiré.
Rainbow est un mélange de… beaucoup de choses.
Rainbow est un langage basé sur une pile 2D avec deux piles (comme Brain-Flak) et 8 directions (
N NE E SE S SW W NW
). Il y a 8 commandes:1
,+
,*
,"
Faire exactement ce qu'ils font en 1+.!
bascule la pile active.>
Faites pivoter l'adresse IP dans le sens des aiguilles d'une montre.,
saisissez un caractère et appuyez dessus..
pop et sortir un caractère.Cependant, les caractères du code source ne sont pas exécutés immédiatement. Au lieu de cela,
[The Character in the source code]^[Top Of Stack]
est alimenté par la conjecture de Collatz, et le nombre de pas nécessaires pour atteindre 1 est converti en caractère par table ASCII. Ce personnage est ensuite exécuté.Au début du programme, le code source (à l'exception du dernier caractère) est inséré dans la pile.
Lorsque l'IP atteint le bord du code source, il se termine.
apocalypse
n et m sont deux registres. Lorsqu'une
>
instruction est exécutée, m est incrémenté. Apocalypse n'est déclenché que si m dépasse n. Lorsque Apocalypse se produit, il:m est initialement zéro et n est initialement le dernier caractère du code source.
Chiffrement
Après l'exécution de toute exécution, le code source est crypté. Le premier caractère ASCII est incrémenté de un, le second est décrémenté de un, le troisième incrémenté de deux, le 4ème est décrémenté de deux, etc.
la source