ASCII 애니메이션 눈 장면


22

ASCII 아트를 떨어지는 눈에서 시작되는 애니메이션 눈 장면으로 변환하는 가장 짧은 프로그램을 작성하십시오 ( 골프되지 않은 JavaScript 예제는 2011-12-19에 마지막으로 업데이트 됨).

입력 사양 : 프로그램은 공백, 별표 및 줄 바꿈을 임의로 조합하여 사용해야합니다. 입력은 최대 23 행과 80 문자를 포함합니다. 빈 줄은 없지만 줄은 공백만으로 구성 될 수 있습니다. 단일 후행 줄 바꿈이 포함되며 무시해야합니다.

출력 : 사용자가 프로그램을 수동으로 종료 할 때까지 운영 체제의 텍스트 콘솔 또는 터미널 에뮬레이터에 대한 ASCII 문자 (공백, 별표) 및 제어 코드 (캐리지 리턴, 줄 바꿈, ANSI 이스케이프 코드 등)를 출력합니다. 운영 체제에서 해당 설정을 허용하는 경우 터미널 창이 80x24 자라고 가정 할 수 있습니다.

규칙 :

  • 애니메이션은 부드럽고 빠릅니다 (15fps 선호).
  • 눈의 밀도는 5 %에서 15 % 사이 여야합니다.
  • 초당 하나 이상의 눈 화면이 스크롤 될 수 있습니다. 즉, 1 초에 24 줄을 초과하여 새로운 눈을 추가 할 수 있습니다.
  • 눈이 화면 상단으로 들어갈 때 눈에 뚜렷한 패턴이 표시되어서는 안됩니다. 무작위로 보여야합니다.
  • 프로그램은 시작될 때 가능한 빨리 화면의 모든 행을 눈으로 채워야합니다. 화면의 개별 행을 처음 채우는 것이 시청자에게 분명하지 않아야합니다.
  • 입력 ASCII 아트의 왼쪽 아래 모서리는 화면의 왼쪽 아래 모서리에 있어야합니다 (자세한 설명은 그림 1).
  • ASCII 아트 내부 또는 아래 영역에 별표가 영구적으로 채워져 있으면 안됩니다. 그러나 별표는이 영역을 스크롤 할 수 있지만 반드시 그럴 필요는 없습니다.
  • 입력에 표시된 것을 제외하고 화면 하단이나 기존 눈 위에 눈이 쌓이지 않아야합니다.
  • 공백을 반대 순서로 채우면 크리스마스 트리 애니메이션이 원래 코드의 출력과 매우 다르게 보이기 때문에 아래쪽 공백은 위쪽 공백보다 먼저 채워야합니다. (2011-12-20에 추가됨)

즐거운 휴일 보내세요!

그림 1 : 80x24 화면의 레이블이있는 영역

---------------------------New snow added on this line--------------------------
                                                                             |
                                                                             |
----------------------------------------------------------+                  |
                                                    ****  |                  |
    Snow MUST fall  Snow MAY fall ---------------->  **** |                  |
    through this    through these          ****      **** |  Snow MUST fall  |
    area.           areas of a              ****     **** |  through this    |
                    completed   \--------->  ****     ****|  area.           |
        ASCII art   scene.    \     ***        ****   ****|                  |
          area         \       \   *******      ****  ****|                  |
                        \       \    ********     ***  ***|  (ALL CAPS terms |
      (located in        \       \-->   *********  ***    |  have standard   |
       lower left         \     *******     ******  MAY   |     RFC 2119     |
       corner of           \    *************  **   fall  |    meanings.)    |
       screen)              \        ***********    here  |                  |
                         *** +--->          ****  ***     |                  |
                         *** | ****************   ***     |                  |
  | Snow MUST fall       *** | ****************   ***     |                  |
  | through this         *** +--->                ***     |                  |
  | area.                *** | ****************   ***     |                  |
--+---------------------+*** +--->                ***+----+------------------+--
  |   Snow MUST NOT     |****************************|      Snow MUST NOT    |
  V  accumulate here.   |****************************|     accumulate here.  V

입력 예

코드 골프 배너

 ******   *******  ********  ********     ******    *******  **       ******** 
**    ** **     ** **     ** **          **    **  **     ** **       **       
**       **     ** **     ** **          **        **     ** **       **       
**       **     ** **     ** ******      **   **** **     ** **       ******   
**       **     ** **     ** **          **    **  **     ** **       **       
**    ** **     ** **     ** **          **    **  **     ** **       **       
 ******   *******  ********  ********     ******    *******  ******** **       

