Crea un programma "hacker typer" che esegua il rendering del proprio codice sorgente


25

Se non si ha familiarità con il pirata informatico di hacker, consultare hackertyper.net . In breve, è un programma che genera un pezzo di una base di codice per sequenza di tasti per un effetto comico. MA, la versione di hackertyper.net è fin troppo facile da implementare. Emette semplicemente tre caratteri alla volta da un pezzo di codice arbitrario . Per questa sfida, un programma deve generare il proprio codice sorgente e stampare una porzione di codice delimitata da spazi per sequenza di tasti.

Dettagli

  • Non è possibile codificare un nome file per il programma; deve determinare il suo nome in modo dinamico. Se il programma viene compilato in un eseguibile, può aggiungere l'estensione del file standard al nome dell'eseguibile (escluso il file .exe se si utilizza Windows) e supporre che il file di origine si trovi nella directory dell'eseguibile. Ad esempio, se un eseguibile C è chiamato "hacker", dovrebbe estrarre il suo codice sorgente da un file chiamato "hacker.c" nella stessa directory. Se un programma compilato ha un'estensione, dovrebbe essere eliminato prima di determinare il nome del suo codice sorgente ("typer.exe" -> "typer.cs").
  • I programmi devono contenere almeno 5 spazi, con almeno un carattere tra ogni spazio. Ciò significa che la dimensione più piccola possibile per questa sfida è di 9 byte. Gli spazi non devono essere cruciali per il funzionamento del programma.
  • Qualsiasi formattazione (rientro, nuove righe, ecc.) Deve essere mantenuta nell'output. Questa formattazione può essere stampata con il codice che la procede o la segue, ciò che conta è che la formattazione venga mantenuta.
  • Evita di usare i commenti per soddisfare i 5 requisiti di spazio a meno che non ci sia altro modo per implementare gli spazi nella tua lingua preferita.

EDIT : le nuove linee possono essere utilizzate al posto o in aggiunta agli spazi come separatori di blocchi.


1
Sono un po 'confuso. Il programma dovrebbe essere un quine o no?
Orby,

8
Il modo in cui l'hai descritto fa sembrare che sia accettabile leggere il codice dal file sorgente originale, che non sarebbe un quine. Penso che sarebbe una gara migliore se il programma dovesse essere un vero quine.
Orby,

1
@Orby Direi che il programma non è un quin nel senso tradizionale, indipendentemente dal fatto che la lettura della fonte sia consentita o meno. Le query non hanno input, ma questi programmi lo fanno chiaramente.
Calvin's Hobbies,

@DrJPepper Il tuo terzo punto elenco fa sembrare che ogni sequenza di spazi bianchi contenga un delimitatore, ma in particolare dici che lo spazio è solo. Puoi chiarire?
Calvin's Hobbies,

2
Questa sfida incoraggia la lettura del codice sorgente del programma, una pratica tipicamente verboten nella costruzione di quines.
feersum

Risposte:


13

bash, 51 58

for w in $(<$0);do read -sn 1;printf -- "$w ";done

2
È bash, non shell: non funzionerà sotto il trattino, ( 2: read: Illegal option -s)
F. Hauri,

1
Supponendo bash, può sostituire cat $0e tildes con$(<$0)

@broslow thx per feedback; etichettato bash, stessa lunghezza
Will

1
@Will Nessun problema. In IFS=\ realtà è necessario se si omette lo shebang? L'IFS predefinito è qualcosa di simile IFS=$'\n\t 'e dal momento che non hai più una nuova riga, non penso che devi limitarlo solo allo spazio.

1
for w in `<$0`;{ read \-sn1;printf $w\ ;}
jimmy23013,

21

HTML e JavaScript, 123

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

Funziona in modo simile al pirata informatico hacker, ma con il suo codice sorgente. Fammi sapere se ho frainteso le regole.

Ed ecco una versione in stile (170 caratteri):

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

Ho fatto una demo . È stato modificato perché JS Bin aggiunge molto codice aggiuntivo, ma l'idea generale è la stessa.


2
Sarei sorpreso se questo non fosse visualizzato correttamente senza i tag <html> e <head> e senza una chiusura </body>. Saresti sorpreso di quanto tutti i browser siano molto indulgenti in questo senso.
Sarà il

