피보나치 도미노 타일링


11

거기에 고전 조합 결과 타일 할 수있는 방법의 수는 있다고 2*n하여 스트립 1*2도미노는 n은 피보나치 수. 목표는 n다음과 같은 8 개의 타일과 같이 대시와 수직선으로 그려진 주어진 모든 타일을 인쇄하는 것 입니다 n=5.

|————
|————

——|——
——|——

|||——
|||——

————|
————|

||——|
||——|

|——||
|——||

——|||
——|||

|||||
|||||

n입력으로 사용하고 필요한 출력을 인쇄 하는 프로그램 또는 명명 된 기능을 제공 해야합니다. 가장 적은 바이트가 이깁니다.

입력

숫자 n사이 110포함 STDIN 또는 기능 입력을 통한.

산출

2*n스트립 의 가능한 모든 도미노 타일을 가로로 그립니다. 바둑판 식 배열은 순서에 관계없이 각각 정확히 한 번 표시되어야합니다. 빈 줄로 분리해야합니다.

세로 도미노는 두 개의 세로 막대 ( |)로 만들어지고 가로 도미노는 두 개의 대시 ( ) 로 만들어집니다 . -em 대시 대신 하이픈 ( )을 사용 하여 ASCII를 유지할 수 있습니다.

인쇄 된 출력물이 동일하게 보이는 한 공백으로 무엇이든 할 수 있습니다.


마지막 타일링 후 추가 줄 바꿈 이 공백이있는 항목에 해당 합니까?
Dennis

@Dennis 네, 여분의 빈 줄은 괜찮습니다.
xnor

나는 같은 문제를 해결하기위한 많은 다른 접근법을보고 놀랐습니다. 기대 했어?
Level River St

