도미노처럼 떨어지는 걸 봐


22

너비가 80자인 터미널 안에 살고 있습니다. 지루해서 도미노를 연주하기로 결정했습니다. 아니요, Scrabble처럼 보이는 지루한 종류는 아닙니다. 재미있는 시간으로 1 초 동안 쓰러 뜨리는 재미있는 종류입니다.

터미널에서 도미노는 다음과 같습니다.

|   upright domino
\   left-tilted domino
/   right-tilted domino
__  fallen domino

우리 모두 알다시피, 기울어 진 도미노가 똑바로 닿으면 두 번째 도미노도 기울어집니다. 이것에 대한 유일한 예외는 두 개의 기울어 진 도미노가 그것에 닿는 경우입니다.

|\ --> \\        /| --> //        /|\ --> /|\

이 전환에 100ms가 걸리도록 터미널의 중력 상수를 조정하십시오.

기울어 진 도미노가 다른 도미노 또는 터미널의 벽에 의해 지탱되면 이동이 종료됩니다.

기울어 진 도미노가 없습니다.

\||||____||||/__                /|\    /\    /|\                __\||||____||||/

두 개의 가장 바깥쪽으로 기울어 진 도미노는 터미널 벽에 의해 지원되고 다른 모든 도미노에 의해 지원되므로 (80 자)가 이동합니다.

그러나 틸팅 방향의 공간이 비어 있으면 도미노가 떨어집니다.

| \\ --> |__\        // | --> /__|

단말기. 중력 상수. 당신은 요점을 얻는다…

마지막으로 왼쪽에서 약간의 바람이 나므로 오른쪽 기울어 진 도미노가 왼쪽 기울어 진 도미노보다 빠릅니다.

|/ \| --> |__\|

태스크

터미널에서 도미노를 재생하는 애니메이션을 보여주는 프로그램 / 기능을 작성하십시오.

코드는 다음을 수행해야합니다.

  1. 입력에서 도미노의 초기 상태를 나타내는 문자열을 읽습니다.

    이 문자열은 80자를 초과하지 않으며 위에서 설명한 도미노와 빈 공간으로 만 구성됩니다.

  2. 상태를 인쇄하고 100ms 동안 기다립니다.

  3. 위에서 설명한대로 상태를 변환하십시오.

  4. 상태가 변경된 경우 2로 돌아갑니다.

추가 규칙

  • 입력 문자열의 길이는 터미널 너비에 영향을 미치지 않습니다. 줄이 80 자보다 짧아도 터미널의 벽은 여전히 ​​80 자 떨어져 있습니다.

  • 2 단계를 실행할 때마다 상태가 동일한 위치에 인쇄되어 이전 상태를 덮어 써야합니다.

  • 일부 언어는 정확히 100 밀리 초를 기다릴 수 없으므로 50 ~ 1000 밀리 초 사이의 양을 기다립니다.

  • 표준 규칙이 적용됩니다.

  • 초기 상태

     ||\/||
    

    다음을 인쇄하십시오 (하나 이상).

     ||\/||
     |\\//|
     \\\///
    __\\//__
    
  • 초기 상태

    /||||\
    

    다음을 인쇄

    /||||\
    //||\\
    ///\\\
    
  • 초기 상태

    /|||\
    

    다음을 인쇄

    /|||\
    //|\\
    
  • 초기 상태

    |/ \|/ \|/ \|/ \|
    

    다음을 인쇄하십시오.

    |__\|__\|__\|__\|
    
  • 초기 상태 (80 자)

    \||||____||||/__                /|\    /\    /|\                __\||||____||||/
    

    다음을 인쇄

    \||||____||||/__                /|\    /\    /|\                __\||||____||||/
    

답변:


13

망막 , 87 86 85 바이트

1 바이트를 절약 해 준 Dennis에게 감사합니다.

^.{0,79}$
$0 
:`^
<ESC>c
(`/ | \\
__
/\|(?!\\)
//a
(?<!/)\|\\
\\
$
aaaaa
a
aaaa
(a+)+b|a
<empty>

<ESC>실제 제어 문자 (0x1B)로 바꿔야합니다. <empty>빈 후행을 나타냅니다. 그런 다음 -s플래그 를 사용하여 단일 파일에서 위의 코드를 실행할 수 있습니다 .