2
@Will Thanks. Il motivo per cui ho incluso <head>è che il browser lo aggiungerà se non è presente, quindi verrà sempre visualizzato. Mi sono dimenticato <html>però.
GRC,

12

Perl + Term :: ReadKey, 56 byte

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

Grazie a ThisSuitIsBlackNot per l'ispirazione originale e al primo per aver suggerito open 0e <0>.

Si noti che la nuova riga successiva non forè effettivamente necessaria, tranne per il fatto che devo includere una riga aggiuntiva in più da qualche parte per portare il conteggio degli spazi bianchi al minimo specificato di cinque.

Si noti inoltre che, come l'invio di ThisSuitIsBlackNot, questo programma richiede il modulo Term :: ReadKey da CPAN. Su Debian / Ubuntu Linux, questo modulo, se non già presente, può essere facilmente installato con il comando sudo apt-get install libterm-readkey-perl.

Inoltre, per salvare alcuni caratteri, questo programma non ripristina la modalità di input su normale all'uscita, quindi potresti non riuscire a vedere ciò che stai digitando in seguito. L'esecuzione del comando shell stty saneo resetdovrebbe risolverlo. Questo problema potrebbe essere risolto, al costo di 10 byte extra, con:

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

Bonus: puro quine, 81 byte

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

Ancora una volta, la nuova riga dopo la virgola è necessaria solo per soddisfare il minimo di cinque spazi bianchi.

A differenza del programma a 56 byte sopra, questa versione in realtà non ha bisogno di leggere il proprio codice sorgente, poiché si basa su un quine - in particolare, su questo quine:

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

La cosa bella di questo quine è che può facilmente trasportare un "payload" arbitrario all'interno del q{ }blocco, senza doverlo ripetere. Sebbene non riesca a battere <0>in breve, si avvicina abbastanza.

Nota: questo programma utilizza la sayfunzione Perl 5.10+ e quindi deve essere invocato con l' opzione -M5.010(o -E) della riga di comando. Secondo il consenso stabilito sulla meta, tali interruttori utilizzati per abilitare le funzionalità del linguaggio moderno non contano come caratteri extra . La soluzione più breve che posso trovare senzasay è 83 byte:

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

Entrambe possono anche essere rese più intuitive dal terminale (unendo le ultime due righe e) inserendo:

;ReadMode
0

prima dell'ultimo }.


Wow. Wow. Molto bello.
ThisSuitIsBlackNon

+1, ma consiglio di avere l'abitudine di digitare stty saneinvece di reset(che potrebbe, su alcuni sistemi operativi, talvolta fare qualcosa di più del semplice ripristino di alcuni parametri terminali ^^)
Olivier Dulac

Soluzione molto bella. FWIW, open F,$0e <F>potrebbe essere sostituito con open 0e <0>. Inoltre, direi che un post in meta non costituisce in realtà un consenso. L'opzione -M5.01non "porta la lingua a un punto specifico" , come suggerisce l'autore, abilita le funzionalità. Non esiste una versione di perl per cui queste funzionalità sono abilitate per impostazione predefinita.
primo

3
@primo: pubblica la tua risposta al meta thread, se non sei d'accordo con quello esistente. Il fatto che nessuno lo abbia fatto in tre anni e mezzo, finora, suggerisce un ragionevole grado di consenso, almeno tra i clienti abituali che visitano attivamente meta, ma il consenso può sempre cambiare. (Comunque, per come la vedo io, se ruby golfscript.rb foo.gsconta come un comando valido per eseguire un programma scritto in GolfScript, allora perl -M5.010 foo.pldovrebbe essere considerato un comando valido per eseguire un programma scritto in "Perl 5.10". Ma tali argomenti appartengono davvero a meta, non qui.)
Ilmari Karonen il

5

Python 3 - 124 byte - 7 spazi


Codice:

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

Ungolfed:

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

Versione in stile:

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

4

Ruby, 85 , 71

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

Peccato che IO#rawnon faccia parte della libreria standard.

Miglioramento

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

Questo elimina la chiamata all'uscita del kernel # e utilizza le variabili globali per abbreviare il codice.


4

Befunge - 21

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

Sono abbastanza contento di questo, appena ho scoperto Befunge. Se non ti dispiace "digitare" in una finestra popup, puoi eseguirlo qui o qui finché non trovo un interprete online migliore.


2

Powershell, 89

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

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)

È un quine. Abbreviato da 507 usando exece spostando alcune dichiarazioni in giro.


