Створіть програму "хакерський друкар", яка надає власний вихідний код


25

Якщо ви не знайомі з машиною хакера, дивіться hackertyper.net . Коротше кажучи, це програма, яка видає один відрізок бази коду за один натискання клавіші для комедійного ефекту. Але НЕ, версія hackertyper.net реалізована занадто просто. Він просто виводить одночасно три символи з довільного фрагмента коду. Для цього завдання програма повинна вивести свій власний вихідний код і надрукувати один відрізок коду з обмеженим пробілом за натискання клавіші.

Деталі

  • Не можна важко кодувати ім'я файлу програми; вона повинна динамічно визначати свою назву. Якщо програма компілюється у виконуваний файл, вона може додати стандартне розширення файлу до імені виконуваного файлу (за винятком .exe, якщо використовується Windows) і припустити, що вихідний файл знаходиться в каталозі виконуваного файлу. Наприклад, якщо виконуваний файл C названий "хакер", він повинен витягнути його вихідний код з файлу з назвою "hacker.c" в тому ж самому каталозі. Якщо компільована програма має розширення, її слід скинути перед тим, як визначити назву її вихідного коду ("typer.exe" -> "typer.cs").
  • Програми повинні містити щонайменше 5 пробілів із принаймні одним символом між кожним пробілом. Це означає, що найменший можливий розмір для цього завдання - 9 байт. Пробіли не повинні мати вирішальне значення для функціонування програми.
  • Будь-яке форматування (відступ, нові рядки тощо) повинно підтримуватися у висновку. Це форматування може бути надруковано разом з кодом, який його виконує, або після нього, що важливо, щоб форматування підтримувалося.
  • Уникайте використання коментарів, щоб задовольнити потребу в 5 місцях, якщо немає іншого способу реалізації пробілів на вашій мові.

РЕДАКТУВАННЯ : Нові рядки можна використовувати замість пробілів або додатково до них як проміжки.


1
Я трохи розгублений. Програма повинна бути королевою, чи ні?
Орбі

8
Те, що ви описали, робить це звучанням так, ніби прийнятним для читання коду є вихідний файл, який би не був королевою. Я думаю, що було б краще змагання, якби програма мала бути справжньою королевою.
Орбі

1
@Orby Я б сказав, що програма не є королевою в традиційному розумінні, незалежно від того, чи дозволено читання джерела чи ні. Куїни не мають вхідних даних, але ці програми явно мають.
Захоплення Кальвіна

@DrJPepper Ваша третя точка кулі робить це звуком, як будь-яка послідовність пробілів вважається роздільником, але ви конкретно говорите, що це лише пробіл. Ви можете уточнити?
Захоплення Кальвіна

2
Цей виклик заохочує читати власний вихідний код програми, як правило, багатослівний в побудові лайків.
feersum

Відповіді:


13

баш, 51 58

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

2
Це баш, а не оболонка: це не буде працювати під тире, ( 2: read: Illegal option -s)
Ф. Хаурі

1
Припускаючи bash, може замінити cat $0і $(<$0)

@broslow thx для зворотного зв'язку; мічений баш, однакова довжина
буде

1
@Без проблем. Чи IFS=\ потрібна насправді, якщо опустити шебанг? IFS за замовчуванням щось подібне IFS=$'\n\t ', і оскільки у вас більше немає нового рядка, я не думаю, що вам потрібно обмежувати його просто простором.

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>

Це працює аналогічно хакерському машинопису, але з власним вихідним кодом. Повідомте мене, чи я неправильно зрозумів правила.

А ось стилізована версія (170 символів):

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

Я зробив демонстрацію . Він модифікований, оскільки JS Bin додає багато додаткового коду, але загальна ідея та ж.


2
Я був би здивований, якби це не відображалось правильно без тегів <html> і <head> та без закриття </body>. Ви здивуєтеся, як дуже прощають у цьому плані всі браузери.
Буде чи

2
@Буду спасибі Я включив причину <head>того, що браузер додасть його, якщо його немає, тож він завжди буде відображатися. Я забув, <html>хоча.
grc

12

Perl + Термін :: ReadKey, 56 байт

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