이 코드에는 ANSI 이스케이프 코드를 지원하는 터미널이 필요합니다. Retina의 출력에서 ​​줄 바꿈을 억제 할 수 없으므로 <ESC>c매번 전체 콘솔을 지워야합니다 . 모노를 사용하여 bash에서 코드를 테스트하여 Retina를 실행했습니다.

설명

^.{0,79}$
$0 

입력에 80 자 미만이 포함 된 경우 공백을 추가하여 시작합니다. 있도록이다 /오른쪽 끝에서 별도로 처리 할 필요가 없습니다.

:`^
<ESC>c

이제 <ESC>c터미널을 지우는 ANSI 이스케이프 코드 인 문자열 앞에 추가 합니다. 따라서 문자열이 인쇄 될 때마다 터미널 상단에서 인쇄됩니다. 는 :`, 즉 초기 구성이 대체의 결과를 출력 망막에 지시합니다.

(`/ | \\
__

(`루프를 시작합니다. 일치하는 것이 없기 때문에 )루프는 프로그램의 마지막 단계까지 진행되는 것으로 가정합니다. 각 반복은 도미노가 떨어지는 한 단계를 시뮬레이션 한 다음 "잠자기"합니다. 이 무대을 대체 처음 /\로 공간 옆에 __. / \일치하는 항목은 겹칠 수 없으며 왼쪽에서 오른쪽으로 검색되므로 대소 문자를 올바르게 처리합니다 . 그래서는 /<sp>일치와 상태로 될 것 __같은이 있음을 \일치시킬 수없는, 우리는 올바른 얻을 __\.

/\|(?!\\)
//a

이 턴 /|//제공은 더 없다 \옆에. 우리는 a이 새로운 /것이 다음 단계를 엉망으로 만들지 않도록 덧붙 입니다.

(?<!/)\|\\
\\

반대 상황 : 옆에 없는 경우 |\로 전환 하십시오. 시뮬레이션의이 단계를 완료 했으므로 여기 에 넣을 필요는 없습니다 .\\/a

자고있는 부분은 ...

$
aaaaa

a코드 끝에 5를 더 추가 합니다.

a
aaaa

각각 a을 4 a초로 바꾸어 결국 20 a초를 얻습니다 .

(a+)+b|a
<empty>

이제 재미있는 부분은 ... 우리는 역 추적 역 추적 의 도움으로 잠을 잔다 . (a+)+그룹의 반복 사이 의 일치를 분할하는 기하 급수적 인 방법이 있습니다. 이로 b인해 일치가 실패 하기 때문에 엔진은 (a+)+b일치하지 않는 것으로 판단하기 전에 해당 조합 중 하나를 역 추적하고 시도합니다 . a결국 20 초 동안 0.5 초 정도 걸립니다.

동시에 정규 표현식이 단일 추적 을 허용 a하지만 역 추적 수행 한 후에 만 가능 합니다. 일치하면 빈 문자열로 바꾸고 문자열에서 a삽입 한 모든 이유를 제거 합니다.

루프 반복이 끝날 때 문자열 인쇄가 남습니다. 여기 Retina에서 루프의 인쇄 동작을 아직 수정하지 않은 것이 편리합니다. 현재 각 단계마다 "print"또는 "do n't print"라는 플래그가 하나만 있습니다. 프로그램의 마지막 단계를 제외하고 기본값은 "인쇄 안 함"이며 기본값은 "인쇄"입니다. 그러나 스테이지가 반복되므로 실제로 각 반복에서 현재 문자열을 인쇄합니다. 일반적으로, 그것은 정말 성가 시며, 최종 결과 만 원한다면 거의 항상 빈 스테이지를 추가해야하지만 여기에서 4 바이트를 절약 할 수 있습니다.


6

자바 (ES6) 206 148 129 158 바이트

나는 마침내 그것을 아주 낮은 지점으로 가져 갔지만 콘솔을 지우거나 여분의 공간을 추가하지는 않았다. 이러한 문제는 현재 해결되었습니다.

c=console;d=s=>{c.clear(s[79]||(s+=' ')),c.log(s),t=s[R='replace'](/\/ | \\/g,'__')[R](/\/\|/g,'//a')[R](/\|\\/g,'\\\\')[R](/a/g,'');t!=s&&setTimeout(d,99,t)}

Node.JS에서 작동하는 대체 153 바이트 버전 :