@ steveverrill 아니, 나는 완전히하지 않았다, 그리고 다양성을보고 기쁘게 생각합니다! 그리고 당신은 예상치 못한 케이크를 가져갑니다. 필자가 사용한 대부분의 솔루션으로 피보나치 스타일의 재귀를 주로 생각했습니다. 나는 필터링하는 것이 효과적 일 것으로 기대하지 않고 그것의 문자열을 필터링 할 것이지만 나는, I를했던 범위 ——|데니스의하지 길이 - 같은 길이만큼 n의 문자열 |필터링을 쌍으로 등장. 후자의 경우, s.split('——당신과 같은 산술 접근 방식이 아니라 생성 된 문자열에 대한 정규 표현식이나 문자열 연산을 통해 이루어질 것으로 기대합니다 .
xnor

"1x2 도미노"는 중복이라고 생각합니다.
SuperJedi224

답변:


5

C, 106

골프 버전

f(n){
  for(int i,h=n*2<<n;h--;(i/3|i/3*2)-i||(putchar(i>>h%n&1?45:124),h%n||puts(h%(n*2)?"":"\n")))
    i=h/2/n;
}

원본 버전

i,j,n;
main(){
  scanf("%d",&n);
  for(i=1<<n;i--;)if((i/3|i/3*2)==i){
    for(j=1<<n;j/=2;)printf("%c",i&j?'-':'|');puts("");
    for(j=1<<n;j/=2;)printf("%c",i&j?'-':'|');puts("\n");
  }
}

작동 원리

변수 i1<<n-1아래에서 0 까지 실행되며 가능한 모든 이진수를 숫자로 생성합니다 n. 0은에 인코딩 |하고 1은에 인코딩합니다 -. 우리는 쌍으로 1을 포함하는 숫자에 관심이 있습니다. 분명히 그러한 숫자는 3으로 나눌 수 있습니다.

숫자를 3으로 나누면 결과에 2를 곱하고 그 자체에 결과를 효과적으로 더하여 (3을 효과적으로 곱함) 원래 숫자를 복구 할 수 있습니다. 대부분의 숫자에는 캐리가 필요하지만 프로세스가 관심이 있으니 캐리가 필요하지 않으므로이 경우에만 OR 대신 추가 할 수 있습니다. 이것은식이 i/3|i/3*2원래 값을 반환하는 유일한 숫자이므로 관심 숫자를 테스트하는 데 사용됩니다 i. 아래 예를 참조하십시오.

1111= 15 ---> 0101= 5 ---> 1111= 15 (유효한, 0101|1010== 0101+1010)

1001= 9 ---> 0011= 3 ---> 0111= 7 (잘못된, 0011|0110! = 0011+0110)

테스트 값은 항상 원래 값보다 작거나 같습니다. 3의 배수가 아닌 숫자도 3으로 나눈 다음 3으로 곱하면 원래보다 작은 수를 반환하기 때문에 테스트는 이러한 숫자에 대해 원하는 FALSE도 제공합니다.

원래 버전에서는 몇 개의 루프 j가 사용되어 비트를 스캔 i하고 출력을 생성합니다. 골프 버전에서는 단일 for루프가 사용되는데,이 루프는 0에서 0 h까지 모든 숫자를 통과합니다 . (n*2)*(1<<n)-1i은에 의해 생성됩니다 h/2/n. j에서 해당 수량을 얻으므로 변수 가 더 이상 사용되지 않습니다 h%n. 이 명령을 n*2사용하면 두 행을 동일한 루프에서 인쇄 할 수 있으며 puts명령문의 일부 다중화로 행 끝에 하나 또는 두 개의 개행을 인쇄 할 수 있습니다.

이것의 고기는 for()괄호 의 증분 위치에 있으므로 . 다음 에 실행 i=h/2/h됩니다.

샘플 출력 n = 6 :

$ ./a
6
------
------

----||
----||

--|--|
--|--|

--||--
--||--

--||||
--||||

|----|
|----|

|--|--
|--|--

|--|||
|--|||

||----
||----

||--||
||--||

|||--|
|||--|

||||--
||||--

||||||
||||||

i/3|i/3*2트릭은 독창적입니다! 나는 문법에 대한 산술 표현을 기대하지 않았다.
xnor

3

CJam, 33 27 바이트

LN{_'|f+@"——"f++}ri*\;{_N}/

6 바이트를 골라 낸 @ jimmy23013에게 감사드립니다!

온라인으로 사용해보십시오!

배경

이것은 재귀 알고리즘의 반복 구현입니다.

의 가능한 타일링 N을 위한 가능한 타일링에 수직 도미노을 첨가함으로써 얻어 질 수 1 - N 의 가능한 타일링 및 두 개의 수평 라이더 N - 2 .

이러한 방식으로, n 에 대한 타일링 수는 n-1n-2에 대한 타일링 수 , 즉 n 번째 피보나치 수의 합이다.

작동 원리

LN                                " A:= [''] B:= ['\n']                         ";
  {             }ri*              " Repeat int(input()) times:                  ";
   _'|f+                          "   C = copy(B); for T ∊ C: T += '|'          ";
              @                   "   Swap A and B.                             ";
               "——"f+             "   for T ∊ B: T += "——"                      ";
                     +            "   B = C + B                                 ";
                        \;        " Discard A.                                  ";
                          {_N}/   " for T ∊ B: print T, T + '\n'                ";

예제 실행

$ alias cjam='java -jar cjam-0.6.2.jar'

$ cjam domino.cjam <<< 3
|||
|||

——|
——|

|——
|——

$ for i in {1..10}; do echo $[$(cjam domino.cjam <<< $i | wc -l) / 3]; done1
2
3
5
8
13
21
34
55
89

LNli{_'|f\@"——"f\+2/}*\;{_N}/.
jimmy23013

f\0.6.2에서는 아직 구현되지 않았지만 접근 방식을 결합 할 수있었습니다. 감사!
Dennis

2

하스켈, 89 바이트

f(-1)=[]
f 0=[""]
f n=map('|':)(f$n-1)++map("--"++)(f$n-2)
g=unlines.(>>= \x->[x,x,""]).f

f숫자가 주어지면 가능한 길이 n의 가능한 모든 피보나치 타일링의 한 줄 목록을 반환하는 함수입니다. 모든 타일의 두 줄이 모두 같기 때문에 한 줄을 반환하는 것은 중요하지 않습니다.

f에 재귀 적으로 호출하여 작동 n-1하고 n-2및 추가 "|"하고 "--"문자열로 (각각).

g질문에 답하는 기능입니다. 기본적으로 f입력을 호출 하고 모든 문자열을 두 배로 늘려 두 줄을 표시하고 모두 줄 바꿈으로 결합합니다.

예제 출력 :

*Main> putStrLn $ g 5
|||||
|||||

|||--
|||--

||--|
||--|

|--||
|--||

|----
|----

--|||
--|||

--|--
--|--

----|
----|

2

CJam, 42 37 바이트

3li:L#,{3b"——|"2/f=s}%{,L=},_&{N+_N}/

질문은 ASCII 하이픈으로 바꿀 수 있기 때문에 대시를 1 바이트로 계산했습니다.

온라인으로 사용해보십시오.

작동 원리

2 × L 의 가능한 모든 타일링을 얻기 위해 음수가 아닌 모든 정수 I <3 L 을 반복 하여 기수 3의 짝수는 수평 도미노에 대응하고 홀수는 수직에 대응합니다.

I 는 밑면 3에 L 이하의 숫자를 가지므로 2 × L 스트립 을 덮을 수있는 모든 방법을 생성합니다 . 남은 것은 2 × L 보다 크거나 작은 피복을 걸러 내고 나머지 피복을 인쇄하는 것입니다.

3li:L#,      " Read an integer L from STDIN and push A := [ 0 1 ... (3 ** N - 1) ].       ";
{            " For each integer I in A:                                                   ";
  3b         " Push B, the array of I's base 3 digits.                                    ";
  "——|"2/    " Push S := [ '——' '|' ].                                                    ";
  f=         " Replace each D in B with S[D % 2] (the modulus is implicit).               ";
  s          " Flatten B.                                                                 ";
}%           " Collect the result in an array R.                                          ";
{,L=},       " Filter R so it contains only strings of length L.                          ";
_&           " Intersect R with itself to remove duplicates.                              ";
{N+_N}/      " For each string T in B, push (T . '\n') twice, followed by '\n'.           ";

예제 실행

$ cjam domino.cjam <<< 3
|——
|——

——|
——|

|||
|||

$ for i in {1..10}; do echo $[$(cjam domino.cjam <<< $i | wc -l) / 3]; done
1
2
3
5
8
13
21
34
55
89

멋있는. 왜 당신이 왜 base 3 대신 edc65와 같은 base 2를 사용하지 않았는지 궁금합니다. 필자는 단계에서 선행 0이 잘릴 수 있기 때문이라고 가정합니다 3b. 맞습니까?
Level River St

1
@ steveverrill : 그렇습니다. 바로 그 이유입니다. 따라서 선행 0은 전혀 도미노에 해당하지 않습니다. 그러나 중복이 없으면 세 블록을 단일 블록으로 바꿀 수 있습니다. 나는 이것에 대해 좀 더 생각해야 할 것이다.
Dennis

@ steveverrill : 기본 2 작업을 수행하지는 못했지만 재귀 적 접근법은 훨씬 짧습니다.
Dennis

2

자바 스크립트 (E6) 102

비트 시퀀스 0-> '-'및 1-> '|'에서 구성을 생성하십시오.

F=n=>{
  for(i=0;(j=++i)<2<<n;s.length==1+n&&console.log('\n'+s+s))
    for(s='\n';j>1;j>>=1)s+=j&1?'|':'--';
}

파이어 폭스 / 파이어 버그 콘솔에서 테스트

F(5)

산출

|----
|----

--|--
--|--

----|
----|

|||--
|||--

||--|
||--|

|--||
|--||

--|||
--|||

|||||
|||||

1

하스켈 : 109 바이트

이것은 피보나치 수의 시퀀스를 느리게 계산하기 위해 잘 알려진 Haskell one-liner의 번역입니다.

b=map.map.(++)
w=zipWith
z=w(++)
s=["\n"]:["|\n"]:z(b"--"s)(b"|"$tail s)
f=sequence_.map putStrLn.(w z s s!!)

바둑판 식 배열 문자열의 주요 순서는 다음과 같습니다.

dominos = [""] : ["|"] : zipWith (++) ("--" `before` dominos) ("|" `before` tail dominos)
    where before = map . map . (++)

그리고 비교를위한 피보나치 원 라이너 :

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

사용 예 :

$ ghci fibtile
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main             ( fibtile.hs, interpreted )
Ok, modules loaded: Main.
*Main> f 5
----|
----|

--|--
--|--

--|||
--|||

|----
|----

|--||
|--||

||--|
||--|

|||--
|||--

|||||
|||||

*Main>

1

코브라-176

코브라 골프 패키지가 끝날 때까지 기다릴 수 없습니다.

def m(n)
    for t in.f(n),print t+t
def f(n,x='')as String*
    if x.length<n,for i in.f(n,x+'-').toList+.f(n,x+'|').toList,yield i
    else if not'-'in x.replace('--',''),yield x+'\n'

1

J-54 자

n오른쪽의 인수로 사용되는 기능 .

0{::(];'--'&,"1@[,'|',"1])&>/@[&0&((1 2$,:)&.>'';,'|')

이 골프의 주된 뿌리는 (];'--'&,"1@[,'|',"1])&>/입니다. 길이 (N-2) 및 (N-1)의 타일링 목록을 가져 와서 길이 (N-1) 및 N의 타일링 목록을 반환합니다. 이것은 선형 대수학 인 표준 피보나치 반복입니다. ];오른쪽 목록을 새 왼쪽으로 리턴합니다 (변경 사항 없음). '--'&,"1@[추가 --하면서, 왼쪽 목록에 타일을 '|',"1]추가 |우측 목록에 타일을, 그 함께 새로운 우측 목록입니다.

