49 번째 수정본 소스 보기 : CodeGolf/AsciiArt
마지막으로 [b]
-- Loading page list... --
내용출력
로그인[l]
Diary
[f]
최근변경내역
[r]
페이지목록[i]
횡설수설[2]
게시판[3]
링크
수정할 수 없습니다: CodeGolf/AsciiArt 는 읽기 전용 페이지입니다.
[http://codegolf.com/bob-ross-the-joy-of-ascii-art Code Golf | Bob Ross' The Joy of ASCII Art] [[Perl]]의 경우 51글자가 최선인 듯. [[Diary/CodeGolf-ASCIIart홀인원]] == 홀인원까지의 과정 == [http://kldp.org/node/82236 재미있는 코드 골프를 해봅시다~!! | KLDP] - 관련 글타래 위 글타래에서 코드가 줄어드는 과정을 구경하면 나름대로 재미있다. === 2차원 배열 === 처음에 keedi 김도형님이 Perl 코드 운을 뗌[http://kldp.org/node/82236#comment-390800]. 입력을 가지고 1글자짜리 스트링의 2차원 배열을 만든 후, 그 배열을 출력. {{{#!vim perl # 87바이트짜리 @a=<>;map{split/ /;$s[$_[1]][$_[0]]=chr$_[2]}@a;map{map{print$_?$_:' '}@$_;print"\n"}@s }}} 풀어서 쓰면 {{{#!vim perl @a=<>; # 표준입력을 배열에 저장하고 map { # 입력의 각 행에 대하여 split/ /; # 공백으로 구분하여 3개의 숫자로 된 배열을 만들어 @_에 담고 $s[$_[1]][$_[0]]=chr$_[2] # 스트링의 2차원 배열에 해당 위치에 해당 문자를 담는다 }@a; map { # 이제 출력 map{print$_?$_:' '}@$_; # 문자가 없는 좌표는 스페이스 출력 print"\n" }@s }}} 굳이 @a라는 임시 배열을 쓸 필요가 없고, split은 인자를 주지 않으면 알아서 스페이스를 구분자로 사용하므로[http://kldp.org/node/82236#comment-390887] {{{#!vim perl #78바이트 map{split;$s[$_[1]][$_[0]]=chr$_[2]}<>;map{map{print$_?$_:' '}@$_;print"\n"}@s }}} 표준 입력을 split으로 나눌 필요 없이 [[Perl/정규표현식]]을 사용하여 x좌표, y좌표, 아스키코드값을 분리해낸다. jg님[http://kldp.org/node/82236#comment-390970] {{{#!vim perl #72바이트 map{/ (.*) /;$s[$1][$`]=chr$'}<>;map{map{print$_?$_:' '}@$_;print"\n"}@s }}} 두 번 등장한 print를 한 번으로 줄이고, 3항 연산자 대신에 ||를 사용하여[http://kldp.org/node/82236#comment-390973] {{{#!vim perl #65바이트 map{/ (.*) /;$s[$1][$`]=$'}<>;print map{map{chr($_||32)}@$_,10}@s }}} 생각해보니 굳이 정규식 저 자리에 괄호를 쓸 필요가 없다[http://kldp.org/node/82236#comment-390987] {{{#!vim perl #63바이트 map{/ .* /;$s[$&][$`]=$'}<>;print map{map{chr($_||32)}@$_,10}@s }}} "어느 좌표에 저장된 문자가 있으면 그 문자를, 없으면 스페이스를"이라는 문제를 해결하기 위해서 계속 "||"연산자를 사용했는데, printf를 써서 "%1s"로 인자를 주어서 출력하게 하는 버전들[http://kldp.org/node/82236#comment-391216] [http://kldp.org/node/82236#comment-391315] [http://kldp.org/node/82236#comment-391368]. 그러나, 결과적으로 이건 홀인원을 향한 길에 도움이 되지 못했음. 오히려 벙커에 빠진 셈이랄까. {{{#!vim perl #62바이트 map{/ .* /;$s[$&][$`]=chr$'}<>;map{printf"%1s"x@$_."\n",@$_}@s #59바이트 $s[$&][$`]=chr$'*/ .* /for<>;printf"%1s"x@$_."\n",@$_ for@s }}} === 스트링의 1차원 배열 === 한 글자 스트링들의 2차원 배열 대신에 각 라인을 나타내는 스트링들의 1차원 배열로 만든 jg님의 버전 등장[http://kldp.org/node/82236#comment-391365]. 이하의 진행에서는 계속 jg님이 힌트를 듣고서야 [[주인장]]도 진행할 수 있었다. ㅠ,.ㅡ 입력되는 좌표의 순서가 중구난방이기 때문에, 어떤 행을 구성한 후 다시 그 행 어느 열의 좌표가 들어오면 기존 행에 합쳐주어야 하는데, 스트링에 대하여 bitwise OR 연산을 사용. {{{#!vim perl #62바이트 / .* /,$s[$&]|="\0"x$`.chr$' for<>;$\="\n";y/\0/ /,print for@s }}} 이후 글타래도 조용해지고 주인장도 바쁘고 해서 두 주일 동안 진전이 없다가... 다시 생각나서 KLDP에 갔더니, === [[Perl]]의 스위치 - 이건 사기야 사기 === jg님의 글[http://kldp.org/node/82236#comment-392112] 이거 전에 Beginning Perl 읽으면서 [[Perl/디버깅]]에도 적어뒀던 것들인데... 명령행 인자를 사용해서 켤 수 있는 스위치들을 일일이 외우기도 싫고 해서 그냥 적어두기만 하고 잊고 있었는데 여기에 비밀이 있었다. 아래와 같이 실행하면 {{{ $ perl -n -e '코드' }}} Perl은 아래와 같이 가정하여 수행한다. {{{#!vim perl while (<>) { 코드 } }}} 명령행 인자가 아니라 shebang 라인에 적어 줄수도 있다. {{{#!vim perl #!perl -n 코드 }}} 근데 우리가 작성하는 프로그램은, 일단 표준 입력을 전부 다 읽어서 스트링을 구성하는 단계와, 완성된 스트링을 출력하는 단계로 나누어지기 때문에, 저렇게 코드 전체가 루프 안으로 들어가버리면 곤란하다...라고 생각을 했는데... 다음과 같은 사기스러운 코드가 가능하더라. {{{#!vim perl #!perl -n 코드1 } { 코드2 }}} 이러면 이게 아래처럼 해석된다! -_-;;; {{{#!vim perl while (<>) { # Perl이 루프의 시작을 붙여주고, 코드1 } # 여기서 첫번째 단계의 루프가 끝나고 -_-; { # 새로운 블럭이 시작되면서 코드2 } # Perl이 닫는 중괄호를 붙여준다 -_-;;;; }}} -n 대신에 -p를 쓰면 Perl이 알아서 print까지 한다 {{{#!vim perl #!perl -p 코드 # 이것은 아래와 같이 해석 LINE: while (<>) { 코드 # your program goes here } continue { print or die "-p destination: $!\n"; } }}} 그리고 -l 옵션을 주면 print를 할 때마다 뒤에 $\ (the output record separator)의 값을 붙이는데 이게 기본값이 "\n"이다. 따라서 아래와 같은 게 가능해지고, 여기까지가 주인장이 알고 있는 것만으로 할 수 있는 최선의 코드였다. {{{#!vim perl #55바이트 #!perl -lp / .* /,$s[$&]|="\0"x$`.chr$'}for(@s){y/\0/ / }}} 다시 jg님의 힌트[http://kldp.org/node/82236#comment-394140]를 얻어 vec()이라는 함수의 존재를 알게 되어서, 스트링을 만들 때 bitwise OR 대신에 vec()을 써서 짠 게 아래와 같다. {{{#!vim perl #52바이트 #!perl -lp / ../;vec($s[$&],$`,8)=$'}for(@s){y/\0/ / }}} === 마지막 1바이트 === 이제 1바이트가 남았는데... jg님의 말을 빌자면, 위 코드에서, '''두 글자로 표현된 것을 한 글자로 줄일 수 있다''' 이것도 사기라면 사기인데, 어쨌거나 해보니까 되더라. {{{#!vim perl #!perl -lp 비밀 :-P }}} 힌트는, "메모장으로는 안 되고 vi나 emacs로는 됨"
[[주인장]]도 그 비밀이 뭐였는지 생각이 안 났다가.. 다시 생각이 났다. "\0" 이라고 표기된 두 바이트를, 널 캐릭터(0x00)로 바꿔쓰면 된다... -_-; ViEditor에서 널 캐릭터 입력은 Ctrl+V,Ctrl+@
이것과 별도로, vi에서 저장하니 시키지도 않았는데 꼭 끝에 "\n"을 붙여버려서 1바이트 늘어나 버린다. (윈도우 gvim에서는 "\r\n"을 붙여서 2바이트) "set noeol binary" 옵션을 주어서 저장하면 끝에 "\n"을 붙이지 않긴 하는데, 리눅스에서 그 상태로 실행하면 에러가 나더라. {{{#!vim $ perl ascii.pl < input Unrecognized character \x11 at ascii.pl line 2. }}} 그렇지만 코드골프에 업로드하면 통과한다.
아니, 코드골프 사이트 가 봤더만 50바이트짜리 1등이 새로 올라와 있다 -ㅅ-;
1
1
1
1
1
1
1
1
----
---- [[컴퓨터분류]]
CodeGolf/AsciiArt
페이지로 돌아가기 |
다른 수정본 보기