Cree un programa "hacker typer" que represente su propio código fuente

25

Si no está familiarizado con hacker typer, consulte hackertyper.net . En resumen, es un programa que genera un fragmento de una base de código por pulsación de tecla para un efecto cómico. PERO, la versión hackertyper.net es demasiado fácil de implementar. Simplemente genera tres caracteres a la vez desde un código arbitrario . Para este desafío, un programa debe generar su propio código fuente e imprimir un fragmento de código delimitado por espacios por pulsación de tecla.

Detalles

  • Uno no puede codificar un nombre de archivo para el programa; debe determinar su nombre dinámicamente. Si el programa se compila en un ejecutable, puede agregar la extensión de archivo estándar al nombre del ejecutable (excluyendo el .exe si usa Windows) y asumir que el archivo fuente está dentro del directorio del ejecutable. Por ejemplo, si un ejecutable en C se llama "hacker", debe extraer su código fuente de un archivo llamado "hacker.c" en su mismo directorio. Si un programa compilado tiene una extensión, debe descartarse antes de determinar el nombre de su código fuente ("typer.exe" -> "typer.cs").
  • Los programas deben contener al menos 5 espacios, con al menos un carácter entre cada espacio. Esto significa que el tamaño más pequeño posible para este desafío es de 9 bytes. Los espacios no tienen que ser cruciales para el funcionamiento del programa.
  • Cualquier formato (sangría, nuevas líneas, etc.) debe mantenerse en la salida. Este formato puede imprimirse con el código que lo sigue o seguirlo, lo importante es mantener el formato.
  • Evite usar comentarios para satisfacer los 5 requisitos de espacio a menos que no haya otra forma de implementar los espacios en el idioma que elija.

EDITAR : Se pueden usar nuevas líneas en lugar de, o además de, espacios como separadores de fragmentos.

DrJPepper
fuente
1
Estoy un poco confundida. ¿El programa debería ser un quine o no?
Orby
8
La forma en que lo describió hace que parezca aceptable leer el código del archivo fuente original, lo que no sería una quine. Creo que sería un mejor concurso si el programa tuviera que ser una quine real.
Orby
1
@Orby Yo diría que el programa no es una quine en el sentido tradicional, independientemente de si la lectura de la fuente está permitida o no. Quines no tiene aportes, pero estos programas claramente los tienen.
Aficiones de Calvin
@DrJPepper Su tercer punto de viñeta hace que parezca que cualquier secuencia de espacios en blanco cuenta como un delimitador, pero usted dice específicamente que solo hay espacio. ¿Puedes aclarar?
Aficiones de Calvin
2
Este desafío fomenta la lectura del propio código fuente del programa, una práctica típicamente verboten en la construcción de quines.
feersum

Respuestas:

13

golpe, 51 58

for w in $(<$0);do read -sn 1;printf -- "$w ";done
Será
fuente
2
Es bash, no shell: esto no funcionará bajo el tablero, ( 2: read: Illegal option -s)
F. Hauri
1
Asumiendo bash, puede reemplazar cat $0e tildes con$(<$0)
@broslow thx para comentarios; etiquetado como bash, misma duración
Será el
1
@ No habrá problema. ¿Es IFS=\ realmente necesario si omite el shebang? El IFS predeterminado es algo así IFS=$'\n\t ', y como ya no tiene una nueva línea, no creo que deba limitarla solo al espacio.
1
for w in `<$0`;{ read \-sn1;printf $w\ ;}
jimmy23013
21

HTML y JavaScript, 123

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

Esto funciona de manera similar al hacker typer, pero con su propio código fuente. Avísame si he entendido mal las reglas.

Y aquí hay una versión con estilo (170 caracteres):

<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>

He hecho una demostración . Se modificó porque JS Bin agrega mucho código extra, pero la idea general es la misma.

grc
fuente
2
Me sorprendería si esto no se procesara correctamente sin las etiquetas <html> y <head>, y sin un cierre </body>. Te sorprendería lo indulgentes que son todos los navegadores a este respecto.
Will
2
@ Gracias. La razón que incluí <head>fue que el navegador lo agregará si no está allí, por lo que siempre se mostrará. Aunque me olvidé <html>.
grc
12

Perl + Término :: ReadKey, 56 bytes

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

Gracias a ThisSuitIsBlackNot por la inspiración original, y a primo por sugerir open 0y <0>.