우리는 그것을 반복해서 여러 n번 반복하고 (즉 @[&0) 빈 타일링과 길이 1의 단일 타일링으로 시작합니다. 그런 다음 페어의 첫 번째를로 반환합니다 0{::. 즉, 0 회 실행하면 첫 번째 즉 빈 타일링 만 반환합니다. 우리가 그것을 실행하면 우리 nnand ( n+1) 쌍 까지 계산 하지만 후자를 무시합니다. 추가 작업이지만 적은 문자입니다.

이는 (1 2$,:)목록의 타일링을 쉽게 확장 할 수 있도록하기 위해 J가해야 할 일입니다. 왼쪽 시작 목록은 각 행의 길이가 0 인 2 행 문자 행렬의 1 개 항목 목록으로 만듭니다. 오른쪽 시작 목록은 동일하지만 행의 길이는 1이며로 채워집니다 |. 그런 다음 각 타일에 새 타일을 추가하고 두 타일 세트를 결합 할 때 행렬 목록을 추가합니다. J 호출 순위라는 개념의 간단한 응용 프로그램입니다. 본질적으로 인수의 차원을 조작하고 필요할 때 암시 적으로 반복됩니다.

   0{::(];'--'&,"1@[,'|',"1])&>/@[&0&((1 2$,:)&.>'';,'|')5
----|
----|

--|--
--|--

--|||
--|||

|----
|----

|--||
|--||

||--|
||--|

|||--
|||--

|||||
|||||

tryj.tk 에서 직접 사용해보십시오 .


1

파이썬 3:70 바이트

f=lambda n,s="\n":n>0and f(n-1,"|"+s)==f(n-2,"--"+s)or n or print(s*2)

s한 행의 도미노를 나타내는 가능한 모든 문자열을 반복적으로 작성합니다.이 문자열 은 복제되어 인쇄됩니다. s개행 문자로 시작 하면 빈 줄이 자동으로 나타납니다.

==에 대한 두 통화 사이는 f단지 두 함수 호출을 수행하는 것입니다. 이들은 보통 None인쇄하기 때문에 반환 ==되며에 대해 정의 된 소수의 연산자 중 하나입니다 None.

andS와 orS는 복제 할 권리 단락 행동 생산되어 ifs와 elseungolfed 코드들.

언 골프 드 :

def f(n,s="\n"):
 if n==-1:pass
 elif n==0: print(s*2)
 else: f(n-1,"|"+s);f(n-2,"--"+s)

1

레티 나 , 44 바이트

참고 : Retina는이 문제보다 젊습니다.

+`([-|]*)11(1*#)
$1|1$2$1--$2
1
|
.*?#
$0$0#

후행 줄 바꿈으로 단항 입력을받습니다.

각 줄은 자체 파일로 이동 #해야하며 파일 에서 줄 바꿈으로 변경되어야합니다. 이것은 실용적이지 않지만 -s플래그를 사용하여 하나의 파일처럼 코드를 실행하여 #마커를 유지 #하고 입력에서 줄 바꿈을 변경할 수도 있습니다. #원하는 경우 가독성을 위해 출력에서 ​​'를 다시 줄 바꿈으로 변경할 수 있습니다 . 예 :

> echo 1111# | retina -s fib_tile | tr # '\n'
||||
||||

||--
||--

|--|
|--|

--||
--||

----
----

방법:

  • 입력에서 시작하여 우리는 모든 줄을 두 개의 다른 것으로 1바꿉니다 . 하나는 첫 번째로 변경 한 |것이고 다른 하나는로 1변경되었습니다 --. 우리는 적어도 두 개의 줄을 가질 때까지 이것을한다 1.
  • 하나만 1남았을 때로 바꿨습니다 |.
  • 각 줄을 두 배로 늘리고 줄 바꿈을 추가하면 원하는 결과를 얻습니다.

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