Créer un programme «hacker typer» qui rend son propre code source

25

Si vous n'êtes pas familier avec le hacker typer, consultez hackertyper.net . En bref, c'est un programme qui produit un morceau d'une base de code par frappe pour un effet comique. MAIS, la version hackertyper.net est beaucoup trop facile à implémenter. Il produit simplement trois caractères à la fois à partir d'un morceau de code arbitraire . Pour ce défi, un programme doit produire son propre code source et imprimer un morceau de code délimité par espace par frappe.

Détails

  • On ne peut pas coder en dur un nom de fichier pour le programme; il doit déterminer son nom dynamiquement. Si le programme compile en un exécutable, il peut ajouter l'extension de fichier standard au nom de l'exécutable (à l'exclusion du .exe si vous utilisez Windows) et supposer que le fichier source se trouve dans le répertoire de l'exécutable. Par exemple, si un exécutable C est nommé "hacker", il doit extraire son code source d'un fichier nommé "hacker.c" dans son même répertoire. Si un programme compilé a une extension, elle doit être supprimée avant de déterminer le nom de son code source ("typer.exe" -> "typer.cs").
  • Les programmes doivent contenir au moins 5 espaces, avec au moins un caractère entre chaque espace. Cela signifie que la taille la plus petite possible pour ce défi est de 9 octets. Les espaces ne doivent pas être cruciaux pour le fonctionnement du programme.
  • Tout formatage (retrait, nouvelles lignes, etc.) doit être conservé dans la sortie. Cette mise en forme peut être imprimée avec le code qui la procède ou la suit, ce qui importe est que la mise en forme soit maintenue.
  • Évitez d'utiliser des commentaires pour satisfaire aux 5 exigences d'espace, sauf s'il n'existe aucun autre moyen d'implémenter les espaces dans la langue de votre choix.

EDIT : De nouvelles lignes peuvent être utilisées à la place ou en plus des espaces comme séparateurs de blocs.

DrJPepper
la source
1
Je suis un peu confus. Le programme devrait-il être une quine ou non?
Orby
8
La façon dont vous l'avez décrit donne l'impression qu'il est acceptable de lire le code du fichier source d'origine, ce qui ne serait pas une quine. Je pense que ce serait un meilleur concours si le programme devait être une véritable quine.
Orby
1
@Orby, je dirais que le programme n'est pas une quine au sens traditionnel, que la lecture de la source soit autorisée ou non. Les quines n'ont pas d'entrée mais ces programmes en ont clairement.
Hobbies de Calvin
@DrJPepper Votre troisième puce donne l'impression que n'importe quelle séquence d'espaces compte comme un délimiteur, mais vous dites spécifiquement que seul l'espace l'est. Pouvez-vous clarifier?
Hobbies de Calvin
2
Ce défi encourage la lecture du code source du programme, une pratique généralement verboten dans la construction des quines.
feersum

Réponses:

13

bash, 51 58

for w in $(<$0);do read -sn 1;printf -- "$w ";done
Volonté
la source
2
Il de shell bash, non: Cela ne fonctionne pas sous tiret, ( 2: read: Illegal option -s)
F. Hauri
1
En supposant que bash, peut remplacer cat $0et tildes avec$(<$0)
@broslow thx pour les commentaires; étiqueté bash, même longueur
Will
1
@ Pas de problème. Est-ce IFS=\ vraiment nécessaire si vous omettez le shebang? IFS par défaut est quelque chose comme ça IFS=$'\n\t ', et comme vous n'avez plus de nouvelle ligne, je ne pense pas que vous ayez besoin de la limiter à l'espace.
1
for w in `<$0`;{ read \-sn1;printf $w\ ;}
jimmy23013
21

HTML et JavaScript, 123

<head></head><body onload="s=(a=document.all)[i=0].innerHTML" onkeyup="a[2].textContent += s.split(/(?= )/)[i++%6]"></body>

Cela fonctionne de manière similaire au hacker typer, mais avec son propre code source. Faites-moi savoir si j'ai mal compris les règles.

Et voici une version stylisée (170 caractères):

<head></head>
<body style="background:#000;color:lime" onload="s=(a=document.all)[i=0].innerHTML" onkeyup="a[3].textContent+=s.split(/(?=\s)/)[i++%6]">
<pre></pre></body>

J'ai fait une démo . Il est modifié parce que JS Bin ajoute beaucoup de code supplémentaire, mais l'idée générale est la même.

grc
la source
2
Je serais surpris si cela ne s'affichait pas correctement sans les balises <html> et <head>, et sans fermeture </body>. Vous seriez surpris de voir à quel point tous les navigateurs sont indulgents à cet égard.
Will
2
@Will Merci. La raison pour laquelle j'ai inclus <head>est que le navigateur l'ajoutera s'il n'est pas là, donc il sera toujours affiché. J'ai oublié <html>cependant.
grc
12

Perl + Term :: ReadKey, 56 octets

use
Term'ReadKey;ReadMode
4;open
0;ReadKey,print
for
<0>

Merci à ThisSuitIsBlackNot pour l'inspiration originale, et à primo pour avoir suggéré open 0et <0>.

Notez que la nouvelle ligne après for n'est en fait pas nécessaire, sauf que j'ai besoin d'inclure une nouvelle ligne supplémentaire quelque part pour porter le nombre d'espaces au minimum spécifié de cinq.

Notez également que, comme la soumission de ThisSuitIsBlackNot, ce programme nécessite le module Term :: ReadKey du CPAN. Sur Debian / Ubuntu Linux, ce module, s'il n'est pas déjà présent, peut être facilement installé avec la commande sudo apt-get install libterm-readkey-perl.

De plus, pour enregistrer quelques caractères, ce programme ne restaure pas le mode d'entrée à la normale à la sortie, vous pouvez donc vous retrouver incapable de voir ce que vous tapez par la suite. L'exécution de la commande shell stty saneou resetdevrait résoudre ce problème. Ce problème pourrait être résolu, au prix de 10 octets supplémentaires, avec:

use
Term'ReadKey;ReadMode
4;open
0;ReadKey,print
for<0>;ReadMode
0

Bonus: Pure quine, 81 octets

$_=q{use
Term'ReadKey;ReadMode
4;ReadKey,say
for
split$/,
"\$_=q{$_};eval"};eval

Encore une fois, la nouvelle ligne après la virgule n'est nécessaire que pour respecter le minimum de cinq espaces blancs.

Contrairement au programme de 56 octets ci-dessus, cette version n'a pas réellement besoin de lire son propre code source, car il est basé sur une quine - en particulier, sur cette quine:

$_=q{say"\$_=q{$_};eval"};eval

La bonne chose à propos de ce quine est qu'il peut facilement transporter une "charge utile" arbitraire dans le q{ }bloc, sans avoir à le répéter. Bien qu'il ne puisse pas tout à fait battre<0> dans la brièveté, il se rapproche assez.

Remarque: Ce programme utilise la fonctionnalité Perl 5.10+ sayet doit donc être appelé avec le commutateur de ligne de commande -M5.010(ou -E). Selon un consensus établi sur la méta, ces commutateurs utilisés pour activer les fonctionnalités du langage moderne ne comptent pas comme des caractères supplémentaires . La solution la plus courte sans laquelle je peux trouver sayest de 83 octets:

$_=q{use
Term'ReadKey;ReadMode
4;ReadKey,print
for
split/^/,
"\$_=q{$_};eval"};eval

Les deux peuvent également être rendus plus conviviaux pour les terminaux en (joignant les deux dernières lignes et) en insérant:

;ReadMode
0

avant le dernier }.

