Sortie de la source, un bit à la fois

18

Écrivez un programme ou une fonction non vide qui, lorsqu'il est appelé, génère une seule valeur, 1 ou 0, et lorsqu'il est appelé plusieurs fois, les numéros de sortie produisent la représentation binaire du code source de votre programme (dans la même page de code à partir de laquelle votre code est compilé). / interprété).

Par exemple, si votre code source était abc(en ASCII), les sorties seraient:

1st call:  0           // ASCII letter 'a'
2nd call:  1
3rd call:  1
4th call:  0
5th call:  0
6th call:  0
7th call:  0
8th call:  1

9th call:  0           // ASCII letter 'b'
10th call: 1
11th call: 1
12th call: 0
13th call: 0
14th call: 0
15th call: 1
16th call: 0

17th call: 0           // ASCII letter 'c'
18th call: 1
19th call: 1
20th call: 0
21st call: 0
22nd call: 0
23rd call: 1
24th call: 1

After the 24th call, the behaviour is undefined.

La représentation binaire de la source doit contenir au moins un bit 0 et un bit 1.

Au lieu de 1 et 0, vous pouvez générer deux valeurs cohérentes distinctes (telles que trueet false).

Les programmes auto-modifiables qui produisent la représentation binaire de la source d'origine sont autorisés, à condition qu'ils ne lisent pas le code source pour savoir quoi imprimer ensuite.

Il s'agit de , donc la réponse la plus courte en octets l'emporte.

Steadybox
la source

Réponses:

8

Funky , 47 41 37 octets

Renvoie un nombre représentant un bit.

