Создайте программу «хакерского типа», которая отображает собственный исходный код.


25

Если вы незнакомы с хакером Typer , см. Hackertyper.net . Короче говоря, это программа, которая выводит один кусок кодовой базы за нажатие клавиши для комедийного эффекта. НО, версия hackertyper.net слишком проста для реализации. Он просто выводит три символа за раз из произвольного фрагмента кода. Для этой задачи программа должна вывести свой собственный исходный код и распечатать один фрагмент кода с пробелом на каждое нажатие клавиши.

Детали

  • Нельзя жестко закодировать имя файла для программы; оно должно определять свое имя динамически. Если программа компилируется в исполняемый файл, она может добавить стандартное расширение файла к имени исполняемого файла (исключая EXE-файл, если используется Windows) и предположить, что исходный файл находится в каталоге исполняемого файла. Например, если исполняемый файл C называется «hacker», он должен извлечь свой исходный код из файла с именем «hacker.c» в том же каталоге. Если скомпилированная программа имеет расширение, ее следует удалить перед определением имени ее исходного кода («typer.exe» -> «typer.cs»).
  • Программы должны содержать не менее 5 пробелов, по крайней мере один символ между каждым пробелом. Это означает, что наименьший возможный размер для этой задачи составляет 9 байтов. Пробелы не должны быть решающими для функционирования программы.
  • Любое форматирование (отступ, новые строки и т. Д.) Должно быть сохранено в выходных данных. Это форматирование может быть либо напечатано с кодом, который его обрабатывает, либо следует за ним, важно то, чтобы форматирование сохранялось.
  • Старайтесь не использовать комментарии, чтобы удовлетворить требование 5 пробелов, если нет другого способа реализовать пробелы на выбранном вами языке.

РЕДАКТИРОВАТЬ : новые строки могут использоваться вместо или в дополнение к пробелам в качестве разделителей чанков.


1
Я немного запутался. Должна ли программа быть лозунгом или нет?
Орби

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

1
@ Я бы сказал, что в традиционном смысле программа не является лозунгом, независимо от того, разрешено или нет чтение исходного текста. Квины не имеют ввода, но эти программы явно делают.
Увлечения Келвина

@DrJPepper Ваша третья точка маркера звучит так, как будто любая последовательность пробелов считается разделителем, но вы специально говорите, что это только пробел. Вы можете уточнить?
Увлечения Кэлвина

2
Эта задача поощряет чтение собственного исходного кода программы, что, как правило, многословно при построении квин.
feersum

Ответы:


13

Баш, 51 58

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

2
Это bash, а не shell: это не будет работать под чертой, ( 2: read: Illegal option -s)
Ф. Хаури

1
Предполагая bash, можно заменить cat $0и тильды на$(<$0)

@broslow thx для обратной связи; с надписью bash, той же длины
будет

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 + Term :: ReadKey, 56 байт

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

Спасибо ThisSuitIsBlackNot за оригинальное вдохновение и primo за предложение 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

Бонус: Pine Quine, 81 байт

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

Опять же, перевод строки после запятой необходим только для соответствия минимуму пяти пробелов.

В отличие от 56-байтовой программы, описанной выше, этой версии на самом деле не нужно читать собственный исходный код, поскольку она основана на квине, в частности, на этой квине:

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

Приятной особенностью этого квайна является то, что он может легко переносить произвольную «полезную нагрузку» внутри q{ }блока, не повторяя ее. В то время как это не может совсем разбить <0>в короткой, это действительно довольно близко.

Примечание. Эта программа использует sayфункцию Perl 5.10+ и, следовательно, должна вызываться с помощью -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()

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

Стилизованная версия:

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

Это исключает вызов Kernel # exit и использует глобальные переменные для сокращения кода.


4

Befunge - 21

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

Я довольно доволен этим, как только что узнал о Befunge. Если вы не против набрать текст во всплывающем окне, вы можете запустить его здесь или здесь, пока я не найду лучшего онлайн-переводчика.


2

Powershell, 89

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

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)

Это Quine. Сокращено с 507 с использованием execи перемещением некоторых утверждений.


2

C 211 186 байт

Мое решение в C с использованием библиотеки curses. Это может быть длиннее, чем другое решение C, но это Quine. Хотя это и не требуется по этому вопросу, это все же довольно приятно. Это также работает довольно хорошо:

#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дважды - огромная трата символов. К счастью, я нашел обходной путь. У меня был второй аргумент к main q, будь просто еще одним int. Затем присвоение qпеременной типа int**каким-то образом удалось извлечь все необходимые байты из стека.

Мне не удалось найти какие-либо подобные приемы, чтобы интерпретировать возвращаемый тип fopenкак указатель без объявления функции.

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


Это segfaults для меня, поэтому я не могу проверить его, но вы должны иметь возможность объявить указатель void ( void **v;) вместо прототипирования fopen().
Коминтерн

@Comintern это изменение не помогло мне правильно сохранить результат fopen. Я не понимаю, почему замена void на 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 компьютере.
feersum

Почему вы не используете прототипы 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}}})()

Ungolfed (хром):

( 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 one работает с firebug, кажется, что консоль разработчика по умолчанию не может быть очищена из скрипта.


Вы пропустили требование, чтобы пользователь нажимал случайные клавиши, чтобы распечатать результат?
Оптимизатор

конечно, перепишу это.
Хакето

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

Поскольку getch()в Java и Java-esque-языках, таких как 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 Quine, но модифицированный.

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.