Utwórz program typu „hacker typer”, który renderuje własny kod źródłowy

25

Jeśli nie jesteś zaznajomiony z hakerem typer, zobacz hackertyper.net . Krótko mówiąc, jest to program, który generuje jeden fragment kodu na każde naciśnięcie klawisza, aby uzyskać efekt komediowy. ALE wersja hackertyper.net jest zbyt łatwa do wdrożenia. Po prostu wypisuje trzy znaki na raz z dowolnego fragmentu kodu. W przypadku tego wyzwania program musi wyprowadzić własny kod źródłowy i wydrukować jeden fragment kodu rozdzielany spacjami na jedno naciśnięcie klawisza.

Detale

  • Nie można na stałe kodować nazwy pliku dla programu; musi dynamicznie określać swoją nazwę. Jeśli program kompiluje się do pliku wykonywalnego, może dołączyć standardowe rozszerzenie pliku do nazwy pliku wykonywalnego (z wyjątkiem .exe, jeśli używasz systemu Windows) i założyć, że plik źródłowy znajduje się w katalogu pliku wykonywalnego. Na przykład, jeśli plik wykonywalny C nosi nazwę „hacker”, powinien pobrać swój kod źródłowy z pliku o nazwie „hacker.c” w tym samym katalogu. Jeśli skompilowany program ma rozszerzenie, należy je usunąć przed określeniem nazwy jego kodu źródłowego („typer.exe” -> „typer.cs”).
  • Programy muszą zawierać co najmniej 5 spacji, z co najmniej jedną postacią między każdą spacją. Oznacza to, że najmniejszy możliwy rozmiar tego wyzwania wynosi 9 bajtów. Przestrzenie nie muszą być kluczowe dla funkcjonowania programu.
  • Każde formatowanie (wcięcie, nowe wiersze itp.) Musi zostać zachowane na wyjściu. To formatowanie może zostać wydrukowane z kodem, który go poprzedza, lub następuje po nim, ważne jest, aby zachować formatowanie.
  • Unikaj używania komentarzy, aby spełnić wymagania 5 miejsca, chyba że nie ma innego sposobu na zaimplementowanie spacji w wybranym języku.

EDYCJA : Nowe linie mogą być używane zamiast spacji lub jako dodatek do spacji jako separatorów porcji.

DrJPepper
źródło
1
Jestem trochę zmieszany. Czy program powinien być quine, czy nie?
Orby
8
Sposób, w jaki go opisałeś, sprawia, że ​​brzmi to tak, jakby można było odczytać kod z oryginalnego pliku źródłowego, co nie byłoby quine. Myślę, że lepszym konkursem byłoby, gdyby program miał być prawdziwym quine.
Orby
1
@Orby powiedziałbym, że program nie jest quine w tradycyjnym znaczeniu, niezależnie od tego, czy czytanie źródła jest dozwolone, czy nie. Quines nie ma danych wejściowych, ale te programy wyraźnie.
Calvin's Hobbies
@DrJPepper Twój trzeci punkt brzmi, jakby każda sekwencja białych znaków liczyła się jako ogranicznik, ale wyraźnie mówisz, że jest tylko spacja. Możesz wyjaśnić?
Calvin's Hobbies
2
Wyzwanie to zachęca do czytania własnego kodu źródłowego programu, co zwykle jest dosłowne w konstrukcji quines.
feersum

Odpowiedzi:

13

bash, 51 58

for w in $(<$0);do read -sn 1;printf -- "$w ";done
Wola
źródło
2
To bash, a nie shell: To nie zadziała w myślniku, ( 2: read: Illegal option -s)
F. Hauri
1
Zakładając bash, można zamieniać cat $0i $(<$0)
@broslow thx za opinie; oznaczone bash, ta sama długość
Will
1
@Will Nie ma problemu. Czy IFS=\ rzeczywiście jest potrzebny, jeśli pominiesz shebang? Domyślny IFS jest podobny IFS=$'\n\t ', a ponieważ nie masz już nowego wiersza, nie sądzę, że musisz ograniczać go do samej przestrzeni.
1
for w in `<$0`;{ read \-sn1;printf $w\ ;}
jimmy23013
21

HTML i JavaScript, 123

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

Działa to podobnie do typera hakerów, ale z własnym kodem źródłowym. Daj mi znać, jeśli źle zrozumiałem zasady.

A oto stylowa wersja (170 znaków):

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

Zrobiłem demo . Jest modyfikowany, ponieważ JS Bin dodaje dużo dodatkowego kodu, ale ogólny pomysł jest taki sam.

grc
źródło
2
Byłbym zaskoczony, gdyby nie wyświetlało się to poprawnie bez tagów <html> i <head> oraz bez zamykania </body>. Byłbyś zaskoczony, jak bardzo wybaczające są wszystkie przeglądarki pod tym względem.
Czy
2
@Will Thanks. Podałem powód <head>, dla którego przeglądarka doda go, jeśli go nie ma, więc zawsze będzie wyświetlany. Ale zapomniałem o tym <html>.
grc
12

Perl + Term :: ReadKey, 56 bajtów

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