d=s=>{s[79]||(s+=' '),console.log("\033c"+s),t=s[R='replace'](/\/ | \\/g,'__')[R](/\/\|/g,'//a')[R](/\|\\/g,'\\\\')[R](/a/g,'');t!=s&&setTimeout(d,99,t)}

IMHO, 아주 재밌습니다. 여기 HTML 버전을 사용해보십시오.

아마도 골프를위한 더 많은 공간이있을 것입니다. 제안을 환영합니다!


내 시간의 10 분을 낭비한 실행 가능한 데모의 경우 +1, 무작위 기능의 경우 +1. 그러나 Dennis가 언급했듯이 첫 번째 테스트 사례에서는 실패합니다. 시도 /하거나 /|타일이 제대로 떨어지지 않는 것을 볼 수 있습니다.
dberm22

@Dennis이 문제를 지적 해 주셔서 감사합니다. 나는 지금 두 가지를 모두 고쳤다 고 생각합니다.
ETHproductions

노드는 팻 화살표에 만족하지 않지만 그렇지 않으면 잘 작동합니다. \033리터럴 ESC 바이트로 대체 하여 3 바이트를 절약 할 수 있습니다 .
Dennis

2

펄 5 154 146

두 정규 표현식 사이의 상태를 유지하기 위해 임시 문자를 사용해야했습니다.
같은 위험을 처리하기 위해 / | | | \는 / / 대신 / / / \ \로 끝납니다. \ \.

$_=substr(pop.' ',0,80);$|++;while($}ne$_){print"$_\r";$}=$_;s@ \\|/ @__@g;s@/\|(?=[^\\])@/F@g;s@([^/])\|\\@$1\\\\@g;tr@F@/@;select($\,$\,$\,0.1)}

테스트

$ perl dominos.pl '|\ |\/|||\/|'
|\__\//|\\/__

1
슬래시 이외의 구분 기호를 사용하는 경우 (예 : s, \\|/ ,__,g대신) 여러 개의 백 슬래시를 제거 할 수 있습니다 s/ \\|\/ /__/g.
hobbs

좋은 팁. 그 트릭을 잊어 버렸습니다. 그리고 부정 세트를 사용하여 몇 바이트를 추가로 줄였습니다.
LukStorms

2

ES6 , 220 218 195 바이트

축소

f=d=>{var e,c=console;if(!d[79])d+=' ';c.clear();c.log(d);e=d;d=d[R='replace'](/\/\|\\/g,'a')[R](/\/ | \\/g,'__')[R](/\/\|/g,'//')[R](/\|\\/g,'\\\\')[R]('a','/|\\');if(e!=d)setTimeout(f,100,d);};

더 읽기

f=d=> {
    var e,
    c=console;
    if(!d[79])
        d+=' ';
    c.clear();
    c.log(d);
    e=d;
    d = d[R='replace'](/\/\|\\/g, 'a')  //Substitute '/|\' with 'a' so it doesn't get replaced
        [R](/\/ |  \\/g, '__')     //Replace '/ ' and ' \' with '__'
        [R](/\/\|/g, '//')    //Replace '/|' with '//'
        [R](/\|\\/g, '\\\\')  //Replace '|\' with '\\'
        [R]('a', '/|\\');     //Put '/|\' back
    if(e!=d)
        setTimeout(f,100,d);
};

2
프로그래밍 퍼즐 및 코드 골프에 오신 것을 환영합니다! 1. 왜 ES6 표기법을 사용하는지 잘 모르겠습니다. () = > {그리고 }()단순히 코드에서 제거 할 수 있습니다. 2. 경고 상자가 애니메이션에 적합한 출력 형식이라고 생각하지 않습니다. JS를 HTML에 임베드하거나 필요한 변경을 수행하여 명령 행에서 작동 할 수 있습니다. 3. 두 경우 모두 코드가 약 기다려야합니다. 한 상태와 다음 상태 인쇄 사이에 100ms
Dennis

2
PPCG에 오신 것을 환영합니다! 나는 체크 아웃 제안 이 게시물을 하고 이 게시물 의 도움으로 당신의 골프를 개선 할 수 있습니다.
jrich

골프 팁에 대한 제안 및 링크에 감사드립니다. 아직 조금 길지만 조금 단축하고 타이머를 추가했습니다. 팁을 더 자세히 살펴보고 단축 할 수있는 내용을 살펴 보겠습니다.
user3000806