Завдяки ThisSuitIsBlackNot за оригінальне натхнення, а також примо за пропозицію open 0та <0>.

Зауважте, що новий рядок після forнасправді непотрібний, за винятком того, що мені потрібно десь включити додатковий новий рядок, щоб довести кількість пробілів до заданого мінімуму п'яти.

Також зауважте, що, як і подання ThisSuitIsBlackNot, для цієї програми потрібен модуль Term :: ReadKey від CPAN. У Debian / Ubuntu Linux цей модуль, якщо його ще немає, можна легко встановити за допомогою команди sudo apt-get install libterm-readkey-perl.

Крім того, щоб зберегти кілька символів, ця програма не повертає режим введення до нормального при виході, тому ви, можливо, не зможете побачити, що ви вводите після цього. Виконання команди оболонки stty saneабо resetмає виправити це. Цю проблему можна вирішити за рахунок 10 додаткових байтів:

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

Бонус: Чиста quine, 81 байт

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

Знову ж таки, новий рядок після коми потрібен лише для досягнення мінімуму з п'яти пробілів.

На відміну від 56-байтової програми, наведеної вище, цій версії насправді не потрібно читати власний вихідний код, оскільки вона заснована на quine - конкретно, на цій quine:

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

Приємна річ у цій квинці - це те, що вона може легко переносити довільну "корисну навантаження" всередині q{ }блоку, не потребуючи повторення. Незважаючи на те, що він не може зовсім бити <0>за короткий час, він все-таки стає дуже близьким.

Примітка. Ця програма використовує функцію Perl 5.10+ sayі тому її потрібно викликати -M5.010(або -E) перемикачем командного рядка. За встановленим консенсусом щодо мета, такі комутатори, що використовуються для включення сучасних мовних функцій , не зараховуються як зайві символи . Найкоротше рішення, яке я можу знайти, say- це 83 байти:

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

І те, і інше можна зробити більш сприятливим для терміналів, приєднавшись до останніх двох рядків та), вставивши:

;ReadMode
0

перед останнім }.


Ого. Просто вау. Дуже круто.
ThisSuitIsBlackNot

+1, але я рекомендую мати звичку вводити stty saneзамість reset(що, на деяких ОС, іноді робити щось більше, ніж просто скидати деякі термінальні параметри ^^)
Олів'є Дулак

Дуже приємне рішення. FWIW, open F,$0і <F>може бути замінений open 0і <0>. Крім того, я заперечу, що одна посада в мета насправді не є консенсусом. Опція -M5.01не "доводить мову до конкретної точки" , як пропонує автор, вона включає функції. Немає версії perl, для якої ці функції включені за замовчуванням.
прима

3
@primo: Будь ласка, опублікуйте власну відповідь на метапотоку, якщо ви не згодні з існуючою. Той факт, що ніхто не робив цього за три з половиною роки, поки що не говорить про розумну ступінь консенсусу, принаймні серед постійних представників, які активно відвідують мета, але консенсус завжди може змінитися. (У будь-якому разі, як я бачу це, якщо він ruby golfscript.rb foo.gsвважається дійсною командою для запуску програми, написаної на GolfScript, то perl -M5.010 foo.plслід вважати дійсною командою для запуску програми, написаної в "Perl 5.10". Але такі аргументи дійсно належать мета, а не тут.)
Ілмарі Каронен

5

Python 3 - 124 байти - 7 пробілів


Код:

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

Безголівки:

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

Стильова версія:

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

Рубі, 85 , 71

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

Шкода, що IO#rawне є частиною стандартної бібліотеки.

Поліпшення

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

Цей виключає виклик до виходу з ядра # та використовує глобальні змінні для скорочення коду.


4

Befunge - 21

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

Я досить задоволений цим, як тільки що дізнався про Befunge. Якщо ви не заперечуєте проти "введення" у спливаюче вікно, можете запустити його тут або тут, поки я не знайду кращого онлайн-перекладача.



2

Пітон 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)

Це - лайка. Скорочено з 507, використовуючи execта переміщуючи деякі заяви.


2

C, 211 186 байт