Dzięki ThisSuitIsBlackNot za oryginalną inspirację i primo za sugestie open 0i <0>.

Zauważ, że nowa linia po forjest właściwie niepotrzebna, z wyjątkiem tego, że muszę gdzieś dołączyć jedną nową linię, aby sprowadzić liczbę białych znaków do określonego minimum pięciu.

Należy również pamiętać, że podobnie jak przesłanie ThisSuitIsBlackNot, ten program wymaga modułu Term :: ReadKey z CPAN. W systemie Debian / Ubuntu Linux ten moduł, jeśli nie jest jeszcze obecny, można łatwo zainstalować za pomocą polecenia sudo apt-get install libterm-readkey-perl.

Ponadto, aby zaoszczędzić kilka znaków, ten program nie przywraca trybu wprowadzania do normalnego stanu po wyjściu, więc możesz nie być w stanie zobaczyć, co piszesz później. Wykonanie polecenia powłoki stty sanelub resetpowinno to naprawić. Ten problem można naprawić kosztem 10 dodatkowych bajtów za pomocą:

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

Bonus: czysty quine, 81 bajtów

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

Znów nowa linia po przecinku jest potrzebna tylko, aby spełnić minimum pięciu białych znaków.

W przeciwieństwie do powyższego 56-bajtowego programu ta wersja nie musi w rzeczywistości czytać własnego kodu źródłowego, ponieważ jest oparta na quinie - a konkretnie na tej quinie:

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

Zaletą tego quine jest to, że może on łatwo przenosić dowolną „ładowność” w q{ }bloku, bez konieczności powtarzania go. Chociaż nie może pobić <0>w skrócie, zbliża się całkiem.

Uwaga: Ten program korzysta z funkcji Perl 5.10+ say, dlatego należy go wywołać za pomocą przełącznika wiersza poleceń -M5.010(lub -E). Zgodnie z ustalonym konsensusem w sprawie meta, takie przełączniki używane do włączania nowoczesnych funkcji językowych nie są liczone jako dodatkowe znaki . Najkrótsze rozwiązanie bez którego mogę znaleźć sayto 83 bajty:

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

Oba z nich można również uczynić bardziej przyjaznymi dla terminali poprzez (połączenie dwóch ostatnich linii i) wstawienie:

;ReadMode
0

przed ostatnim }.

Ilmari Karonen
źródło
Łał. Po prostu łał. Bardzo fajny.
ThisSuitIsBlackNot
+1, ale zalecam przyzwyczajenie się do pisania stty sanezamiast reset(co w niektórych systemach operacyjnych czasami robi coś więcej niż tylko resetuje niektóre parametry terminala ^^)
Olivier Dulac
Bardzo fajne rozwiązanie. FWIW, open F,$0i <F>może być zastąpiony przez open 0i <0>. Ponadto twierdzę, że jeden post w meta tak naprawdę nie stanowi konsensusu. Ta opcja -M5.01nie „sprowadza języka do określonego punktu” , jak sugeruje autor, włącza funkcje. Nie ma wersji perla, dla której te funkcje są domyślnie włączone.
primo
3
@primo: Jeśli nie zgadzasz się z istniejącym, opublikuj własną odpowiedź w meta wątku. Fakt, że do tej pory nikt tego nie robił przez trzy i pół roku, sugeruje rozsądny stopień konsensusu, przynajmniej wśród stałych bywalców, którzy aktywnie odwiedzają meta, ale konsensus zawsze może się zmienić. (W każdym razie, moim zdaniem, jeśli ruby golfscript.rb foo.gsliczy się jako prawidłowe polecenie do uruchomienia programu napisanego w GolfScript, to perl -M5.010 foo.plpowinno się liczyć jako prawidłowe polecenie do uruchomienia programu napisanego w „Perlu 5.10”. Ale takie argumenty naprawdę należą do meta, a nie tutaj.)
Ilmari Karonen
5

Python 3 - 124 bajty - 7 spacji


Kod:

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

Nie golfowany:

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

Wersja w stylu:

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
źródło
4

Ruby, 85 , 71

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

Szkoda, że IO#rawnie jest częścią standardowej biblioteki.

Poprawa

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

Ten eliminuje wezwanie do wyjścia jądra # i używa zmiennych globalnych do skracania kodu.

ferdinand808
źródło
4

Befunge - 21

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

Jestem z tego całkiem zadowolony, ponieważ właśnie dowiedziałem się o Befunge. Jeśli nie masz nic przeciwko „wpisywaniu” okna wyskakującego, możesz uruchomić je tutaj lub tutaj, dopóki nie znajdę lepszego tłumacza online.

Yann
źródło
2

PowerShell, 89

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

To jest quine. Skrócono z 507 poprzez użycie execi przenoszenie niektórych instrukcji.

faubi
źródło
2

C, 211 186 bajtów

Moje rozwiązanie w C przy użyciu biblioteki curses. Może być dłuższy niż inne rozwiązanie C, ale jest to quine. Chociaż nie jest to wymagane przez pytanie, wciąż jest całkiem miłe. Działa również całkiem nieźle:

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