f=_=>1&("%b"%("f="+f)[i//8])>>7-i++%8

Cela utilise le format quine de f=_=>"f="+f. Il prend le caractère à la position ⌊i / 8⌋ , puis obtient le bit en prenant la paire d' n >> 7-i%8nest la valeur ascii du caractère actuel.

Il s'agit d'une fonction itérative qui s'incrémente ià chaque appel, une fois le code source épuisé, il écrira le code pour ntoujours.

Essayez-le en ligne!

ATaco
la source
Est-ce un polyglotte avec JavaScript?
Stan Strum
9

Bash , 105 octets

trap -- 'trap|xxd -b -c1|cut -d\  -f2|tr -d \\n|cut -c`x=\`cat f||echo 1\`;echo $((x+1))>f;echo $x`' EXIT

Remarque : assurez-vous que vous n'avez pas un fichier important appelé fdans le répertoire que vous testez.


Si vous souhaitez tester cela, vous pouvez utiliser la commande suivante:

for i in $(seq 848); do bash path/to/script.sh 2> /dev/null; done | tr -d \\n

Ce qui devrait donner la même sortie xxd -c1 -b path/to/script.sh|cut -d\ -f2|tr -d \\n.

Explication

Ceci utilise l' trapastuce - appeler trapà l'intérieur de l' trapaction imprime simplement cette ligne. Ensuite, cette sortie est canalisée vers xxdlaquelle la convertit en binaire (malheureusement xxd -bpne fonctionne pas - donc la solution de contournement avec cut& tr):

xxd -c1 -b $0|cut -d\  -f2|tr -d \\n

De cela, nous ne sommes intéressés que par un bit (disons N) avec lequel nous pouvons sélectionner cut -cN.

Pour savoir ce Nque nous utilisons (rappelez-vous que c'est la partie qui doit être incrémentée après chaque appel), essayez simplement de définir xle contenu du fichier fet s'il n'existe pas, définissez-le sur 1:

x=`cat f||echo 1`

La dernière chose à faire est de mettre à jour le fichier f- en y écrivant x+1:

echo $((x+1))>f
ბიმო
la source
7

TI-Basic (série TI-83), 592 357 309 octets

"123456789ABCDEF02A3132333435363738394142434445463004AA003FB958833404593FB9588338045A3F3230363FDA582B383F303FCE5A405A6B3232333F5A70BB0FAA002BBB0CAA002B5A2B313FB932BA32F01058713459713511BB0FAA002BBB0CAA002B597031377132722B31→Str1
iPart(X/4→Y
iPart(X/8→Z
206
IS>(X,8
0
If Z and Z<223
Z+inString(Str1,sub(Str1,Z,1
iPart(2fPart(2^(X-4Y-5)inString(Str1,sub(Str1,Y+17-2Ans,1

Ce tableau est une référence possible pour la représentation binaire de la calculatrice du code source, bien que finalement je viens d'utiliser le débogueur de Virtual TI.

A titre de comparaison et / ou d'intérêt historique: les premiers quines écrits en TI-Basic .

Comment ça fonctionne

Str1stocke le code source (maintenant en hexadécimal glorieux, économisant beaucoup d'espace sur la version binaire précédente), en laissant de côté les bits où le contenu de Str1lui-même serait représenté.

Nous partons du principe que le programme démarre sur une calculatrice dont la mémoire vient d' être effacé, donc Xest 0. Chaque fois que nous parcourons le programme, nous progressons X.

Habituellement, nous venons de comprendre le demi-octet dont nous essayons d'extraire un peu, de le lire Str1, de le convertir en hexadécimal en binaire et de l'imprimer. Si nous sommes sur la partie du code source qui est de stocker Str1( ce qui est des deux tiers de la longueur totale du programme), puis nous avons d' abord passer à la partie de la chaîne de stockage correspondante 31, 32et ainsi de suite.

Misha Lavrov
la source
4

Java 8, 249 241 237 234 148 octets

int i;v->{String s="int i;v->{String s=%c%s%1$c;return s.format(s,34,s).charAt(-i/8)>>(--i&7)&1;}";return s.format(s,34,s).charAt(-i/8)>>(--i&7)&1;}

Désolé d'avance pour les longues explications. :)

  • Pas moins de 89 octets enregistrés grâce à @Nevay .

Essayez-le ici.

Explication:

int i;                     // Index-integer on class-level
v->{                       // Method with empty unused parameter and integer return-type
  String s="int i;v->{String s=%c%s%1$c;return s.format(s,34,s).charAt(-i/8)>>(--i&7)&1;}";
                           //  String containing the unformatted source code
  return s.format(s,34,s)  //    Quine to get the source code,
      .charAt(-i/8)        //     and get the character at index `-i/8`
     >>                    //    And bitwise right-shift it with:
       (--i&7)             //     `i-1` bitwise-AND 7
                           //     by first decreasing `i` by 1 with `--i`
      &1;                  //   Then bitwise-AND everything above with 1
}                          // End of method

Explication supplémentaire:

-part:

  • String s contient le code source non formaté
  • %s est utilisé pour mettre cette chaîne en elle-même avec s.format(...)
  • %c, %1$cEt 34sont utilisés pour formater les guillemets doubles ( ")
  • s.format(s,34,s) met tout cela ensemble

Essayez-le ici avec certaines parties supprimées / modifiées pour vérifier les sorties quine est son propre code source.

partie :


Ancien 233 octets réponse:

int i;v->{String s="int i;v->{String s=%c%s%1$c;return Long.toString((s.format(s,34,s).charAt(i/8)&255)+256,2).substring(1).charAt(i++%%8);}";return Long.toString((s.format(s,34,s).charAt(i/8)&255)+256,2).substring(1).charAt(i++%8);}

Essayez-le ici.

Explication:

int i;                           // Index-integer on class-level
v->{                             // Method with empty unused parameter and char return-type
  String s="int i;v->{String s=%c%s%1$c;return Long.toString((s.format(s,34,s).charAt(i/8)&255)+256,2).substring(1).charAt(i++%%8);}";
                                 //  String containing the unformatted source code
  return Long.toString(
          (s.format(s,32,s)      //  Quine-formatting
          .charAt(i/8)           //  Take the current character
           &255)+256,2).substring(1)
                                 //  Convert it to an 8-bit binary-String 
         .charAt(i++%8);         //  And return the bit at index `i` modulo-8
                                 //  and increase index `i` by 1 afterwards with `i++`
}                                // End of method

Explication supplémentaire:

-part:

Même explication que ci-dessus, avec l'ajout de:

  • %%est la forme échappée du signe modulo ( %)

Essayez-le ici avec certaines parties supprimées / modifiées pour vérifier les sorties quine est son propre code source.

partie :

  • i/8tronquera automatiquement sur la division entière, donc quand iest 0-7, il deviendra 0; si iest 8-15, il deviendra 1; etc.
  • Prend donc s.charAt(i/8)le caractère actuel du code source, huit fois l'un après l'autre. Essayez-le ici avec une version modifiée.
  • 255est 0xFFou 11111111(la valeur maximale pour un octet non signé)
  • 256est 0x100ou 100000000.
  • L' &upcasts le caractère ASCII à un entier. À ce stade, c'est n'importe où entre 0et 255( 00000000à 11111111).
  • Long.toString(...,2) le convertit en représentation de chaîne binaire 9 bits
  • +256et .substring(1)garantira qu'il y a des zéros non significatifs, et convertira le 9 bits en 8 bits.

Essayez-le ici avec certaines parties supprimées / modifiées pour vérifier la totalité des octets.

Kevin Cruijssen
la source
1
149 octets:int i;v->{String s="int i;v->{String s=%c%s%1$c;return 1&s.format(s,34,s).charAt(-i/8)>>(--i&7);}";return 1&s.format(s,34,s).charAt(-i/8)>>(--i&7);}
Nevay
@Nevay Whopping 88 octets enregistrés. Merci! Et comme il s'agit en fait d'une approche assez différente de celle que j'avais à l'origine, j'ai conservé l'ancienne réponse et ajouté la nouvelle. (Si vous le souhaitez, je le supprimerai à nouveau et vous pourrez le poster vous-même, mais vous m'avez dit par le passé que vous préférez
jouer
2

Javascript ES6, 73 58 52 octets

o=_=>`o=${o}`.charCodeAt((o.n=1+o.n|0)/8)>>(7-o.n%8)&1

Explication

Répartition du code:

  • o=_=>: définir une fonction.
  • `o=${o}`: construire une chaîne; oest converti en chaîne, qui dans ce cas est le code source de la fonction.
  • .charCodeAt(: récupère un caractère dans la chaîne comme son code de caractère ASCII.
  • (o.n=1+o.n|0)/8: sélectionnez un caractère. C'est également là que le compteur est incrémenté.
  • )>>(7-o.n%8): décale le code de caractère résultant pour que le bit souhaité soit dans la bonne position.
  • &1: mettre tous les autres bits à 0.
RamenChef
la source
Vous pouvez raccourcir cela avec un lambda eno=_=>(o+'').charCodeAt(('n'in top?++n:n=0)/8|0)>>(7-n%8)&1
ATaco
Cela compte pour définir une fonction.
ATaco
1
Essayezo=_=>('o='+o).charCodeAt(('n'in top?++n:n=0)/8|0)>>(7-n%8)&1
ATaco
Au lieu de 'n'in top?++n:n=0vous pouvez utiliser ++n||(n=0)ou ++n?n:n=0ou n=++n||0ou n=1+n||0qui utilisent tous la fausseté NaNqui est produite par incrémentationundefined
Bergi
1
o=_=>('o='+o).charCodeAt((o.n=1+o.n|0)/8)>>(~o.n&7)&1
tsh
2

q / kdb + , 45 octets

Solution:

a:-1;f:{((,/)0b vs'4h$"a:-1;f:",($).z.s)a+:1}

Exemple:

q)f[] / call function f with no parameters
0b   
q)f[]
1b   
q)f[]
1b   
q)f[]
0b   
q)f[]
0b   
q)f[]
0b   
q)f[]
0b   
q)f[]
1b   
q)f[]  
q)"c"$0b sv 01100001b / join back to a byte and cast to a character
"a"

Explication:

Je pense avoir compris le mémoire.

Configurez d'abord une variable globale aavec une valeur de départ de -1. La fonction fconstruit la représentation binaire de la représentation sous forme de chaîne de la fonction (tout y compris le {}) précédée de la a:-1;f:jonque, et indexe dans cette liste binaire à l'index a (qui est incrémenté à chaque appel).

a:-1;f:{(raze 0b vs'4h$"a:-1;f:",string .z.s)a+:1} / ungolfed solution
a:-1;                                              / stick -1 in variable a
     f:{                                         } / define function f
                                             a+:1  / increment a by 1 (:: is required as a is a global variable), indexes into the left
        (                                   )      / do all this together
                                 string .z.s       / z.s is the function, string converts it to a string
                       "a:-1;f:",                  / prepend "a:-1;f:" to the start
                    4h$                            / cast to bytes
              0b vs'                               / convert each byte to binary
         raze                                      / flatten binary into long list
streetster
la source
2

Python 2 , 164 octets

lambda s='lambda s=%r,i=[]:i.append(1)or"{:08b}".format(ord((s%%s)[~-len(i)/8]))[~-len(i)%%8]',i=[]:i.append(1)or"{:08b}".format(ord((s%s)[~-len(i)/8]))[~-len(i)%8]

Essayez-le en ligne!

Explication

Commençons par une quine Python 2 standard.

s = '...'; print s % s

Bon, eh bien, ça sort comme ça. Nous avons besoin de binaire!

s = '...'; print "\n".join("\n".join("{:08b}".format(ord(i))) for i in s % s)

D'accord, cela convertit simplement tout en binaire. Mais le titre dit "un bit à la fois". Nous avons besoin de quelque chose pour persister pendant plusieurs exécutions. Je sais, faisons-en une fonction!

lambda s = '...': "\n".join("\n".join("{:08b}".format(ord(i))) for i in s % s)

Attendez, cela n'aide pas ... Hmm, comment pouvons-nous garder une trace de l'index du bit nécessaire pour être sorti? Ooh, ooh, ayons un entier pour garder une trace.

lambda s = '...', i = 0: "{:08b}".format(ord((s % s)[i / 8]))[i % 8]

Um ... qui sort toujours le premier bit. Oh, nous devons incrémenter le tracker! Oh merde, Python n'autorise pas la modification des entiers comme arguments par défaut. Et les affectations ne sont pas des expressions en Python, vous ne pouvez donc pas le faire dans un lambda. Welp, c'est impossible en Python, affaire close.

... Enfin, pas tout à fait. Python ne permet listes comme arguments par défaut à modifier. (Et il mord tout le temps aux programmeurs Python.) Utilisons sa longueur!

lambda s = '...', i = []: "{:08b}".format(ord((s % s)[len(i) / 8]))[len(i) % 8]

Mais cela ne modifie toujours pas le tracker ... Nous pouvons y ajouter quelque chose pour augmenter sa longueur ... Mais comment? Ah, eh bien, nous avons list.append. lst.append(1)est équivalent à lst += [1]. Génial!

lambda s = '...', i = []: i.append(1) and "{:08b}".format(ord((s % s)[len(i) / 8]))[len(i) % 8]

Oups, cela saute le premier bit car la longueur du tracker est de 1 avant que le bit ne soit émis. Nous devons décrémenter la longueur où il est utilisé.

lambda s = '...', i = []: i.append(1) and "{:08b}".format(ord((s % s)[(len(i) - 1) / 8]))[(len(i) - 1) % 8]

Ça y est, les amis! Jouez au golf et vous avez ma solution!

totalement humain
la source
2

Perl 5 , 59 octets

sub{$_=q{unpack(B.++$-,"sub{\$_=q{$_};eval}")=~/.$/g};eval}

Essayez-le en ligne!

Dom Hastings
la source