ASCII 힐버트 커브


23

정수 감안할 때 n출력에게 n의 일 반복 힐버트 곡선 문자를 사용하여 ASCII에 _|.

처음 4 개의 반복은 다음과 같습니다.

n=1
 _ 
| |

n=2
 _   _ 
| |_| |
|_   _|
 _| |_

n=3
 _   _   _   _ 
| |_| | | |_| |
|_   _| |_   _|
 _| |_____| |_ 
|  ___   ___  |
|_|  _| |_  |_|
 _  |_   _|  _ 
| |___| |___| |

n=4
 _   _   _   _   _   _   _   _ 
| |_| | | |_| | | |_| | | |_| |
|_   _| |_   _| |_   _| |_   _|
 _| |_____| |_   _| |_____| |_ 
|  ___   ___  | |  ___   ___  |
|_|  _| |_  |_| |_|  _| |_  |_|
 _  |_   _|  _   _  |_   _|  _ 
| |___| |___| |_| |___| |___| |
|_   ___   ___   ___   ___   _|
 _| |_  |_|  _| |_  |_|  _| |_ 
|  _  |  _  |_   _|  _  |  _  |
|_| |_| | |___| |___| | |_| |_|
 _   _  |  ___   ___  |  _   _ 
| |_| | |_|  _| |_  |_| | |_| |
|_   _|  _  |_   _|  _  |_   _|
 _| |___| |___| |___| |___| |_ 

설명

  • 내 질문은 슬래시를 사용하여 Hilbert 곡선 그리기Hilbert 곡선 그리기 와 유사합니다 .
  • 밑줄 (사이의 전환 _)와 수직 막대 ( |) 인 u=2*v-1u의 번호 _들과 v의 번호 |들.
  • 원래 게시물과의 일관성을 유지하려면 곡선이 맨 아래에서 시작하고 끝나야합니다.
  • 당신은 전체 프로그램이나 기능을 가질 수 있습니다.
  • stdout (또는 비슷한 것)으로 출력하십시오.
  • 선행 또는 후행 공백을 가질 수 있으며 출력은 예제처럼 보이도록 정렬해야합니다.
  • 이것은 코드 골프이므로 바이트 단위의 최단 답변이 승리합니다.

3
게시 할 때 힐버트 곡선의 정의와 ASCII 버전 구성 방법에 대한 정확한 사양을 포함시켜 주시겠습니까?
Loovjo

@Bobas_Pett : kolmogorov- 복잡성이
shooqie


@Loovjo "설명"아래에 밑줄 (_)과 세로 막대 (|)의 길이에 대한 정보를 추가했습니다. 자세한 정보 나 엄격한 정의가 여전히 필요한 경우 알려주십시오.
Bobas_Pett

@shooqie 내가 태그를 제거
Bobas_Pett

답변:


5

Befunge, 444 368 323 바이트