2

C, 211 186 byte

La mia soluzione in C usando la libreria curses. Potrebbe essere più lungo dell'altra soluzione C, ma è un quine. Sebbene non sia richiesto dalla domanda, è comunque piuttosto carino. Funziona anche abbastanza bene:

#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 versione più leggibile con alcuni commenti e cose:

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

compilare con:

gcc -o h h.c -lncurses

2

C - 136 135 132 byte (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: c'è uno spazio alla fine del programma, che probabilmente non verrà visualizzato.

Non posso garantire che questo programma funzionerà su un singolo computer diverso dal mio in quanto è incredibilmente confuso. Le cose sarebbero state molto più semplici quando tutti avessero solo macchine a 32 bit. Quindi non avrei bisogno di preoccuparmisizeof(int*) essere 8 (che è sicuramente; l'ho stampato per essere sicuro) mentre sizeof(int)è 4.

Fortunatamente, il nome dell'eseguibile è memorizzato nella prima stringa in argv. Tuttavia, inserire un puntatore come argomento di una funzione significa che devo specificare esplicitamente il tipo di TUTTI gli argomenti della funzione - il che significa che dovrei digitare intdue volte - un enorme spreco di caratteri. Fortunatamente ho trovato una soluzione alternativa. Ho avuto il secondo argomento di main q, essere solo un altro int. Quindi assegnando qa una variabile di tipoint** qualche modo è riuscita a catturare tutti i byte necessari dallo stack.

Non sono riuscito a trovare tali trucchi per interpretare il tipo di ritorno di fopen come puntatore senza dichiarare la funzione.

Modifica: ho notato che dovrei usare ~fscanf(*v,"%s",b)invece che fscanf(*v,"%s",b)>0poiché il ritorno è -1 quando viene raggiunto EOF.


Questo segfault per me, quindi non posso provarlo, ma dovresti essere in grado di dichiarare un puntatore vuoto ( void **v;) invece di prototipare fopen().
Comintern,

@Comintern questa modifica non mi ha aiutato a memorizzare correttamente il risultato di fopen. Non vedo perché la sostituzione di void con int dovrebbe fare la differenza, dato che tutti i puntatori hanno comunque le stesse dimensioni.
feersum,

Buon punto. Ancora più breve e più stabile per solo dichiarare un puntatore però - questo in realtà funziona per me: 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();}(ho dovuto sostituire getchar()per getch()però).
Comintern,

@Comintern il tuo codice si blocca ancora sul mio sistema, ma bel lavoro farlo funzionare. Immagino sia come ho detto - ogni versione del programma verrà eseguita su 1 computer.
feersum

Perché non usi i prototipi K&R? Ad esempio *fopen()invece di *fopen(a,b)?
FUZxxl,

1

Perl - 87 byte

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

Non ho visto nulla nelle regole su cosa fare una volta che il file è stato letto fino alla fine, quindi rimane semplicemente in attesa di input dopo aver stampato l'ultimo blocco.


1

node.js con LiveScript:

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

versione asincrona:

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

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 è così utile!


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

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

Ungolfed (cromato):

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

Ha due versioni, perché Chrome non gestisce la funzione freccia e la console non viene cancellata con lo stesso metodo

Quello di Firefox funziona con firebug, sembra che la console di sviluppo predefinita non possa essere cancellata da uno script.


Hai perso il requisito che l'utente deve premere i tasti casuali per stampare l'output?
Ottimizzatore

certo!, riscriverò questo.
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)
}   

Dal momento che non esiste un getch()equivalente o in linguaggi Java e Java come Groovy ... fondamentalmente il mio codice non gestisce i tasti premuti. Questo è tutto: D


0

C, 248 caratteri

Vero quine

Funziona solo con unix, in Windows sarebbe implementato 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");}

0

HTML e Javascript, 232 byte

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

Quine Javascript tradizionale, ma modificato.

JSFiddle qui .


0

SmileBASIC, 79 75 byte

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

È molto semplice ottenere una LINEA specifica di un programma in SmileBASIC, quindi ho appena messo gli spazi prima di ogni interruzione di riga.Pensavo di essere così intelligente, mettendo gli spazi prima di ogni interruzione di riga, ma a quanto pare ci è permesso usare interruzioni di riga anziché spazi ...

Spiegazione:

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 

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.