Buat program "hacker typer" yang membuat kode sumbernya sendiri


25

Jika Anda tidak terbiasa dengan peretas hacker, lihat hackertyper.net . Singkatnya, ini adalah sebuah program yang mengeluarkan satu potongan basis kode per keystroke untuk efek komedi. TETAPI, versi hackertyper.net terlalu mudah untuk diimplementasikan. Ini hanya menghasilkan tiga karakter sekaligus dari sepotong kode sewenang - wenang . Untuk tantangan ini, suatu program harus mengeluarkan kode sumbernya sendiri, dan mencetak satu spasi yang dibatasi potongan kode per penekanan tombol.

Detail

  • Seseorang tidak bisa membuat kode nama file untuk program; itu harus menentukan namanya secara dinamis. Jika program mengkompilasi ke executable, ia dapat menambahkan ekstensi file standar ke nama executable (tidak termasuk .exe jika menggunakan Windows) dan menganggap bahwa file sumber berada di dalam direktori executable. Sebagai contoh, jika C executable bernama "hacker", itu harus menarik kode sumbernya dari file bernama "hacker.c" di direktori yang sama. Jika sebuah program yang dikompilasi memiliki ekstensi, ia harus dibuang sebelum menentukan nama kode sumbernya ("typer.exe" -> "typer.cs").
  • Program harus mengandung setidaknya 5 spasi, dengan setidaknya satu karakter di antara setiap ruang. Ini berarti bahwa ukuran terkecil yang mungkin untuk tantangan ini adalah 9 byte. Ruang tidak harus penting untuk berfungsinya program.
  • Setiap pemformatan (indentasi, baris baru, dll.) Harus dipertahankan dalam output. Format ini dapat dicetak dengan kode yang menghasilkannya atau mengikutinya, yang penting format tetap dipertahankan.
  • Hindari menggunakan komentar untuk memenuhi persyaratan 5 ruang kecuali jika tidak ada cara lain untuk mengimplementasikan ruang dalam bahasa pilihan Anda.

EDIT : Baris baru dapat digunakan sebagai pengganti, atau sebagai tambahan, spasi sebagai pemisah chunk.


1
Saya agak bingung. Haruskah program menjadi quine, atau tidak?
Orby

8
Cara Anda menggambarkannya membuatnya terdengar seolah-olah dapat diterima untuk membaca kode dari file sumber asli, yang tidak akan menjadi quine. Saya pikir ini akan menjadi kontes yang lebih baik jika programnya harus quine yang sebenarnya.
Orby

1
@Orby Saya akan mengatakan program ini bukan quine dalam arti tradisional, terlepas dari apakah sumber membaca diperbolehkan atau tidak. Quines tidak memiliki input tetapi program-program ini jelas melakukannya.
Calvin Hobbies

@DrJPepper Titik peluru ketiga Anda membuatnya terdengar seperti urutan spasi putih dihitung sebagai pembatas tetapi Anda secara khusus mengatakan bahwa hanya ruang yang ada. Bisakah Anda mengklarifikasi?
Calvin Hobbies

2
Tantangan ini mendorong pembacaan kode sumber program sendiri, suatu praktik yang biasanya verboten dalam pembangunan quines.
feersum

Jawaban:


13

bash, 51 58

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

2
Ini bash, bukan shell: Ini tidak akan bekerja di bawah tanda hubung, ( 2: read: Illegal option -s)
F. Hauri

1
Dengan asumsi bash, dapat mengganti cat $0dan tildes dengan$(<$0)

@broslow thx untuk umpan balik; berlabel bash, sama panjangnya
Will

1
@ Tidak Akan masalah. Apakah yang IFS=\ sebenarnya dibutuhkan jika Anda menghilangkan shebang? IFS default adalah sesuatu seperti IFS=$'\n\t ', dan karena Anda tidak lagi memiliki baris baru, saya rasa Anda tidak perlu membatasinya hanya pada ruang.

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

21

HTML & JavaScript, 123

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

Ini berfungsi mirip dengan hacker typer, tetapi dengan kode sumbernya sendiri. Beri tahu saya jika saya salah mengerti aturan.

Dan inilah versi gaya (170 karakter):

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

Saya sudah membuat demo . Ini dimodifikasi karena JS Bin menambahkan banyak kode tambahan, tetapi ide umumnya sama.


2
Saya akan terkejut jika ini tidak ditampilkan dengan benar tanpa tag <html> dan <head>, dan tanpa penutup </body>. Anda akan terkejut betapa sangat memaafkan semua browser dalam hal ini.
Will

2
@Terima kasih. Alasan saya termasuk <head>adalah bahwa browser akan menambahkannya jika tidak ada di sana, sehingga akan selalu ditampilkan. Tapi aku lupa <html>.
grc