&1>\1-:v
0v^*2\<_$00p>
_>:10p\:20pv^_@#-*2g00:+1,+55$
^!-<v*2g000<>$#<0>>-\:v
g2*^>>10g20g+v \ ^*84g_$:88+g,89+g,\1+:00
v#*!-1g02!g01_4^2_
>::00g2*-!\1-:10g-\20g-++>v
87+#^\#p01#<<v!`g01/2\+76:_
vv1-^#1-g01:\_$:2/20g`!
_ 2/^>:10g#vv#`g02/4*3:\+77
v>0p^^/2:/2_
<^2-1-g02</2`#*3:
0g+10p2*:^*3_1
! "#%$
%$"#!
 !!##%
|||_
 _ __

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

힐버트 커브를 그리는 일반적인 방법은 경로를 일련의 획과 회전으로 따라가 비트 맵 또는 메모리 영역에 결과를 렌더링 한 다음 경로가 완료되면 해당 렌더링을 작성하는 것입니다. 작업 할 메모리가 2000 바이트에 불과한 경우 Befunge에서는 실행 불가능하며 여기에는 프로그램 자체의 소스가 포함됩니다.

따라서 우리가 취한 접근법은 주어진 x, y 좌표에 대해 어떤 문자를 출력 할 것인지 정확하게 알려주는 공식을 제시하는 것입니다. 그것은 시작하는 ASCII 렌더링을 무시하는 가장 쉬운 방법이 작품을 이해하고, 단지 상자 문자로 구성으로 곡선의 생각 : , , , , ,와 .

이 곡선을 보면 오른쪽이 왼쪽의 정확한 거울이라는 것을 즉시 알 수 있습니다. 오른쪽에 문자가 간단히 왼쪽에있는 파트너를 찾고 수평으로 반영하여 결정할 수있다 (즉, 발생 교환하는 등이다 ).

수직축에 걸친 반사를 나타내는 레벨 3 힐버트 커브

그런 다음 왼쪽 하단 모서리를 보면 아래쪽 절반이 위쪽 절반을 반영한다는 것을 알 수 있습니다. 따라서 바닥에 문자가 단순히 위의 파트너를 찾고, 수직을 반영하여 결정된다 (즉, 발생 교환하는 등이다 ).

왼쪽 하단에서 수평 축을 가로 질러 반사를 나타내는 레벨 3 힐버트 커브

이 코너의 나머지 절반은 조금 덜 분명합니다. 우측 블록은 블록에 대각선으로 인접한 블록의 수직 반사로부터 도출 될 수있다.

왼쪽 하단 모서리의 오른쪽 상단 블록을 파생시키는 방법을 보여주는 레벨 3 힐버트 곡선

그리고 왼쪽 블록은 전체 곡선의 가장 왼쪽 상단에있는 블록의 수직 반사에서 파생 될 수 있습니다.

왼쪽 하단 모서리의 왼쪽 상단 블록을 파생시키는 방법을 보여주는 레벨 3 힐버트 곡선

이 시점에서, 우리가 남은 것은 왼쪽 상단 코너인데, 이것은 또 하나의 힐버트 커브 일뿐입니다. 이론적으로 우리는 이제 프로세스를 다시 반복해야하지만 약간의 캐치가 있습니다.이 수준에서는 블록의 왼쪽과 오른쪽 절반이 서로 정확히 거울이 아닙니다.

따라서 최상위 이외에서 오른쪽 골대 문자가 특별한 경우로 취급 할 필요가 문자로 반영 하고, 문자로 반영된다 .

왼쪽 하단 모서리의 왼쪽 상단 블록을 파생시키는 방법을 보여주는 레벨 3 힐버트 곡선

그러나 그 외에는이 과정을 재귀 적으로 반복 할 수 있습니다. 마지막 레벨에서 왼쪽 상단 문자는로 , 그 아래 문자는로 하드 코딩합니다 .

곡선의 나머지 부분이 어떻게 도출되는지 보여주는 이미지 시퀀스

이제 특정 x, y 좌표에서 곡선의 모양을 결정하는 방법이 생겼습니다. ASCII 렌더링으로 어떻게 변환합니까? 실제로는 가능한 각 타일을 두 개의 ASCII 문자로 변환하는 간단한 매핑입니다.

  • 가된다  _(공간 플러스 밑줄)
  • 된다   (두 대)
  • 진다 |_(수직 바 플러스 밑줄)
  • 진다 (수직 바 플러스 공간)
  • 이된다 (다시 수직 막대 플러스 공간)
  • 된다 __(두 밑줄)

이 매핑은 처음에는 직관적이지 않지만 두 개의 해당 렌더링을 나란히 볼 때 어떻게 작동하는지 확인할 수 있습니다.

ASCII 아트로 그리고 상자 문자로 렌더링 된 레벨 2 힐버트 커브

그리고 그것이 기본적으로 전부입니다. 실제로 Befunge에서이 알고리즘을 구현하는 것은 또 다른 문제이지만 다른 설명은 남겨 두겠습니다.


2

C, 267 바이트

const n=4,s=1<<n,a[]={1,-s,-1,s};l,p,q;
t(d){d&=3;p-q||printf("%.2s",&"__|      _|       |___ _|_| | | "[l*8+d*2]);p+=a[l=d];}
h(d,r,n){n--&&(h(d+r,-r,n),t(d+r),h(d,r,n),t(d),h(d,r,n),t(d-r),h(d-r,-r,n));}
main(){for(;p=s*s-s,l=1,q<s*s;++q%s||putchar(10))h(0,1,n),t(3);}

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

h()재귀를 사용하여 hlibert 곡선의 획을 생성합니다. t()펜 위치 p가 현재 출력 위치와 같은 경우에만 스트로크 문자를 인쇄합니다 q.

이것은 비효율적이지만 간단합니다.

곡선이 왼쪽 상단에서 시작하면 코드를 256 바이트로 줄일 수 있습니다.


puts("")대신에 putchar(10)그리고 "..."+l*8+d*2대신에 &"..."[l*8+d*2]그리고 n--?h(d+r...-r,n):0대신에 제안n--&&(h(d+r...-r,n))
ceilingcat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.