자체 소스 코드를 렌더링하는 "해커 입력기"프로그램을 만듭니다.


25

해커 입력기에 익숙하지 않은 경우 hackertyper.net을 참조하십시오 . 간단히 말해, 코믹 효과를 위해 키 스트로크 당 하나의 코드 기반 청크를 출력하는 프로그램입니다. 그러나 hackertyper.net 버전은 구현하기가 너무 쉽습니다. 임의 의 코드 조각 에서 한 번에 세 문자 만 출력 합니다. 이 문제를 해결하려면 프로그램에서 자체 소스 코드를 출력하고 구분 된 공백을 인쇄해야합니다 키 스트로크마다 코드 덩어리를 .

세부

  • 프로그램의 파일 이름을 하드 코딩 할 수 없습니다. 이름을 동적으로 결정해야합니다. 프로그램이 실행 파일로 컴파일되면 표준 파일 확장자를 실행 파일 이름에 추가하고 (Windows를 사용하는 경우 .exe 제외) 소스 파일이 실행 파일의 디렉토리에 있다고 가정합니다. 예를 들어 C 실행 파일의 이름이 "hacker"인 경우 동일한 디렉토리의 "hacker.c"파일에서 소스 코드를 가져와야합니다. 컴파일 된 프로그램에 확장명이 있으면 소스 코드의 이름 ( "typer.exe"-> "typer.cs")을 결정하기 전에 삭제해야합니다.
  • 프로그램은 각 공백 사이에 하나 이상의 문자를 포함하여 최소 5 개의 공백을 포함해야합니다. 이것은이 챌린지에 가능한 가장 작은 크기가 9 바이트임을 의미합니다. 공간은 프로그램 기능에 중요하지 않아도됩니다.
  • 모든 형식 (들여 쓰기, 줄 바꿈 등)은 출력에서 ​​유지되어야합니다. 이 형식은 코드를 진행하거나 따라가는 형식으로 인쇄 될 수 있습니다. 중요한 것은 서식이 유지되어야한다는 것입니다.
  • 선택한 언어로 공백을 구현할 다른 방법이없는 경우 주석을 사용하여 5 개의 공간 요구 사항을 충족하지 마십시오.

편집 : 줄 대신 청크 구분 기호로 줄 바꿈을 사용할 수 있습니다.


1
조금 혼란 스러워요. 프로그램이 엉망일까요?
Orby

8
당신이 묘사 한 방식은 원본 소스 파일에서 코드를 읽는 것이 용납되는 것처럼 들립니다. 프로그램이 실제 퀴네 여야한다면 더 좋은 대회가 될 것이라고 생각합니다.
Orby

1
@Orby 소스를 읽는 것이 허용되는지 여부에 관계없이 프로그램이 전통적인 의미에서 엉망이 아니라고 말하고 싶습니다. Quines 에는 입력이 없지만 이러한 프로그램은 명확합니다.
Calvin 's Hobbies

@DrJPepper 세 번째 글 머리 기호는 공백 문자가 구분 기호로 간주되는 것처럼 들리지만 구체적으로 공백만이라고 말합니다. 당신은 명확히 할 수 있습니까?
Calvin 's Hobbies

2
이 과제는 프로그램 자체 소스 코드를 읽는 것을 권장합니다.
feersum

답변:


13

강타, 51 58

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

2
쉘이 아닌 배쉬 : 이것은 대시에서 작동하지 않습니다. ( 2: read: Illegal option -s)
F. Hauri

1
배쉬를 가정하면 다음 cat $0과 같이 바꿀 수 있습니다$(<$0)

피드백을위한 @broslow thx; 표시 bash는, 같은 길이

1
@ 문제 없습니다. IFS=\ shebang을 생략 하면 실제로 필요한 가요 ? 기본 IFS는와 같 IFS=$'\n\t '으며 더 이상 줄 바꿈이 없으므로 공백으로 제한 할 필요가 없다고 생각합니다.

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

21

HTML 및 자바 스크립트, 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 원래의 영감과에 프리모 제안에 open 0<0>.

공백 문자 수를 지정된 최소 5까지 가져 오려면 어딘가에for 한 줄을 추가해야한다는 점을 제외하고는 이후 줄 바꿈 이 실제로 필요하지 않습니다.

또한 ThisSuitIsBlackNot의 제출과 같이이 프로그램에는 CPAN 의 Term :: ReadKey 모듈 이 필요합니다 . 데비안 / 우분투 리눅스에서이 모듈은 아직 없으면 다음 명령으로 쉽게 설치할 수 있습니다sudo apt-get install libterm-readkey-perl .

또한 일부 문자를 저장하기 위해이 프로그램은 종료시 입력 모드를 정상으로 복원하지 않으므로 나중에 입력하는 내용을 볼 수 없습니다. 쉘 명령을 실행 stty sane하거나 reset수정해야합니다. 이 문제는 10 바이트의 추가 비용으로 다음과 같이 해결할 수 있습니다.

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

보너스 : 퓨어 퀴니, 81 바이트

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

다시, 쉼표 뒤의 개행 문자는 최소 5 개의 공백을 충족시키기 위해 필요합니다.