Моє рішення на C, використовуючи бібліотеку прокльонів. Це може бути довше, ніж інший розчин С, але це квінт. Хоча питання цього не вимагає, все-таки досить приємно. Це також працює досить непогано:

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

Більш прочитана версія з деякими коментарями та деталями:

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

компілювати з:

gcc -o h h.c -lncurses

2

C - 136 135 132 байт (лише для 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();} 

Примітка. В кінці програми є пробіл, який, ймовірно, не відображатиметься.

Я не можу гарантувати, що ця програма буде працювати на одному комп'ютері, крім мого власного, оскільки це надзвичайно хакі. Все було б набагато простіше, коли всі мали лише 32-бітні машини. Тоді мені не потрібно буде турбуватися про sizeof(int*)те, що це 8 (що це, безумовно, я роздрукував, щоб переконатися), покиsizeof(int) це 4.

На щастя, ім'я виконуваного файлу зберігається в першому рядку в argv. Однак, якщо вказати покажчик як аргумент на функцію, це означає, що я повинен чітко вказати тип ВСІХ аргументів функції - це означає, що я повинен був би набрати intдвічі - величезна марнотрата символів. На щастя, я знайшов вирішення. У мене був другий аргумент для головного q, бути лише іншим int. Потім присвоєння qзмінної типу int**якось вдалося схопити всі необхідні байти зі стека.

Мені не вдалося знайти будь-які подібні хитрощі, щоб інтерпретувати тип повернення fopenяк вказівник, не оголошуючи функції.

Редагувати: Помічено, що я повинен використовувати ~fscanf(*v,"%s",b)замість, fscanf(*v,"%s",b)>0оскільки повернення дорівнює -1, коли буде досягнуто EOF.


Це segfaults для мене, тому я не можу його перевірити, але ви повинні мати можливість оголосити недійсний покажчик ( void **v;) замість прототипування fopen().
Комінтерн

@Comintern ця зміна не допомогла мені правильно зберігати результат fopen. Я не бачу, чому заміщення недійсності на int повинно змінити значення, оскільки всі покажчики все одно мають однаковий розмір.
feersum

Влучне зауваження. Ще коротше і більш стабільним , просто оголосити покажчик , хоча - це на самому справі працює для мене 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();}(я повинен був замінити getchar()на getch()хоча).
Комінтерн

@Comintern ваш код все ще виходить з ладу в моїй системі, але приємна робота примушує його працювати. Я здогадуюсь, як я вже сказав - кожна версія програми працюватиме на 1 комп’ютері.
феерсум

Чому ви не використовуєте прототипи K&R? Наприклад, *fopen()замість*fopen(a,b) ?
FUZxxl

1

Perl - 87 байт

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

Я нічого не бачив у правилах, що робити після того, як файл буде прочитаний до кінця, тому він просто сидить в очікуванні введення після друку останнього фрагменту.


1

node.js з LiveScript:

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

асинхронна версія:

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

1

Кобра - 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 так корисно!


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

Обидва 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}}})()

Безлічі (хром):

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

Має дві версії, оскільки Chrome не обробляє функцію стрілки, а консоль не очищається тим самим методом

Firefox працює з firebug, здається, що консоль розробника за замовчуванням неможливо очистити від сценарію.


Ви пропустили вимогу, що користувач повинен натискати випадкові клавіші, щоб отримати результат друку?
Оптимізатор

точно!, перепишу це.
Hacketo

0

Гроовий - 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)
}   

Оскільки getch()в Java та на мовах, що перебувають на Java-Java, таких як Groovy, немає або еквівалентно… в основному мій код не обробляє натискання клавіш. Ось і все: D


0

C, 248 символів

Справжня квинка

Працює лише в unix, у Windows він буде реалізований за допомогою _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 і Javascript, 232 байти

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

Традиційна JavaScript JavaScript, але змінена.

JSFiddle тут .


0

SmileBASIC, 79 75 байт

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

Отримати певну лінію програми в SmileBASIC дуже просто, тому я просто розміщую пробіли перед кожним розривом рядка. Я думав, що я такий розумний, розміщуючи пробіли перед кожним розривом рядка, але, мабуть, нам дозволяється використовувати розриви рядків замість пробілів ...

Пояснення:

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 

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.