스택 오버플로 로고

                                                    ****
                                                     ****
                                           ****      ****
                                            ****     ****
                                             ****     ****
                                    ***        ****   ****
                                   *******      ****  ****
                                     ********     ***  ***
                                        *********  ***
                                *******     ******
                                *************  **
                                     ***********
                         ***                ****  ***
                         ***   ****************   ***
                         ***   ****************   ***
                         ***                      ***
                         ***   ****************   ***
                         ***                      ***
                         ****************************
                         ****************************

크리스마스 트리

                                        *
                                       ***                           *
                *                     *****                         ***
               ***                   *******           *           *****
              *****                 *********         ***            *
                *                  ***********       *****
                       *          *************     *******
        *             ***        ***************       *               *
       ***           *****      *****************                     ***
      *****         *******    *******************                   *****
     *******           *      *********************                 *******
    *********                           *                          *********
        *                                                              *

1
세 번째 크리스마스 트리가 고장났습니다.
Bobby

좋은 도전! 더 쉽게 참조 할 수 있도록 규칙을 열거해야한다고 생각하고 세 번째와 여섯 번째 규칙을 이해하지 못합니다.
hallvabo

@hallvabo 나는 두 가지 규칙을 명확히했다.
PleaseStand

설명 요청 : 줄 바꿈이 80 자 최대 줄 길이에 포함되어 있습니까 , 아니면 최대 80 자 + 줄 바꿈입니까? (나는 후자를 가정했지만 일부 제출은 전자를 가정 한 것으로 보인다.)
Ilmari Karonen

@IlmariKaronen 후자.
PleaseStand

답변:


5

펄, 196/239 자

chomp(@p=(@f=($"x80)x24,<>)[-24..-1]);{@s=(join("",map rand>.1?$":"*",1..80),@s);if(@s>23){$t=$f[$_],print$_?$/:"\e[H",($f[$_]|=$s[$_]&$p[$_])|($s[$_]&=~$t^$f[$_])for 0..23;select"","","",.1}redo}

이 솔루션은 패턴이 상향식이 아닌 하향식으로 채워진다는 점에서 JS 예제와 다릅니다.하지만 규칙에 대해 아무 것도 말하지 않았으므로 괜찮습니다.

\e리터럴 ESC 문자 로 대체 하여 사소한 1 문자 감소를 얻을 수 있지만 코드를 읽고 편집하기가 훨씬 어렵습니다.


업데이트 : 내가 했다 아래에서 위로 패턴을 채우고, 눈은 43 개 여분의 문자의 비용으로, 예 JS 구현과 같이 패턴의 작성 부분을 통해 떨어지지 않는 버전을 마련하기 위해 관리 :

chomp(@p=(@q=@f=($"x80)x24,<>)[-24..-1]);{@s=(join("",map rand>.1?$":"*",1..80),@s);if(@s>23){my$q;$q[-1-$_]=($q|=$p[-$_]&~$f[-$_])for@a=0..23;print$_?$/:"\e[H",($f[$_]|=$s[$_]&$p[$_]&~$q[$_])|($s[$_]&=~$f[$_])for@a;select"","","",.1}redo}

교체 ($s[$_]&=~$f[$_])로 단지 $s[$_]패턴의 작성 부분을 통해 떨어지는 눈의 패스를 시켜서 11 개 문자를 저장 (스펙과 일치가 아니라 예를 구현) 것입니다.


일주일 후에도 여전히 레이스를 이끌고있는 것 같으므로 더 많은 경쟁을 장려하기 위해 솔루션이 어떻게 작동하는지 설명해야한다고 생각합니다. (참고 :이 설명은 196-char 하향식 필링 버전에 대한 것입니다. 나중에 다른 버전을 포함하도록 수정할 수 있습니다.)

우선, 내 솔루션이 기반으로하는 하나의 큰 트릭은 ASCII 문자 코드가 배열되는 방식으로 인해 공간에 대한 ASCII 코드의 1 비트가 코드에 대한 ASCII 문자의 하위 세트 일뿐입니다. 별표.

따라서, 다음과 같은 표현은 해당 : " " & "*" eq " "" " | "*" eq "*". 개별 문자를 반복하지 않고도 장면의 정적 부분과 움직이는 부분을 결합하기 위해 비트 단위 문자열 연산을 사용할 수 있습니다.