Bardziej czytelna wersja z kilkoma komentarzami i innymi rzeczami:

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

Połącz z:

gcc -o h h.c -lncurses
MarcDefiant
źródło
2

C - 136 135 132 bajtów (tylko 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();} 

Uwaga: na końcu programu znajduje się spacja, która prawdopodobnie się nie pojawi.

Nie mogę zagwarantować, że ten program będzie działał na jednym komputerze innym niż mój, ponieważ jest niesamowicie włamany. Gdyby wszyscy mieli tylko 32-bitowe maszyny, wszystko byłoby znacznie prostsze. Wtedy nie musiałbym się martwić, sizeof(int*)że będę miał 8 lat (co zdecydowanie jest; wydrukowałem to, żeby się upewnić), gdy sizeof(int)jest 4.

Na szczęście nazwa pliku wykonywalnego jest przechowywana w pierwszym ciągu w argv. Jednak umieszczenie wskaźnika jako argumentu funkcji oznacza, że ​​muszę jawnie określić typ WSZYSTKICH argumentów funkcji - co oznacza, że ​​musiałbym wpisać intdwa razy - ogromna strata znaków. Na szczęście znalazłem obejście. Miałem drugi argument do głównego q, bądź tylko kolejnym int. Następnie przypisanie qdo zmiennej typu int**jakimś sposobem udało się pobrać wszystkie niezbędne bajty ze stosu.

Nie udało mi się znaleźć takich sztuczek, aby zinterpretować typ zwracany fopenjako wskaźnik, bez deklarowania funkcji.

Edycja: Zauważyłem, że powinienem użyć ~fscanf(*v,"%s",b)zamiast, fscanf(*v,"%s",b)>0ponieważ zwracany jest -1 po osiągnięciu EOF.

feersum
źródło
To dla mnie segfault, więc nie mogę go przetestować, ale powinieneś być w stanie zadeklarować void pointer ( void **v;) zamiast prototypowania fopen().
Comintern
@Comintern ta zmiana nie pomogła mi poprawnie zapisać wyniku fopen. Nie rozumiem, dlaczego podstawienie void na int powinno mieć znaczenie, ponieważ i tak wszystkie wskaźniki są tego samego rozmiaru.
feersum
Słuszna uwaga. Jeszcze krótsze i bardziej stabilny po prostu zadeklarować wskaźnik chociaż - to faktycznie działa dla mnie: 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();}(miałem zastąpił getchar()na getch()choć).
Comintern,
@Comintern Twój kod nadal zawiesza się w moim systemie, ale fajna robota, aby go uruchomić. Myślę, że to tak, jak powiedziałem - każda wersja programu będzie działać na 1 komputerze.
feersum
Dlaczego nie używasz prototypów K&R? Np. *fopen()Zamiast *fopen(a,b)?
FUZxxl,
1

Perl - 87 bajtów

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

Nie widziałem nic w regułach dotyczących tego, co robić po przeczytaniu pliku do końca, więc po prostu czeka na dane wejściowe po wydrukowaniu ostatniej porcji.

ThisSuitIsBlackNot
źródło
1

node.js z LiveScript:

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

wersja asynchroniczna:

#!/usr/local/bin/lsc
require \fs .readFile __filename, encoding: \utf8, -> console.log &1
homam
źródło
1

Kobra - 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 jest bardzo przydatne!

Obrzydliwe
źródło
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}}})()

Zarówno 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}}})()

Nie golfowany (chrom):

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

Ma dwie wersje, ponieważ Chrome nie obsługuje funkcji strzałek, a konsola nie jest czyszczona tą samą metodą

Firefox jeden działa z firebug, wydaje się, że domyślnej konsoli programisty nie można usunąć ze skryptu.

Hacketo
źródło
Czy przegapiłeś wymóg, że użytkownik musi nacisnąć losowe klawisze, aby wydrukować wydruk?
Optymalizator
pewnie!, przepiszę to.
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)
}   

Ponieważ nie ma getch()ani nie ma odpowiednika w językach Java i językach Java, takich jak Groovy ... w zasadzie mój kod nie obsługuje naciśnięć klawiszy. To wszystko: D

Małe dziecko
źródło
0

C, 248 znaków

Prawdziwy quine

Działa tylko w systemie Unix, w systemie Windows można go zaimplementować za pomocą _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
źródło
0

HTML i JavaScript, 232 bajty

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

Tradycyjna wersja Javascript, ale zmodyfikowana.

JSFiddle tutaj .

BobTheAwesome
źródło
0

SmileBASIC, 79 75 bajtów

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

Bardzo łatwo jest uzyskać konkretną LINIĘ programu w SmileBASIC, więc po prostu wstawiam spacje przed łamaniem każdej linii. Myślałem, że jestem taki sprytny, stawiając spacje przed każdym łamaniem linii, ale najwyraźniej wolno nam używać łamania linii zamiast spacji ...

Wyjaśnienie:

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
źródło
-1

Haskell

{-# LANGUAGE CPP #-}
main = readFile __FILE__ >>= putStrLn
homam
źródło
To po prostu drukuje jego źródło.
Carcigenicate