12

Perl + Term :: ReadKey, 56 byte

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

Terima kasih kepada ThisSuitIsBlackNot untuk inspirasi orisinalnya, dan kepada primo untuk menyarankan open 0dan <0>.

Perhatikan bahwa baris baru setelahnya forsebenarnya tidak perlu, kecuali bahwa saya perlu menyertakan satu baris baru tambahan di suatu tempat untuk membawa jumlah spasi putih hingga minimum yang ditentukan lima.

Juga perhatikan bahwa, seperti pengajuan ThisSuitIsBlackNot, program ini memerlukan modul Term :: ReadKey dari CPAN. Pada Debian / Ubuntu Linux, modul ini, jika belum ada, dapat dengan mudah diinstal dengan perintah sudo apt-get install libterm-readkey-perl.

Selain itu, untuk menyimpan beberapa karakter, program ini tidak mengembalikan mode input ke normal saat keluar, sehingga Anda mungkin tidak dapat melihat apa yang Anda ketikkan setelahnya. Menjalankan perintah shell stty saneatau resetharus memperbaikinya. Masalah ini dapat diperbaiki, dengan biaya 10 byte tambahan, dengan:

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

Bonus: Pure quine, 81 byte

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

Sekali lagi, baris baru setelah koma hanya diperlukan untuk memenuhi minimum lima spasi putih.

Berbeda dengan program 56-byte di atas, versi ini sebenarnya tidak perlu membaca kode sumbernya sendiri, karena ini didasarkan pada quine - khususnya, pada quine ini:

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

Yang menyenangkan tentang quine ini adalah ia dapat dengan mudah membawa "payload" sewenang-wenang di dalam q{ }blok, tanpa harus mengulanginya. Meskipun tidak bisa mengalahkan <0>dalam waktu singkat, itu cukup dekat.

Catatan: Program ini menggunakan fitur Perl 5.10+ say, dan karenanya perlu dipanggil dengan saklar baris perintah -M5.010(atau -E). Sesuai konsensus tentang meta, sakelar seperti itu yang digunakan untuk mengaktifkan fitur bahasa modern tidak dihitung sebagai karakter tambahan . Solusi terpendek yang dapat saya temukan tanpa say83 byte:

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

Kedua hal ini juga dapat dibuat lebih ramah terminal dengan (bergabung dengan dua baris terakhir dan) memasukkan:

;ReadMode
0

sebelum yang terakhir }.


Wow. Cuma wow. Sangat keren.
ThisSuitIsBlackNot

+1, tapi saya sarankan untuk memiliki kebiasaan mengetik stty sanedaripada reset(yang bisa, pada beberapa os, kadang-kadang melakukan sesuatu lebih dari sekadar menyetel ulang beberapa parameter terminal ^^)
Olivier Dulac

Solusi yang sangat bagus FWIW, open F,$0dan <F>bisa diganti dengan open 0dan <0>. Juga, saya berpendapat bahwa satu posting di meta tidak benar-benar merupakan konsensus. Opsi -M5.01tidak "membawa bahasa ke titik tertentu" , seperti yang penulis sarankan, ia mengaktifkan fitur. Tidak ada versi perl yang fitur-fiturnya diaktifkan secara default.
Primo

3
@primo: Silakan kirim jawaban Anda sendiri ke meta utas, jika Anda tidak setuju dengan yang ada. Fakta bahwa tidak ada yang melakukannya dalam tiga setengah tahun, sejauh ini, memang menunjukkan tingkat konsensus yang masuk akal, setidaknya di antara pengunjung tetap di sini yang secara aktif mengunjungi meta, tetapi konsensus selalu dapat berubah. (Omong-omong, seperti yang saya lihat, jika ruby golfscript.rb foo.gsdihitung sebagai perintah yang valid untuk menjalankan program yang ditulis dalam GolfScript, maka perl -M5.010 foo.plharus dihitung sebagai perintah yang valid untuk menjalankan program yang ditulis dalam "Perl 5.10". Tetapi argumen seperti itu benar-benar berasal dari meta, bukan di sini.)
Ilmari Karonen

5

Python 3 - 124 byte - 7 spasi


Kode:

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

Tidak Disatukan:

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

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}

Sayang sekali itu IO#rawbukan bagian dari perpustakaan standar.

Perbaikan

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

Yang ini menghilangkan panggilan untuk keluar # Kernel dan menggunakan variabel global untuk mempersingkat kode.


4

Befunge - 21

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

Saya cukup senang dengan ini, karena saya baru tahu tentang Befunge. Jika Anda tidak keberatan "mengetik" ke jendela sembulan, Anda dapat menjalankannya di sini atau di sini sampai saya menemukan juru bahasa online yang lebih baik.


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)