1
이제 터미널에서 작동하지만 여전히 이전 상태에서 업데이트 된 상태를 인쇄하지는 않습니다. Linux에서는 console.log("^[c"+d)대신 ^[ESC 문자 (1 바이트)가있는 위치 를 호출하여이 문제를 해결할 수 있습니다 .
Dennis

1
첫 번째 .replace를로 변경하고 [R='replace']이후의 각 을로 변경하면 [R]상당히 줄어 듭니다. setTimeout(f,100,d)현재 설정 대신 사용하여 몇 바이트를 절약 할 수도 있습니다 .
ETHproductions

2

C #, 335 바이트

훌륭한 언어 선택이 아닙니다.

두 자리 숫자를 선택하기 위해 50에서 1000 사이의 지연이 남용되었습니다.

명확성을 위해 새 줄과 들여 쓰기가 추가되었습니다.

namespace System.Threading{
    class P{
        static void Main(string[]z){
            var c=@"/|\,/|\,/|,//,|\,\\,/ ,__, \,__".Split(',');
            for(string a=z[0].PadRight(80),b="";a!=b;){
                Console.Clear();
                Console.Write(b=a);
                Thread.Sleep(99);
                a="";
                for(int i,j;(i=a.Length)<80;)
                    a+=(j=Array.FindIndex(c,d=>b.Substring(i).StartsWith(d)))%2==0
                        ?c[j+1]
                        :b.Substring(i,1);
            }
        }
    }
}

1

PHP, 175 바이트

$i=sprintf("%-80s",$argv[1]);$p='preg_replace';do{echo($o=$i)."\r";$i=$p('(/\|\\\\(*SKIP)(?!)|(?|(/)\||\|(\\\\)))','$1$1',$p('(/ | \\\\)','__',$i));usleep(1e5);}while($i!=$o);

축소되지 않은 :

$input = sprintf("%-80s",$argv[1]);
do {
  echo $input."\r";
  $old = $input;
  $input = preg_replace('(/ | \\\\)','__',$input);
  $input = preg_replace('(/\|\\\\(*SKIP)(?!)|(?|(/)\||\|(\\\\)))','$1$1',$input);
  usleep(100000);
}
while( $input != $old);

기본적으로 정규식 골프. 먼저 공간이있는 떨어지는 도미노를 평평하게 만듭니다 (왼쪽에서 오른쪽으로 일치하는 순서로 인해 "바람"이 불면). 그런 다음 못생긴 부분이 온다.

  • 일치 /|\하고 건너 뜁니다.
  • 일치 (/)|하고 교체//
  • 일치 |(\)하고 교체\\

이로 인해 도미노가 떨어집니다. 마지막으로 다음 단계를 100ms 정도 기다리십시오.

()정규 표현식에서 구분 기호로 사용하면 /탈출 할 필요가 없으므로 최소한의 도움이됩니다!


100 문자 대신 50ms를 기다려 1 문자를 절약 할 수 있습니다.) PHP는 10 ^ 5를 허용합니까?
BlueCacti

1

POSIX shell + sed, 144

sed 's/^.\{1,79\}$/& /;s/.*/printf '"'&\\r'"';sleep .1/;h;:;s,/|\\,/:\\,g;s,\(/ \| \\\),__,g;s,/|,//,g;s,|\\,\\\\,g;H;t;x;y/:/|/;s/\\/\\\\/g'|sh

이것은 두 부분으로되어 있습니다. 도미노를 토핑하는 주요 작업은 표준 sed패턴 교체로 라인을 홀드 공간에 축적합니다. 우리는 일시적으로 설정 /|\으로 /:\마지막에 회복을 보호 할 수 있습니다.

s/^.\{0,79\}$/& /
h

:
s,/|\\,/:\\,g
s,\(/ \| \\\),__,g
s,/|,//,g
s,|\\,\\\\,g
H
t

x
y/:/|/

sed지연을 삽입 할 수있는 방법이 없기 때문에 (terminfo / termcap을 보았지만 표준 방법을 찾을 수 없었습니다) 각 줄을 감싸서 printf "...\r"; sleep .1 100ms마다 줄을 인쇄합니다. 한 줄만 있으면 명령의 문자가 토글 링의 대체로 만지지 않기 때문에 실제로이 작업을 먼저 수행합니다.

모두를 사용하여 테스트 dash 및 GNU coreutils와 함께, POSIXLY_CORRECT환경에서 설정합니다.

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