Tenga en cuenta que la nueva línea posterior fores realmente innecesaria, excepto que necesito incluir una nueva línea adicional en algún lugar para llevar el recuento de espacios en blanco hasta el mínimo especificado de cinco.

También tenga en cuenta que, al igual que el envío de ThisSuitIsBlackNot, este programa requiere el módulo Term :: ReadKey de CPAN. En Debian / Ubuntu Linux, este módulo, si aún no está presente, se puede instalar fácilmente con el comando sudo apt-get install libterm-readkey-perl.

Además, para guardar algunos caracteres, este programa no restaura el modo de entrada a la normalidad al salir, por lo que es posible que no pueda ver lo que está escribiendo después. Ejecutando el comando de shell stty saneo resetdebería solucionarlo. Este problema podría solucionarse, a un costo de 10 bytes adicionales, con:

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

Bonus: quine puro, 81 bytes

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

Nuevamente, la nueva línea después de la coma solo es necesaria para cumplir con el mínimo de cinco espacios en blanco.

A diferencia del programa de 56 bytes anterior, esta versión en realidad no necesita leer su propio código fuente, ya que se basa en una quine, específicamente, en esta quine:

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

Lo bueno de este quine es que puede transportar fácilmente una "carga útil" arbitraria dentro del q{ }bloque, sin tener que repetirlo. Si bien no puede vencer <0>en brevedad, se acerca bastante.

Nota: Este programa utiliza la función Perl 5.10+ sayy, por lo tanto, debe invocarse con el -M5.010(o -E) interruptor de línea de comando. Según el consenso establecido sobre meta, tales interruptores utilizados para habilitar las características del lenguaje moderno no cuentan como caracteres adicionales . La solución más corta que puedo encontrar sin sayes de 83 bytes:

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

Ambos también se pueden hacer más amigables con la terminal (uniendo las dos últimas líneas e) insertando:

;ReadMode
0

antes de la última }.

Ilmari Karonen
fuente
Guau. Simplemente guau. Muy genial.
ThisSuitIsBlackNot
+1, pero recomiendo tener el hábito de escribir en stty sanelugar de reset(lo que, en algunos sistemas operativos, a veces podría estar haciendo algo más que simplemente restablecer algunos parámetros terminales ^^)
Olivier Dulac,
Muy buena solución. FWIW, open F,$0y <F>podría ser reemplazado con open 0y <0>. Además, diría que una publicación en meta no constituye realmente un consenso. La opción -M5.01no "lleva el idioma a un punto específico" , como sugiere el autor, habilita funciones. No hay una versión de perl para la que estas funciones estén habilitadas de forma predeterminada.
primo
3
@primo: publique su propia respuesta al metahilo, si no está de acuerdo con la existente. El hecho de que nadie lo haya hecho en tres años y medio, hasta ahora, sugiere un grado razonable de consenso, al menos entre los clientes habituales que visitan activamente el meta, pero el consenso siempre puede cambiar. (De todos modos, tal como lo veo, si ruby golfscript.rb foo.gscuenta como un comando válido para ejecutar un programa escrito en GolfScript, entonces perl -M5.010 foo.pldebería contar como un comando válido para ejecutar un programa escrito en "Perl 5.10". Pero tales argumentos realmente pertenecen al meta, no aquí.)
Ilmari Karonen
5

Python 3 - 124 bytes - 7 espacios


Código:

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

Sin 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()

Versión con estilo:

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
fuente
4

Ruby, 85 , 71

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

Lástima que IO#rawno sea parte de la biblioteca estándar.

Mejora

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

Este elimina la llamada a Kernel # exit y usa variables globales para acortar el código.

ferdinand808
fuente
4

Befunge - 21

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

Estoy bastante satisfecho con esto, ya que me acabo de enterar de Befunge. Si no le importa "escribir" en una ventana emergente, puede ejecutarlo aquí o aquí hasta que encuentre un mejor intérprete en línea.

Yann
fuente
2

Powershell, 89

(gc $MyInvocation.MyCommand.Path).split(" ")|%{$l+="$_ ";write-host "$l";read-host ;cls}
tomkandy
fuente
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)

Es una quine. Se redujo de 507 al usar execy mover algunas declaraciones.

faubi
fuente
2

C, 211 186 bytes

Mi solución en C usando la biblioteca de maldiciones. Puede ser más largo que la otra solución de C, pero es una quine. Aunque no es requerido por la pregunta, sigue siendo bastante agradable. También funciona bastante 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)))

Una versión más legible con algunos comentarios y cosas:

#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)))

compilar con:

gcc -o h h.c -lncurses
MarcDefiant
fuente
2

C - 136135132 bytes (solo Windows)

*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();} 

Nota: hay un espacio al final del programa, que probablemente no aparecerá.

No puedo garantizar que este programa funcione en una sola computadora que no sea la mía, ya que es increíblemente hacky. Las cosas habrían sido mucho más simples cuando todos tenían máquinas de 32 bits. Entonces no tendría que preocuparme por sizeof(int*)tener 8 (lo que definitivamente es; lo imprimí para asegurarme) mientras sizeof(int)tenga 4.

Felizmente, el nombre del ejecutable se almacena en la primera cadena en argv. Sin embargo, poner un puntero como argumento para una función significa que tengo que especificar explícitamente el tipo de TODOS los argumentos de la función, lo que significa que tendría que escribir intdos veces, una gran pérdida de caracteres. Afortunadamente encontré una solución alternativa. Tuve el segundo argumento para main q, ser solo otro int. Luego, asignar qa una variable de tipo de int**alguna manera logró capturar todos los bytes necesarios de la pila.

No tuve éxito en encontrar tales trucos para interpretar el tipo de retorno fopencomo un puntero sin declarar la función.

Editar: Notado que debería usar en ~fscanf(*v,"%s",b)lugar de fscanf(*v,"%s",b)>0ya que el retorno es -1 cuando se alcanza EOF.

Feersum
fuente
Esto es un error para mí, así que no puedo probarlo, pero deberías poder declarar un puntero vacío ( void **v;) en lugar de crear prototipos fopen().
Comintern
@Comintern este cambio no me ayudó a almacenar correctamente el resultado de fopen. No veo por qué sustituir void por int debería hacer la diferencia, ya que todos los punteros son del mismo tamaño de todos modos.
fiesta del
Buen punto. Aún más corto y más estable que acaba de declarar un puntero sin embargo - esto realmente funciona para mí: 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();}(tuve que sustituir getchar()por getch()embargo).
Comintern
@Comintern su código aún se bloquea en mi sistema, pero es un buen trabajo hacerlo funcionar Supongo que es como dije: cada versión del programa se ejecutará en 1 computadora.
fiesta del
¿Por qué no usas prototipos de K&R? Por ejemplo, en *fopen()lugar de *fopen(a,b)?
FUZxxl
1

Perl - 87 bytes

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

No vi nada en las reglas sobre qué hacer una vez que el archivo se ha leído hasta el final, por lo que simplemente se queda esperando la entrada después de imprimir el último fragmento.

ThisSuitIsBlackNot
fuente
1

node.js con LiveScript:

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

versión asincrónica:

#!/usr/local/bin/lsc
require \fs .readFile __filename, encoding: \utf8, -> console.log &1
homam
fuente
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 es muy útil!

Οurous
fuente
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}}})()

Ambos 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}}})()

Sin golf (cromo):

( 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
        }
    }
})()

Tiene dos versiones, porque Chrome no maneja la función de flecha y la consola no se borra con el mismo método

El Firefox uno funciona con firebug, parece que la consola de desarrollador predeterminada no se puede borrar de un script.

Hacketo
fuente
¿Se perdió el requisito de que el usuario tenga que presionar teclas aleatorias para imprimir la salida?
Optimizador
¡Seguro !, reescribiré esto.
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)
}   

Como no hay ninguno getch()o equivalente en los lenguajes Java y Java-esque como Groovy ... básicamente mi código no maneja las pulsaciones de teclas. Eso es todo: D

Niño pequeño
fuente
0

C, 248 caracteres

Quine verdadero

Solo funciona en Unix, en Windows se implementaría usando _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
fuente
0

HTML y Javascript, 232 bytes

<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>

El tradicional Javascript quine, pero modificado.

JS Violín aquí .

BobTheAwesome
fuente
0

SmileBASIC, 79 75 bytes

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

Es muy fácil obtener una LÍNEA específica de un programa en SmileBASIC, así que solo pongo los espacios antes de cada salto de línea. Pensé que era muy inteligente, colocando los espacios antes de cada salto de línea, pero aparentemente se nos permite usar saltos de línea en lugar de espacios ...

Explicación:

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
fuente
-1

Haskell

{-# LANGUAGE CPP #-}
main = readFile __FILE__ >>= putStrLn
homam
fuente
Esto solo imprime su fuente.
Carcigenicate