Ini quine. Dipersingkat dari 507 dengan menggunakan execdan memindahkan beberapa pernyataan.


2

C, 211 186 byte

Solusi saya di C menggunakan perpustakaan kutukan. Mungkin lebih lama dari solusi C lainnya, tetapi ini adalah quine. Meskipun tidak diharuskan oleh pertanyaan, itu masih cukup bagus. Ini juga bekerja dengan sangat baik:

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

Versi yang lebih mudah dibaca dengan beberapa komentar dan hal:

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

kompilasi dengan:

gcc -o h h.c -lncurses

2

C - 136 135 132 byte (hanya 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();} 

Catatan: ada ruang di akhir program, yang mungkin tidak akan muncul.

Saya tidak dapat menjamin program ini akan bekerja pada satu komputer selain saya sendiri karena ini sangat hacky. Segalanya akan jauh lebih sederhana ketika semua orang hanya memiliki mesin 32-bit. Maka saya tidak perlu khawatir tentang sizeof(int*)menjadi 8 (yang pasti; saya mencetaknya untuk memastikan) sedangkan sizeof(int)4.

Untungnya, nama executable disimpan dalam string pertama di argv. Namun, menempatkan pointer sebagai argumen ke fungsi berarti bahwa saya harus secara eksplisit menentukan jenis SEMUA argumen untuk fungsi - yang berarti saya harus mengetik intdua kali - buang-buang karakter. Untungnya saya menemukan solusi. Saya memiliki argumen kedua untuk main,, qhanya menjadi int lain. Kemudian menugaskan qke variabel tipe int**entah bagaimana berhasil mengambil semua byte yang diperlukan dari stack.

Saya tidak berhasil menemukan trik seperti itu untuk menafsirkan tipe kembali fopensebagai pointer tanpa mendeklarasikan fungsinya.

Sunting: Memperhatikan saya harus menggunakan ~fscanf(*v,"%s",b)sebagai ganti fscanf(*v,"%s",b)>0karena pengembaliannya -1 ketika EOF tercapai.


Segfault ini bagi saya jadi saya tidak bisa mengujinya, tetapi Anda harus dapat mendeklarasikan pointer kosong ( void **v;) alih-alih prototyping fopen().
Comintern

@Comintern perubahan ini tidak membantu saya untuk menyimpan hasil dengan benar fopen. Saya tidak melihat mengapa mengganti void untuk int harus membuat perbedaan, karena semua pointer memiliki ukuran yang sama.
feersum

Poin bagus. Masih lebih pendek dan lebih stabil untuk hanya mendeklarasikan pointer meskipun - ini benar-benar berjalan untuk saya: 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();}(saya harus mengganti getchar()untuk getch()meskipun).
Comintern

@Comintern kode Anda masih macet di sistem saya, tetapi pekerjaan yang bagus membuatnya berfungsi. Saya kira itu seperti yang saya katakan - setiap versi program akan berjalan pada 1 komputer.
feersum

Mengapa Anda tidak menggunakan prototipe K&R? Misalnya *fopen()bukan *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

Saya tidak melihat apa-apa dalam aturan tentang apa yang harus dilakukan setelah file dibaca hingga akhir, jadi ia hanya duduk menunggu input setelah mencetak potongan terakhir.


1

node.js dengan LiveScript:

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

versi asinkron:

#!/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 sangat berguna!


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

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

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

Memiliki dua versi, karena Chrome tidak menangani fungsi panah dan konsol tidak dibersihkan dengan metode yang sama

Firefox satu bekerja dengan pembakar, sepertinya konsol pengembang default tidak dapat dihapus dari skrip.


Apakah Anda melewatkan persyaratan bahwa pengguna harus menekan tombol acak untuk mendapatkan hasil cetak?
Pengoptimal

tentu !, akan menulis ulang ini.
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)
}   

Karena tidak ada getch()atau setara dalam bahasa Jawa dan bahasa Java-esque seperti Groovy ... pada dasarnya kode saya tidak menangani penekanan tombol. Itu saja: D


0

C, 248 karakter

Quine benar

Hanya berfungsi di unix, di windows itu akan diimplementasikan menggunakan _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 dan 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 tradisional, tetapi dimodifikasi.

JSFiddle di sini .


0

SmileBASIC, 79 75 byte

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

Sangat mudah untuk mendapatkan LINE tertentu dari sebuah program di SmileBASIC, jadi saya hanya menempatkan spasi sebelum setiap jeda baris. Saya pikir saya sangat pintar, menempatkan spasi sebelum setiap jeda baris, tetapi tampaknya kami diizinkan untuk menggunakan jeda baris alih-alih spasi ...

Penjelasan:

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 

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.