Comme vous le savez (espérons-le), une quine durcie aux radiations est une quine à partir de laquelle vous pouvez supprimer n’importe quel caractère et continuer d’imprimer sa source originale, préalablement modifiée. Le fait est qu'avec la plupart d'entre eux, vous ne pouvez supprimer qu'un seul caractère; sinon tout tombe en panne. C'est là que ça entre; votre objectif est de construire un quine durci par radiation capable de supprimer autant de personnages que possible. Toute langue conforme aux règles convient.
Règles
- Le programme doit comporter au moins un caractère.
- La langue utilisée doit être complète (les langues comme HQ9 + ne sont donc pas admissibles)
- Toutes les autres règles applicables aux règles normales s'appliquent également ici.
- La solution avec le moins
program_length^(2/n)
dans laquelle n'importe quel jeu den
caractères exacts peut être supprimé tout en imprimant le code source original l'emporte.
Subleq
. Je pense que ce serait idéal pour ce genre de défi!Réponses:
Perl,
11161124 octets, n = 3, score = 1124 ^ (2/3) ou environ 108,1Mise à jour : j'ai maintenant vérifié que cela fonctionne avec n = 3 via la force brute (ce qui a pris quelques jours); Avec un programme aussi complexe, il est difficile de vérifier manuellement la résistance aux radiations (et j'ai commis une erreur dans une version précédente, c'est pourquoi le nombre d'octets a augmenté). Fin de la mise à jour
Je recommande de rediriger stderr quelque part que vous ne le verrez pas; ce programme produit une tonne d'avertissements sur la syntaxe douteuse même lorsque vous ne supprimez pas de caractères de celle-ci.
Il est possible que le programme puisse être raccourci. Travailler dessus est assez pénible, ce qui permet de rater facilement les micro-optimisations possibles. Je visais surtout à obtenir le plus grand nombre possible de caractères supprimables (car c’est là la partie la plus difficile du programme), et j’ai considéré la rupture de code-golf comme un objectif agréable à atteindre, mais que je ne mettrais pas. effort ridicule d’optimisation (sur la base du fait qu’il est très facile de casser la résistance aux radiations par accident).
Le programme
Remarque: il y a un
_
caractère de contrôle littéral (ASCII 31) immédiatement avant chacune des quatre occurrences de-+
. Je ne pense pas qu'il soit correctement copié-collé sur StackOverflow, vous devrez donc le rajouter avant d'exécuter le programme.L'explication
Clairement, ce programme est constitué de quatre programmes identiques plus petits concaténés ensemble. L'idée de base est que chaque copie du programme vérifie si elle a été trop endommagée pour être exécutée ou non. si cela a été le cas, il ne fera rien (à part peut-être émettre des avertissements) et laissera la copie suivante être exécutée; s'il ne l'a pas été (c.-à-d. aucune suppression, ou si le caractère qui a été supprimé ne fait aucune différence dans le fonctionnement du programme), il fera son petit geste (afficher le code source du programme complet; c'est un bon quine, avec chaque partie contenant un codage du code source complet) puis quittez (en empêchant toute autre copie non endommagée d’imprimer à nouveau le code source et de ruiner ainsi la séquence en imprimant trop de texte).
Chaque partie est à son tour composée de deux parties qui sont effectivement indépendantes sur le plan fonctionnel; un wrapper extérieur et un code interne. En tant que tels, nous pouvons les considérer séparément.
Emballage extérieur
Le wrapper extérieur est, en gros,
eval<+eval<+eval< ... >####>####...>###
(plus un groupe de points-virgules et de nouvelles lignes dont le but doit être assez évident; il s'agit de s'assurer que les parties du programme resteront séparées, que les sémicules ou les nouvelles lignes qui les précèdent soient supprimés. ). Cela peut paraître assez simple, mais c'est subtile de plusieurs façons et c'est la raison pour laquelle j'ai choisi Perl pour ce défi.Tout d’abord, examinons le fonctionnement du wrapper dans une copie non endommagée du programme.
eval
analyse en tant que fonction intégrée, qui prend un argument. Parce qu'un argument est attendu,+
voici un unaire+
(qui sera maintenant très familier aux golfeurs de Perl; ils sont d'une utilité surprenante souvent). Nous attendons toujours un argument (nous venons de voir un opérateur unaire), donc le<
qui vient ensuite est interprété comme le début de l'<>
opérateur (qui ne prend pas d'argument préfixe ou postfix, et peut donc être utilisé en position d'opérande).<>
est un opérateur assez bizarre. Son but est d' habitude de lire handles de fichiers, et vous placez le nom filehandle dans les crochets. Sinon, si l'expression n'est pas valide en tant que nom de descripteur de fichier, elle est globalisée (processus identique à celui utilisé par les shells UNIX pour traduire le texte entré par l'utilisateur en une séquence d'arguments de ligne de commande; des versions bien plus anciennes de Perl étaient effectivement utilisées). le shell pour cela, mais de nos jours Perl gère le globbing en interne). L’utilisation prévue va donc dans le sens de<*.c>
, qui devrait normalement renvoyer une liste semblable à("foo.c", "bar.c")
. Dans un contexte scalaire (tel que l’argument deeval
), il retourne simplement la première entrée trouvée lors de la première exécution (l'équivalent du premier argument) et renvoie d'autres entrées sur des exécutions hypothétiques futures qui ne se produisent jamais.Maintenant, les shells gèrent souvent des arguments en ligne de commande; si vous donnez quelque chose comme
-r
sans argument, il sera simplement transmis intégralement au programme, qu'il y ait ou non un fichier portant ce nom. Perl agit de la même manière. Par conséquent, tant que nous nous assurons qu'il n'y a pas de caractères spéciaux pour le shell ou entre Perl<
et les correspondances>
, nous pouvons efficacement utiliser ceci comme une forme vraiment maladroite de littéral de chaîne. Mieux encore, l'analyseur Perl pour les opérateurs de type devis a une tendance compulsive à faire correspondre les crochets même dans des contextes comme celui-ci où cela n'a aucun sens, afin que nous puissions imbriquer en<>
toute sécurité (ce qui est la découverte nécessaire pour que ce programme soit possible). Le principal inconvénient de tous ces éléments imbriqués<>
est que l’échappement du contenu de la<>
est presque impossible; il semble y avoir deux couches de fuites avec chacune<>
, donc pour échapper à quelque chose à l'intérieur des trois, il faut le faire précéder de 63 barres obliques inverses. J'ai décidé que même si la taille du code n'était qu'une considération secondaire dans ce problème, cela ne valait certainement pas la peine de payer ce type de pénalité à mon score, alors j'ai simplement décidé d'écrire le reste du programme sans utiliser les caractères incriminés.Alors que se passe-t-il si des parties de l'emballage sont supprimées?
eval
font qu'il se transforme en mot simple , une chaîne sans signification. Perl n'aime pas cela, mais il les traite comme s'ils étaient entourés de guillemets.eal<+eval<+...
est donc interprété comme"eal" < +eval<+...
. Cela n'a aucun effet sur le fonctionnement du programme, car il ne prend en fait que le résultat des évaluations fortement imbriquées (que nous n'utilisons pas de toute façon), en le convertissant en un entier et en effectuant des comparaisons inutiles. (Ce type de produit génère de nombreux spams de mise en garde car ce n’est manifestement pas une chose utile à faire dans des circonstances normales; nous l’utilisons simplement pour absorber les suppressions.) Cela change le nombre de crochets dont nous avons besoin (parce que le est maintenant interprété comme un opérateur de comparaison), mais la chaîne de commentaires à la fin garantit que la chaîne se terminera en toute sécurité, quel que soit le nombre de fois où elle est imbriquée. (Il y a plus de#
signes que strictement nécessaire ici; je l'ai écrit comme je l'ai fait afin de rendre le programme plus compressible, me permettant d'utiliser moins de données pour stocker le quine.)<
est supprimé, le code est analysé commeeval(eval<...>)
. L'extérieur, secondaireeval
n'a aucun effet, car les programmes que nous évaluons ne renvoient aucun élément ayant des effets réels en tant que programme (s'ils retournent normalement, c'est normalement une chaîne nulle ou un mot simple; plus généralement, ils retournent via exception, ce qui aeval
pour effet de renvoyer une chaîne null ou de l’utiliserexit
pour éviter de tout renvoyer).+
est supprimé, cela n’a pas d’effet immédiat si le code adjacent est intact; unaire+
n'a aucun effet sur le programme. (Les raisons d'origine+
existent pour aider à réparer les dommages; elles augmentent le nombre de situations dans lesquelles un<
interprète est considéré comme unaire,<>
plutôt que comme un opérateur relationnel, ce qui signifie que vous avez besoin de plus de suppressions pour générer un programme invalide.)L'empaquetage peut être endommagé avec suffisamment de suppressions, mais vous devez effectuer une série de suppressions afin de produire quelque chose qui n'est pas analysé. Avec quatre suppressions, vous pouvez faire ceci:
et en Perl, l'opérateur relationnel
<
n'est pas associatif et vous obtenez donc une erreur de syntaxe (identique à celle que vous obtiendriez1<2<3
). En tant que tel, le plafond du programme écrit est n = 3. Ajouter plus de unaires+
semble un moyen prometteur de l’augmenter, mais comme cela rendrait de plus en plus probable que l’intérieur de l’emballage puisse aussi se briser, il peut être très difficile de vérifier que la nouvelle version du programme fonctionne.La raison pour laquelle l'encapsuleur est si précieux est que
eval
Perl intercepte des exceptions, telles que (par exemple) l'exception que vous obtenez lorsque vous essayez de compiler une erreur de syntaxe. Comme ileval
s'agit d'un littéral de chaîne, la compilation de la chaîne a lieu au moment de l'exécution et si la compilation échoue, l'exception qui en résulte est interceptée. Cela aeval
pour effet de renvoyer une chaîne null et de définir l'indicateur d'erreur$@
, mais nous ne vérifions jamais non plus (sauf en exécutant occasionnellement la chaîne null renvoyée dans quelques versions mutées du programme). Surtout, cela signifie que si quelque chose devait arriver au code à l' intérieurle wrapper, causant une erreur de syntaxe, il ne fera que rendre le code inactif (et le programme continuera à s'exécuter pour tenter de trouver une copie non endommagée de lui-même). Par conséquent, le code interne ne doit pas nécessairement être aussi résistant aux radiations que l’emballage; tout ce qui nous importe est que s'il est endommagé, il agira de la même manière que la version non endommagée du programme, ou bien il plantera (permettanteval
d'attraper l'exception et de continuer) ou quittera normalement sans imprimer.À l'intérieur de l'emballage
Le code à l'intérieur du wrapper, fondamentalement, ressemble à ceci (là encore, il y a un contrôle -
_
que Stack Exchange ne montrera pas immédiatement avant le-+
):Ce code est entièrement écrit avec des caractères globales, et vise à ajouter un nouvel alphabet de signes de ponctuation permettant d'écrire un programme réel, en effectuant une translittération et en évaluant un littéral de chaîne (nous ne pouvons ni utiliser
'
ni"
citer marques, maisq(
…)
est également un moyen valide de former une chaîne en Perl). (La raison du caractère non imprimable est que nous devons translittérer quelque chose dans le caractère espace sans caractère littéral dans le programme; nous formons ainsi une plage commençant à ASCII 31 et l'interceptons comme deuxième élément de la plage.) Évidemment, si nous produisons des caractères par translittération, nous devons sacrifier des caractères pour les translittérer de, mais les lettres majuscules ne sont pas très utiles et il est beaucoup plus facile d’écrire sans accès à celles-ci que sans accès aux signes de ponctuation.Voici l'alphabet des signes de ponctuation qui deviennent disponibles à la suite du glob (la ligne supérieure indique l'encodage, la ligne inférieure le caractère qu'il code):
Plus particulièrement, nous avons un tas de signes de ponctuation qui ne sont pas globalement sûrs mais qui sont utiles pour écrire des programmes Perl, ainsi que le caractère espace. J'ai également enregistré deux lettres majuscules, le littéral
A
etZ
(qui ne codent pas pour elles-mêmes, mais pourT
etU
, car ellesA
étaient nécessaires en tant que point final supérieur et inférieur); cela nous permet d'écrire l'instruction de translittération elle-même en utilisant le nouveau jeu de caractères codés (bien que les lettres majuscules ne soient pas très utiles, elles sont utiles pour spécifier les modifications à apporter aux lettres majuscules). Les caractères les plus remarquables dont nous ne disposons pas sont[
,\
et]
, mais aucun n’est nécessaire (lorsque j’avais besoin d’une nouvelle ligne dans la sortie, je l’ai produite à l’aide de la nouvelle ligne implicite desay
plutôt que d'avoir besoin d'écrire\n
;chr 10
aurait également fonctionné mais est plus prolixe).Comme d'habitude, nous devons nous inquiéter de ce qui se passe si l'intérieur du wrapper est endommagé en dehors du littéral string. Un corrompu
eval
empêchera tout en cours d'exécution; cela nous convient. Si les guillemets sont endommagés, l’intérieur de la chaîne n’est pas valide en Perl, et donc le wrapper l’attrapera (et les nombreuses soustractions sur les chaînes signifient que même si vous pouviez le rendre valide en Perl, il ne ferait rien, ce qui est un résultat acceptable). Si la translittération n’est pas une erreur de syntaxe, la chaîne en cours d’évaluation sera mutilée, ce qui en fera généralement une erreur de syntaxe; Je ne suis pas tout à fait sûr qu'il n'y ait pas de cas dans lequel cela se casse, mais je le force brute pour le moment, mais ce devrait être assez facile à réparer s'il y en a.Le programme encodé
En regardant à l'intérieur du littéral de chaîne, en inversant l'encodage que j'ai utilisé et en ajoutant des espaces pour le rendre plus lisible, nous obtenons ceci (encore une fois, imaginons un contrôle-soulignement avant le
-+
, codé ainsiA
):Les personnes habituées à quines reconnaîtront cette structure générale. La partie la plus cruciale est au début, où nous vérifions que $ o n’est pas endommagé; si les caractères ont été supprimés, sa longueur ne correspondra pas à
181
, donc nous couronszzzz((()))
qui, si elle n'est pas une erreur de syntaxe en raison de supports inégalés, sera une erreur d'exécution même si vous supprimez tous les trois personnages, parce qu'aucun dezzzz
,zzz
,zz
, etz
est une fonction, et il n’ya aucun moyen de l’empêcher de l’analyser comme une fonction autre que la suppression(((
et la génération d’une erreur de syntaxe évidente. Le chèque lui-même est également immunisé contre les dommages; cela||
peut être endommagé,|
mais l'zzzz((()))
appel sera exécuté sans condition; les variables ou les constantes préjudiciables causeront une disparité, car vous comparez l’un des éléments suivants0
,180
,179
,178
Pour l' égalité à un sous - ensemble des chiffres181
; et en supprimer un=
provoquera un échec d'analyse, et deux=
obligeront inévitablement le LHS à se transformer en un entier égal à 0 ou en une chaîne nulle, les deux étant falsey.Mise à jour : Cette vérification était légèrement fausse dans une version précédente du programme, j'ai donc dû la modifier pour résoudre le problème. La version précédente ressemblait à ceci après le décodage:
et il était possible de supprimer les trois premiers signes de ponctuation pour obtenir ceci:
lengtho179
, étant un mot simple, est la vérité et brise ainsi la vérification. J'ai corrigé cela en ajoutant deuxB
caractères supplémentaires (qui codent les espaces), ce qui signifie que la dernière version de la quine fait ceci:Maintenant, il est impossible de cacher les
=
signes et le$
signe sans produire une erreur de syntaxe. (Je devais ajouter deux espaces plutôt qu'un, car une longueur180
mettrait un0
caractère littéral dans la source, ce qui pourrait être abusé dans ce contexte pour comparer zéro avec un mot simple, ce qui aboutit.) Fin de la mise à jourUne fois que la vérification de la longueur est réussie, nous savons que la copie est intacte, du moins en termes de suppressions de caractères, de sorte que tout est mis en ordre à partir de là (les substitutions de signes de ponctuation dues à une table de décodage corrompue ne seraient pas capturées , mais j’ai déjà vérifié, par la force des brutes, qu’il n’existait pas trois suppressions provenant uniquement de la table de décodage, mais la plupart d’entre elles provoquaient probablement des erreurs de syntaxe. Nous avons
$o
dans une variable déjà, donc tout ce que nous devons faire est de mettre en dur (avec des enveloppes à l' extérieur un petit degré de compression, je ne l' ai pas sauter le code golf partie de la question tout à fait ). Une astuce consiste à stocker la majeure partie de la table de codage dans$r
; nous pouvons soit l’imprimer littéralement afin de générer la section de la table de codage de l’emballage interne, soit concaténer du code autour de celle-eval
ci afin de lancer le processus de décodage à l’inverse (nous permettant ainsi de déterminer quelle est la version codée de $ o , seule la version décodée étant disponible à ce stade).Enfin, si nous étions une copie intacte et pouvions ainsi sortir le programme original dans son intégralité, nous appelons
exit
afin d’empêcher les autres copies d’essayer également d’imprimer le programme.Script de vérification
Pas très joli, mais l'affiche parce que quelqu'un l'a demandé. J'ai couru cela plusieurs fois avec une variété de paramètres (généralement en train de changer
$min
et$max
de vérifier différents domaines d'intérêt); ce n'était pas un processus entièrement automatisé. Il a tendance à s’arrêter en raison de la charge de processeur élevée ailleurs; lorsque cela se produisait, je venais juste de passer$min
à la première valeur$x
qui n'était pas entièrement vérifiée et je continuais à exécuter le script (assurant ainsi que tous les programmes de la gamme étaient vérifiés). J'ai seulement vérifié les suppressions de la première copie du programme, car il est assez évident que les suppressions des autres copies ne peuvent pas faire plus.la source
Befunge-98 , 884, n = 14, score ≈ 2,636
Essayez-le en ligne!
Cela ne fonctionne pas uniquement lorsque vous supprimez exactement 14 caractères, mais même lorsque vous supprimez un maximum de 14 caractères.
n = 14
Cela peut sembler un choix très arbitraire, mais la technique que j'ai utilisée ne peut en fait être utilisée que pour les ordres de durcissement des radiations allant de 1 à 14, mais pas facilement au-delà (cela pourrait être possible, mais je ne sais pas comment.). Order-1 quine ne fait que 73 octets (bien qu’il utilise des astuces de golf qui ne s’appliquent pas aux plus grandsn
):Explication
Lorsque je travaillais sur cette réponse, j'ai découvert qu'il était possible de définir le delta du pointeur d'instruction sur
(2,0)
dans des conditions de durcissement extrême, avec l'extrait suivant:Voir cette réponse pour savoir pourquoi cela fonctionne. J'ai trouvé cela juste avec quelques manipulations à la main, mais cela a posé la question de savoir s'il existe des modèles similaires qui sont robustes lorsque plusieurs caractères sont supprimés. J'ai donc écrit un court script Mathematica pour rechercher ces éléments par force brute:
Cela a très vite révélé un motif. Pour obtenir un extrait correspondant qui permet de supprimer un maximum de
n
caractères, vous pouvez utiliser(m0x){n}m0
oùm
estn+1
etx
est l'unm
ou l' autre0
. Ainsi, tous les éléments suivants fonctionneraient pour la suppression de deux caractères au maximum:Je suis sûr qu'il est possible de le prouver, mais j'ai simplement vérifié
n
jusqu'à7
. Bien sûr, cela ne fonctionne que tant que nous pouvons représentern+1
sous forme de chiffre unique, et le plus grand chiffre de ce type dans Befunge 98f
correspond à 15. C'est pourquoi mon approche est limitée àn = 14
. Si quelqu'un trouve un moyen d'n+1
augmenter de manière fiable le delta , il serait probablement possible d'augmenter l'ordre de ce quine durci aux radiations indéfiniment.Regardons le code actuel. Il comporte essentiellement deux parties. Tout d'abord, nous plaçons le delta sur
(15,0)
comme je viens de le mentionner:Et le reste du code a chaque commande répétée 15 fois et imprime la source. Si nous supprimons la répétition, cela ressemble à ceci:
Il
"
s'agit d'une technique de quining 2D standard: elle démarre le mode chaîne, place tous les caractères (sauf lui-même) sur la pile et termine le mode chaîne une fois le bouclé terminé. Cela nous aide à obtenir tous les points de code du second semestre, mais il ne parviendra pas à nous faire quelque chose d' utile de la première moitié, car tout au long duf00f00...f0
bit, il n'enregistrera deux caractères (qui peuvent être soitf
ou0
selon lequel les caractères sont supprimés ) Mais comme cette partie n’est pas composée de caractères répétés 15 fois, nous aurons quand même besoin de l’imprimer séparément.De manière plus pratique, dans le cas non modifié, la longueur de la chaîne avant le
"
est-1 (mod 15)
. Cela garantit que quel que soit le nombre de caractères (jusqu'à 14) que nous supprimons, le nombre de caractères enregistrés est toujours de 3 (unx
et deux def
et0
). Ceci est vrai pour toute commande de radiation jusqu’à 14.Nous commençons maintenant par imprimer la
f00f00...f0
pièce:Le suivant
3k$
ignore simplement cela0
ainsi que les trois personnages qui ont été poussés"
depuis le début du programme. La pile ne contient plus que les caractères après le"
, ainsi que des éléments indésirables sous l’original, enf00f00...f0
fonction des caractères supprimés.Il ne nous reste plus qu’à inverser le haut de la pile (contenant les caractères restants) et à les imprimer 15 fois.
Et c'est tout. :)
la source
JavaScript (ES6), 927 octets, n = 1, score = 859329
remarque: n'utilisez pas de REPL (comme une console de navigateur) pour l'exécuter.
Cela a été écrit avant que la longueur du code ne soit un facteur important, donc il n'est pas encore joué au golf.
C'était très difficile et mérite une explication approfondie. Ce que j'écrirai plus tard, après avoir exploré un peu plus ce défi!
note: il y a un retour à la ligne
Fondamentalement, la première ligne est construite avec soin pour renommer toutes les "fautes d'orthographe"
setTimeout
en fonctions valides, de sorte que si un caractère est supprimé de l'un dessetTimeout
s, le code ne sera pas en erreur et la version non endommagée pourra être exécutée. Il est également écrit de sorte que si un caractère quelconque est supprimé de la première ligne, il n'y aura pas d'erreur et le reste du code pourra être exécuté sans être affecté.Les deuxième et troisième blocs sont exactement équivalents. Si l'un d'entre eux est terminé, il définit la
_
variable de sorte que l'autre sache ne pas dupliquer le quine. Si l'un de ces blocs tombe en erreur, il n'affecte pas l'autre bloc car il a été appelé de manière asynchrone parsetTimeout
. L'erreur entraînera la_
non définition, de sorte que l'autre bloc sera terminé avec succès. Le code principal est une chaîne dont la longueur est vérifiée dans chaque bloc pour s'assurer qu'il n'y a pas eu de suppression.Les chaînes de modèle sur la ligne suivante avec des commentaires à la fin des chaînes de modèle protègent le code des erreurs si l'une des backticks formant la chaîne de modèle est supprimée. Si le backtick final est supprimé, la chaîne de modèle se termine par le backtick dans le commentaire. Si le backtick de départ est supprimé, setTimeout est évalué en tant que fonction non attribuée (no-op) et le code s'exécute normalement, sans setTimeout. Le backtick final est annulé par un autre commentaire.
Qu'est-ce que vous dites? Vous voulez l'essayer? Ne dis pas plus!
Mode pleine page recommandé.
Ignorer la zone de saisie, cet extrait ne prend aucune entrée.
Essayez de supprimer n'importe quel caractère du code!
Ne le crois pas? Le code normal fonctionnera toujours (mais il ne sera pas quine ...) Essayez quelque chose comme
console.log(5)
!Remarque: l'extrait de code a dû être légèrement modifié pour désactiver la fonction REPL. J'ai donc supprimé plusieurs fonctionnalités de sortie pour cette réponse uniquement.
Une meilleure explication est à venir. En attendant, n'hésitez pas à me contacter sur le chat @jrich avec vos commentaires / questions / critiques!
la source
this
au lieu dewindow
.