위의 56 바이트 프로그램과는 달리이 버전은 실제로 소스 코드를 읽을 필요가 없습니다. 왜냐하면 소스는 quine을 기반으로하기 때문입니다.

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

이 quine의 좋은 점은 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(일부 OS에서는 때로는 일부 터미널 매개 변수를 재설정하는 것보다 더 많은 일을 할 수 있습니다 ^^)
Olivier Dulac

아주 좋은 해결책. FWIW는, open F,$0<F>로 대체 될 수 open 0<0>. 또한 메타의 한 게시물이 실제로 합의를 구성하지는 않는다고 주장합니다. 이 옵션 -M5.01은 저자가 제안한대로 기능을 활성화하는 "언어를 특정 지점으로 가져 오지" 않습니다 . 이러한 기능이 기본적으로 사용되는 perl 버전은 없습니다.
primo

3
@primo : 기존 스레드와 동의하지 않는 경우 메타 스레드에 대한 답변을 게시하십시오. 지금까지 3 년 반 동안 아무도 그렇게하지 않았다는 사실은 적어도 메타를 적극적으로 방문하는 규칙들 사이에서 합리적인 수준의 합의를 제시하지만 합의는 항상 바뀔 수 있습니다. (어쨌든 내가 본 방식 ruby golfscript.rb foo.gs은 GolfScript로 작성된 프로그램을 실행하는 유효한 명령으로 perl -M5.010 foo.pl간주되면 "Perl 5.10"으로 작성된 프로그램을 실행하는 올바른 명령으로 계산해야합니다. 그러나 이러한 인수는 실제로 메타에 속하지 않습니다. 에 여기).
Ilmari 카로 넨에게

5

파이썬 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)}

이것은 커널 #exit에 대한 호출을 제거하고 전역 변수를 사용하여 코드를 줄입니다.


4

베 펀지-21

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

방금 Befunge에 대해 알게 되었기 때문에 이것에 상당히 만족합니다. 팝업 창에 "입력"하는 것이 마음에 들지 않으면 더 나은 온라인 통역사를 찾을 때까지 여기 또는 여기에서 실행할 수 있습니다 .


2

파워 쉘, 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)

그것은 엉망입니다. exec일부 문장 을 사용 하고 이동 하여 507에서 단축되었습니다 .


2

C, 211 186 바이트

curses 라이브러리를 사용하는 C의 솔루션. 다른 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- 136135132 바이트 (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. 그런 다음 q유형의 변수에 할당int** 어떻게 든 하면 스택에서 필요한 모든 바이트를 가져 왔습니다.

fopen함수를 선언하지 않고 포인터 의 반환 유형을 해석하는 그러한 트릭을 찾지 못했습니다 .

편집 : EOF에 도달하면 반환 값이 -1이므로 ~fscanf(*v,"%s",b)대신 사용해야 합니다 fscanf(*v,"%s",b)>0.


이 segfaults 때문에 테스트 할 수는 없지만 void **v;프로토 타이핑 대신 void 포인터 ( ) 를 선언 할 수 있어야합니다 fopen().
Comintern

@Comintern이 변경은의 결과를 올바르게 저장하는 데 도움이되지 않았습니다 fopen. 모든 포인터의 크기가 어쨌든 int 대신 void를 대체하면 왜 차이가 나는지 알 수 없습니다.
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

@Comintern 코드가 여전히 내 시스템에서 충돌하지만 작동하는 것은 좋은 일입니다. 프로그램의 각 버전은 1 대의 컴퓨터에서 실행됩니다.
feersum

K & R 프로토 타입을 왜 사용하지 않습니까? 예 *fopen()대신 *fopen(a,b)?
FUZxxl

1

펄-87 바이트

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

파일을 끝까지 읽은 후에는 무엇을해야하는지에 대한 규칙에서 아무것도 보지 못했기 때문에 마지막 청크를 인쇄 한 후 입력을 기다리는 것입니다.


1

LiveScript를 사용한 node.js :

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

자바 스크립트 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}}})()

크롬 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와 작동하며 기본 개발자 콘솔을 스크립트에서 지울 수없는 것 같습니다.


사용자가 임의의 키를 눌러 출력을 인쇄해야한다는 요구 사항을 놓쳤습니까?
Optimizer

확실히!, 이것을 다시 쓰겠습니다.
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()Groovy와 같은 Java 및 Java 언어 가 없거나 그에 상응하는 언어 가 있기 때문에 기본적으로 내 코드는 키 누르기를 처리하지 않습니다. 그게 다야 : D


0

C, 248 자

진정한 퀴네

유닉스에서만 작동하며 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 및 자바 스크립트, 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>

전통적인 자바 스크립트는 엉망이지만 수정되었습니다.

여기 JSFiddle .


0

SmileBASIC, 79 75 바이트

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

SmileBASIC에서 프로그램의 특정 LINE을 얻는 것은 매우 쉬우므로 각 줄 바꿈 앞에 공백을 넣습니다. 각 줄 바꿈 전에 공백을 넣는 것이 영리하다고 생각했지만 공백 대신 줄 바꿈을 사용할 수 있습니다 ...

설명:

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 

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.