Ilmari Karonen
la source
Sensationnel. Juste wow. Très sympa.
ThisSuitIsBlackNot
+1, mais je recommande d'avoir l'habitude de taper stty saneau lieu de reset(ce qui pourrait, sur certains systèmes d'exploitation, faire quelque chose de plus que simplement réinitialiser certains paramètres terminaux ^^)
Olivier Dulac
Très belle solution. FWIW, open F,$0et <F>pourrait être remplacé par open 0et <0>. De plus, je dirais qu'un poste dans la méta ne constitue pas vraiment un consensus. L'option " -M5.01n'amène pas la langue à un point spécifique" , comme le suggère l'auteur, elle active des fonctionnalités. Il n'y a pas de version de perl pour laquelle ces fonctionnalités sont activées par défaut.
primo
3
@primo: Veuillez publier votre propre réponse sur le fil de méta, si vous n'êtes pas d'accord avec la réponse existante. Le fait que personne ne l'ait fait depuis trois ans et demi, jusqu'à présent, suggère un degré raisonnable de consensus, au moins parmi les habitués ici qui visitent activement les méta, mais le consensus peut toujours changer. (Quoi qu'il en soit, la façon dont je le vois, si ruby golfscript.rb foo.gscompte comme une commande valide pour exécuter un programme écrit en GolfScript, perl -M5.010 foo.pldevrait alors compter comme une commande valide pour exécuter un programme écrit en "Perl 5.10". Mais ces arguments appartiennent vraiment à la méta, pas ici.)
Ilmari Karonen
5

Python 3 - 124 octets - 7 espaces


Code:

from curses import*
s=initscr();noecho()
for x in open(__file__).read().split(" "):s.getch();s.addstr(x+" ")
echo();endwin()

Non golfé:

from curses import*
# init curses
screen=initscr()
noecho()
# split code into spaces
code = open(__file__).read().split(" ")
for x in code:
    # wait for keypress
    screen.getch()
    # print a bit
    screen.addstr(x+" ")
# deactivate curses
echo()
endwin()

Version stylée:

from curses import*
s=initscr();noecho();start_color();init_pair(2,COLOR_GREEN,COLOR_BLACK)
for x in open(__file__).read().split(" "):s.getch();s.addstr(x+" ",color_pair(2))
echo();endwin()
matsjoyce
la source
4

Rubis, 85 , 71

require"io/console";f=File.open __FILE__;loop{STDIN.raw &:getc;print f.read(3)||exit}

Dommage que cela IO#rawne fasse pas partie de la bibliothèque standard.

Amélioration

require"io/console";24.times{|q|STDIN.raw &:getc;$><<IO.read($0,3,q*3)}

Celui-ci élimine l'appel à la sortie du noyau # et utilise des variables globales pour raccourcir le code.

ferdinand808
la source
4

Befunge - 21

~ $ g , 1 +:54*`#@_:0

Je suis assez content de cela, car je viens de découvrir Befunge. Si cela ne vous dérange pas de "taper" dans une fenêtre contextuelle, vous pouvez l'exécuter ici ou ici jusqu'à ce que je trouve un meilleur interprète en ligne.

Yann
la source
2

Powershell, 89

(gc $MyInvocation.MyCommand.Path).split(" ")|%{$l+="$_ ";write-host "$l";read-host ;cls}
tomkandy
la source
2

Python 3 - 299

a="""from curses import*
s=initscr()
raw()
noecho()
for x in e:
 s.getch()
 s.addstr(x+' ')
nocbreak()
echo()
endwin()
""";b="""e=(a+'a=#%s#;b=#%s#;%s'%(a,b,b.replace('#','""''"',4))+'exec(a)').split(' ')
""";e=('a="""%s""";b="""%s""";%s'%(a,b,b.replace('#','""''"',4))+'exec(a)').split(' ')
exec(a)

C'est une quine. Raccourci de 507 en utilisant execet en déplaçant certaines déclarations.

faubi
la source
2

C, 211 186 octets

Ma solution en C en utilisant la bibliothèque curses. Elle peut être plus longue que l'autre solution C, mais c'est une quine. Bien que cela ne soit pas requis par la question, c'est quand même assez agréable. Cela fonctionne aussi très bien:

#define R(x)#x
#define T(x)R(x)
#define S(p)char*s="#define R(x)#x\n#define T(x)R(x)\n#define S(p)"p"\nS(T(S(p)))";main(){initscr();noecho();while(*s)if(~getch())addch(*s++);}
S(T(S(p)))

Une version plus lisible avec des commentaires et des trucs:

#define R(x)#x /* macros to convert the source code in S into a C-string */
#define T(x)R(x)
#define S(p) char*s="#define R(x)#x\n" \
                    "#define T(x)R(x)\n" \
                    "#define S(p) " p "\n" \
                    "S(T(S(p)))";\
    main(){\
        initscr();\
        noecho(); /* don't echo input */ \
        while(*s)\
            if(~getch()) /*true if character has been typed */ \
                addch(*s++);\
}
S(T(S(p)))

compiler avec:

gcc -o h h.c -lncurses
MarcDefiant
la source
2

C - 136 135 132 octets (Windows uniquement)

*fopen();**v;b[ 1<<20];main(p,q){v=q; strcpy(b,*v);strcat(b,".c") ;for(*v=fopen(b,"r");~fscanf(*v,"%s",b);printf("%s ",b))getch();} 

Remarque: il y a un espace à la fin du programme, qui ne s'affichera probablement pas.

Je ne peux pas garantir que ce programme fonctionnera sur un seul ordinateur autre que le mien car il est incroyablement hacky. Les choses auraient été beaucoup plus simples lorsque tout le monde n'avait que des machines 32 bits. Ensuite, je n'aurais pas besoin de m'inquiéter d' sizeof(int*)avoir 8 ans (ce qui est certainement le cas; je l'ai imprimé pour être sûr) alors qu'il a sizeof(int)4 ans.

Heureusement, le nom de l'exécutable est stocké dans la première chaîne dans argv. Cependant, mettre un pointeur comme argument sur une fonction signifie que je dois spécifier explicitement le type de TOUS les arguments de la fonction - ce qui signifie que je devrais taper intdeux fois - un énorme gaspillage de caractères. Heureusement, j'ai trouvé une solution de contournement. J'ai eu le deuxième argument à main q, être juste un autre int. Puis attribuerq à une variable de type a int**réussi à récupérer tous les octets nécessaires de la pile.

Je n'ai pas réussi à trouver de telles astuces pour interpréter le type de retour de fopen comme un pointeur sans déclarer la fonction.

Edit: J'ai remarqué que je devrais utiliser à la ~fscanf(*v,"%s",b)place de fscanf(*v,"%s",b)>0car le retour est -1 lorsque EOF est atteint.

feersum
la source
Cette erreur se produit pour moi, donc je ne peux pas la tester, mais vous devriez pouvoir déclarer un pointeur vide ( void **v;) au lieu du prototypage fopen().
Comintern
@Comintern, ce changement ne m'a pas aidé à stocker correctement le résultat de fopen. Je ne vois pas pourquoi le remplacement de void par int devrait faire une différence, car tous les pointeurs sont de la même taille de toute façon.
feersum
Bon point. Encore plus courte et plus stable juste déclarer un pointeur bien - cela va en fait pour moi: b[1<<20];main(int *c,char **v){strcpy(b,*v);strcat(b,".c");c=fopen(b,"r");for(;fscanf(c,"%s",b)>0;printf("%s ",b))getch();}(je devais remplacer getchar()pour getch()bien).
Comintern
@Comintern, votre code se bloque toujours sur mon système, mais c'est du bon travail pour le faire fonctionner. Je suppose que c'est comme je l'ai dit - chaque version du programme fonctionnera sur 1 ordinateur.
feersum
Pourquoi n'utilisez-vous pas les prototypes K&R? Par exemple, *fopen()au lieu de *fopen(a,b)?
FUZxxl
1

Perl - 87 octets

#!/usr/bin/perl -040
use Term::ReadKey;open F,$0;ReadMode 3;print''.<F>while ReadKey 0

Je n'ai rien vu dans les règles sur ce qu'il faut faire une fois que le fichier a été lu jusqu'à la fin, il reste donc simplement en attente d'entrée après l'impression du dernier morceau.

ThisSuitIsBlackNot
la source
1

node.js avec LiveScript:

#!/usr/local/bin/lsc
console.log <| require \fs .readFileSync __filename, encoding: \utf8

version asynchrone:

#!/usr/local/bin/lsc
require \fs .readFile __filename, encoding: \utf8, -> console.log &1
homam
la source
1

Cobra - 147

class P
    def main
        while 1,for a in File.readLines(CobraCore.exePath[:-4]+'.cobra'),print if('[Console.readKey]'and (Console.cursorLeft=0)<1,a,'')*

CobraCore.exePath est tellement utile!

Οurous
la source
1

Javascript ES6, 154

Firefox 154 :

(a= (i=1,b="(a= "+a+")()",s="") => {window.onkeydown=()=>{clear();i=b.indexOf(" ",i+1),d=b.slice(0,i<0?b.length:i);console.log(s+d);if(i<0){i=0,s+=d}}})()

Chrome 175 :

( a= function (i,s){b="( a= "+a+")()";c=console,window.onkeydown=function(){c.clear();s=s||"",i=b.indexOf(" ",i+1),d=b.slice(0,i<0?b.length:i);c.log(s+d);if(i<0){i=0,s+=d}}})()

Les deux 274 :

( a= function (i,s){b="( a= "+a+")()";c=console,window.onkeydown=function(){(clear)?clear():c.clear?c.clear():0;s=s||"",i=b.indexOf(" ",i+1),d=b.slice(0,i<0?b.length:i);c.log(s+d);if(i<0){i=0,s+=d}}})()

Non golfé (chrome):

( a= function (i,s){        // starting index | undefined, output string
    b="( a= "+a+")()";      // get a string representation of the function
    c=console,
    window.onkeydown=function(){    // on each key down event
        c.clear();                  // clear the output 
        s=s||"";
        i=b.indexOf(" ",i+1);       // get the index of next space
        d=b.slice(0,i<0?b.length:i);// get the string part wanted
        c.log(s+d);                 // print the string
        if(i<0){
            i=0,                    // reset counters
            s+=d                    // adding the string to the main output
        }
    }
})()

A deux versions, car Chrome ne gère pas la fonction flèche et la console n'est pas effacée avec la même méthode

Firefox fonctionne avec firebug, il semble que la console développeur par défaut ne puisse pas être effacée d'un script.

Hacketo
la source
Avez-vous manqué l'exigence selon laquelle l'utilisateur doit appuyer sur des touches aléatoires pour imprimer la sortie?
Optimizer
bien sûr, je vais réécrire ça.
Hacketo
0

Groovy - 379

import java.nio.file.*
Path p = Paths.get(System.getProperty("user.dir"))
DirectoryStream<Path> f = Files.newDirectoryStream(p,"*.groovy")
try{for(e in f){read(e.toAbsolutePath().toString())}}
catch(Exception e){ }
finally{f.close()}

void read(String x){
    def s = new File(x).text
    for(e in s.replace("%n"," %n").split(" ")) 
        print e + " " 
    Thread.sleep(200)
}   

Puisqu'il n'y a pas getch()ou l'équivalent dans les langages Java et Java-esque comme Groovy ... fondamentalement, mon code ne gère pas les pressions de touches. C'est tout: D

Petit enfant
la source
0

C, 248 caractères

True quine

Fonctionne uniquement sous Unix, dans Windows, il serait implémenté à l'aide de _getch.

main(){char *p="main(){char *p=\"%s\",s[400];sprintf(s,p,p);system(\"stty raw\");for(p=s;*p!=0;putchar(*p++))getchar();system(\"stty cooked\");}",s[400];sprintf(s,p,p);system("stty raw");for(p=s;*p!=0;putchar(*p++))getchar();system("stty cooked");}
rorlork
la source
0

HTML et Javascript, 232 octets

<body><script>var n=0;var f=function (){document.onkeypress=function(){document.body.innerHTML+=("&lt;body>&lt;script>var n=0;var f="+f.toString()+"f()&lt;/script>&lt;/body>").split(" ")[n]+" ";n++;}};f()</script></body>

Le quine Javascript traditionnel, mais modifié.

JSFiddle ici .

BobTheAwesome
la source
0

SmileBASIC, 79 75 octets

LOAD"PRG1:"+PRGNAME$()
PRGEDIT 1
@L
IF BUTTON(2)THEN?PRGGET$();
WAIT
GOTO@L

Il est très facile d'obtenir une LIGNE spécifique d'un programme dans SmileBASIC, donc je mets juste les espaces avant chaque saut de ligne.Je pensais que j'étais si intelligent, en mettant les espaces avant chaque saut de ligne, mais apparemment, nous sommes autorisés à utiliser des sauts de ligne au lieu d'espaces ...

Explication:

LOAD "PRG1:"+PRGNAME$() 'load the code into slot 1 so we can easily read 1 line at a time
PRGEDIT 1 'Edit slot 1
@LOOP
IF BUTTON(2) THEN 'When a button is pressed...
                   PRINT PRGGET$(); 'get a line of code and print it
WAIT 'delay so we don't detect the same press multiple times in a single frame.
GOTO @LOOP 
12Me21
la source
-1

Haskell

{-# LANGUAGE CPP #-}
main = readFile __FILE__ >>= putStrLn
homam
la source
Cela imprime simplement sa source.
Carcigenicate