그래서 그 길을 벗어나서 코드를 살펴 보겠습니다. 디 골프 버전은 다음과 같습니다.

chomp(@p = (@f = ($" x 80) x 24, <ARGV>)[-24..-1]);
{
    @s = (join('', map((rand > 0.1 ? $" : '*'), 1..80)), @s);
    if (@s > 23) {
        foreach (0 .. 23) {
            $t = $f[$_];
            print( $_ ? $/ : "\e[H" );
            print( ($f[$_] |= $s[$_] & $p[$_]) | ($s[$_] &= ~$t ^ $f[$_]) );
        }
        select '', '', '', 0.1;
    }
    redo;
}

첫 번째 줄은 배열 @f( "고정")과 @p( "패턴")을 설정합니다. @f디스플레이의 고정 부분을 형성하고 공백 만 포함하여 시작하지만 @p직접 표시되지 않는 입력 패턴이 포함됩니다. 애니메이션이 진행됨에 따라 애니메이션 @f이 결국처럼 보일 때까지 점점 더 많은 별표를 추가 @p합니다.

특히, 각각 80 개의 공백으로 24 개의 문자열을 @f = ($" x 80) x 23설정 @f합니다. ( $"이것은 기본값이 공백 인 특수 Perl 변수입니다.) 그런 다음이리스트를 가져 와서 readline 연산자를 사용하여 입력 라인을 추가 <>하고이 결합 된리스트의 마지막 24 행을 가져 와서 할당합니다 @p: @p빈 줄로 채우는 간단한 방법으로 패턴이 원하는 곳에 나타납니다. 마지막으로 chomp입력 줄을 입력 @p하여 후행 줄 바꿈을 제거하여 나중에 문제가 발생하지 않도록합니다.

이제 메인 루프를 봅시다. 세미콜론을 생략하기 전에 블록 바로 뒤에 있기 때문에 특히 또는 {...;redo}보다 무한 루프를 작성하는 것이 더 짧은 방법 이라는 것이 밝혀졌습니다 .while(1){...}for(;;){...}redoif

메인 루프의 첫 번째 줄은 배열 @s(물론 "눈"의 경우)을 소개합니다. 여기에는 반복 할 때마다 90 % 간격의 임의의 80 자 문자열과 10 % 별표가 붙습니다. (몇 줄의 문자를 저장하기 위해 실제로 @s배열 의 끝에서 여분의 줄을 팝하지 않으므로 점점 길어지고 계속됩니다. 결국 배열이 메모리에 들어가기에 너무 길어지면 프로그램이 정지됩니다. 대부분의 사람들이 영원히이 애니메이션을 보는 것보다 훨씬 오래 걸릴 수 있습니다. 추가 pop@s;문을 전에 select일곱 개 문자의 비용으로 그것을 해결하는 것입니다.)

메인 루프의 나머지 부분은 if블록으로 싸여 @s배열에 최소한 24 줄이 포함 된 후에 만 실행됩니다 . 이는 스펙을 준수하는 간단한 방법으로, 전체 디스플레이를 처음부터 떨어지는 눈으로 채워야하고 비트 단위 작업도 약간 단순화해야합니다.

다음은 foreach골프 버전에서 실제로 for 0..23수정자를 포함 하는 단일 명령문 인 루프를 제공합니다 . 루프의 내용은 아마도 약간의 설명이 필요할 것이므로 아래에서 좀 더 압축을 풀겠습니다.

foreach (0 .. 23) {
    print $_ ? $/ : "\e[H";     # move cursor top left before first line, else print newline
    $t = $f[$_];                # save the previous fixed snowflakes
    $f[$_] |= $s[$_] & $p[$_];  # snowflakes that hit the pattern become fixed 
    $s[$_] &= ~$t ^ $f[$_];     # ...and are removed from the moving part
    print $f[$_] | $s[$_];      # print both moving and fixed snowflakes ORed together
}

우선 $_다른 변수를 지정하지 않으면 Perl의 기본 루프 카운터 변수입니다. 여기서는 0에서 23까지, 즉 디스플레이 프레임의 24 개 라인 이상에서 실행됩니다. 배열에서 $foo[$_]인덱스 된 요소를 나타냅니다 .$_@foo

디 골프 루프의 첫 번째 줄에서 개행 ( $/특별 변수 에서 편리하게 얻음)을 인쇄하거나 $_0과 같으면 string을 표시합니다. "\e[H"여기서 \eESC 문자를 나타냅니다. 커서를 화면의 왼쪽 상단으로 이동 시키는 ANSI 터미널 제어 코드 입니다. 기술적으로 특정 화면 크기를 가정하면 애니메이션을 실행하기 위해 터미널 크기를 조정할 필요가 없으므로이 버전으로 유지했습니다.

$t = $f[$_]라인 우리 단지 현재 값으로 저장 $f[$_](그러므로 "임시"변수는 $t) 전에 잠재적 다음 라인에서 변화 $s[$_] & $p[$_]하여 떨어지는 눈과 입력 패턴의 교차점 (비트 단위 AND)를 제공하고, |=운영자 논리합 고정 출력 라인에 $f[$_].

그 아래 줄 $t ^ $f[$_]에는 이전 및 현재 값의 비트 별 XOR $f[$_], 즉 이전 줄에서 변경된 비트 목록 (있는 경우)을 제공하고 입력 문자열 중 하나를 ~무효화하면 출력 이 무효화됩니다. 따라서 우리가 얻는 것은 이전 줄에서 추가 한 것을 제외한 모든 비트가 1로 설정된 비트 마스크입니다 $f[$_]. 해당 비트 마스크를 AND하면 AND에서 해당 비트가 $s[$_]제거됩니다. 사실상 이것은 떨어지는 눈송이가 고정 된 패턴의 구멍을 채울 때 떨어지는 눈 배열에서 제거됨을 의미합니다.

마지막으로 print $f[$_] | $s[$_](골프 버전에서는 이전 두 줄을 OR로 연결하여 구현) 현재 줄에 고정 및 움직이는 눈송이의 합집합 (비트 OR)을 인쇄합니다.

설명해야 할 또 다른 사항 select '', '', '', 0.1은 내부 루프 아래에 있습니다. 이것은 Perl에서 0.1 초간 잠자기 어려운 방법입니다. 어리석은 역사적 이유 때문에 표준 Perl sleep명령의 해상도는 1 초이며 모듈 sleep에서 더 잘 가져 오려면 4-arg를 사용Time::HiRes 하는 것보다 많은 문자가 필요 합니다.select


약간의 버그가있는 것 같습니다 : 24 번째 줄은 사용되지 않으며 ASCII 아트의 마지막 줄은 23 번째 줄입니다. 그리고 원래는 그것을 지정하지 않았지만 실제로는 더 낮은 공간을 채워야합니다.
PleaseStand

@PleaseStand : say2 개의 추가 문자를 희생시키면서 24 줄을 모두 사용하도록 코드를 변경했습니다 (실수로을 제거했습니다 ). 필자는 채우기 순서를 매우 쉽게 변경할 수 있다고 생각하지 않습니다. 내 구현은 근본적으로 그것에 묶여 있습니다.
Ilmari Karonen

좋은 설명! 이 항목을 다시 투표 할 수 있기를 바랍니다.
Dillon Cower

@PleaseStand : 나는 실제로 않았다 이제 거의 당신의 JS 예와 같은 보이는 상향식 (bottom-up) 충전 버전을 만들기 위해 관리; 하향식 항목보다 약간 길지만 지금까지 다른 항목보다 짧습니다.
Ilmari Karonen

3

HTML 및 JavaScript, 436 자

입력 앞에 추가하십시오.

<body onload="for(a=[],b=[],c=document.body.firstChild,e=c[H='innerHTML'].split(N='\n'),f=e.length-1,g=24,h=g-f;f--;)for(X=80;X--;)b[80*(h+f)+X]='*'==e[f][X];for(setInterval(F='for(y=24;y--;)for(x=80;x--;)if(a[w=80*y+x]){d=1;if(b[w])for(d=0,z=y+1;24>z;++z)b[s=80*z+x]&&!a[s]&&(d=1);d&&(a[w]=0,a[w+80]=1)}for(x=80;x--;).1>Math.random(i=0)&&(a[x]=1);for(t=\'\';1920>i;++i)t+=\'* \'[+!a[i]],79==i%80&&(t+=N);c[H]=t',67);g--;)eval(F)"><pre>

코드 골프 , 스택 오버플로 로고 , 크리스마스 트리 와 같은 각 예제에서 실행되는 것을 참조하십시오 . Internet Explorer 사용자는이 제출이 올바르게 작동하려면 버전 9를 실행하고 "문서 모드"를 "IE9 표준"(F12 개발자 도구 사용)으로 설정해야합니다.


1
3 개 모두 고장난 것 같아? pasteall.org/pic/show.php?id=66297
CoDEmanX

1

파이썬, 299 자

줄 바꿈이 80 자 제한에 포함되어 있다고 가정하면 규칙을 준수해야합니다.

import random,sys,time
C=1920
v=_,x=' *'
a=['']*C
f=lambda n:[random.choice(e*9+x)for e in _*n]
for e in sys.stdin:a+="%-80s"%e
a=a[-C:]
s=f(C)
while 1:
 z=0;t=''
 for e in s:
    t+=v[x<a[z]or e>_]
    if(e>_<a[z])>(x in a[z+80::80]):a[z]='+'
    t+=z%80/79*'\n';z+=1
 print t;s=f(80)+s[:-80];time.sleep(.1)

입력에 정확히 80 자 (줄 바꿈) 길이의 행이 있으면 출력이 고정됩니다. PleaseStand에게 문제가 없는지 확인하도록 요청했습니다.
Ilmari Karonen

80 자 너비의 각 줄 끝에 줄 바꿈을 포함시키기 때문입니다. 줄 바꿈을 포함해야하지만 터미널이 80 자라고 가정 할 수 있기 때문에 설명이 모호합니다 (이 경우 줄 바꿈을 생략하고 자동 줄 바꿈에 의존 할 수 있음).
hallvabo

실제 문제는 입력 줄을 80 문자로 채우기 전에 줄 바꿈을 제거하지 않기 때문에 80 문자 + 줄 바꿈 입력은 실제로 81 문자를 추가 a하여 인덱싱을 망칠 수 있습니다. 난 그냥 그것을 시도, 그것은 대체 모양 %e%e.rstrip()라인에 6 수정 문제. (물론, 더 짧은 수정이있을 수도 있습니다. 저는 파이썬 골프를 잘 못합니다.)
Ilmari Karonen

81 개의 문자 줄을 지원하려면 숫자를 변경하면 제대로 작동합니다. 줄당 100 자 이하로 유지되는 한 문자 수를 변경하지 않습니다. :-)
hallvabo

81 문자 줄을 사용하도록 코드를 변경하면 80 열 터미널에서 올바르게 실행되지 않습니다. 80 열 출력을 올바르게 생성 하는 것은 80 열 입력을 올바르게 받아들이지 않는 것입니다. 시도해보십시오. 각 줄에 80 개의 별표가있는 두 줄로 입력 파일을 만들고 결과를 확인하십시오. 그렇게 어렵지 않아야합니다. 내 솔루션은 잘 처리합니다.
Ilmari Karonen

0

자바, 625 자

import java.io.*;import java.util.*;class s extends TimerTask {int _c,_k;char _i[],_o[];boolean _b[];public s(String f) throws IOException {_i=new char[23*80];_o=new char[80];_b=new boolean [23*80];BufferedReader br = new BufferedReader(new FileReader(f));while (br.read(_i,_c++*80,80)!=-1);} public void run(){_k=--_k<0?_c:_k;for(int i=0;i<80;_b[_k*80+i]=Math.random()>0.9?true:false,i++);for(int m=0;m<_c;m++){for(int n=0;n<80;_o[n]=_b[(_k+m)%_c*80+n]?'*':_i[m*80+n],n++);System.out.println(_o);}}public static void main(String[] a) throws IOException{Timer timer=new Timer();timer.scheduleAtFixedRate(new s(a[0]),0,500);}}

Java의 간단한 솔루션.


좋았지 만 사양을 준수한다고 생각하지 않습니다. 특히, 처음부터 전체 패턴을 보여줍니다. 샘플 데모에서와 같이 "떨어지는 눈에서 형성되지 않습니다". (물론, 이것은 질문에서 더 잘 설명 될 수 있습니다. 데모를보고 어떻게 해야하는지 이해해야합니다.) 또한 프레임 속도가 너무 느리고 눈이 가득한 화면으로 시작하지 않습니다. 주어진 예제와 다른 입력 형식을 가정하고 실제로 프레임 사이의 커서 위치를 재설정해야합니다 (인쇄 "\033[H"해야 함).
Ilmari Karonen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.