Đường cong Hilbert của ASCII


23

Cho một nđầu ra số nguyên , nlần lặp thứ nhất của Đường cong Hilbert trong ASCII bằng cách sử dụng các ký tự _| .

Dưới đây là 4 lần lặp đầu tiên:

n=1
 _ 
| |

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

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

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

Làm rõ

  • Câu hỏi của tôi tương tự như Vẽ đường cong HilbertVẽ đường cong Hilbert bằng cách sử dụng dấu gạch chéo .
  • Việc chuyển đổi giữa các dấu gạch dưới ( _) và thanh dọc ( |) là u=2*v-1nơi ucó số lượng _s và vlà số |s.
  • Để duy trì tính nhất quán với bài viết gốc của tôi, đường cong phải bắt đầu và kết thúc ở phía dưới.
  • Bạn có thể có một chương trình đầy đủ hoặc một chức năng.
  • Đầu ra cho thiết bị xuất chuẩn (hoặc một cái gì đó tương tự).
  • Bạn có thể có các khoảng trắng ở đầu hoặc cuối, đầu ra chỉ cần xếp hàng sao cho giống như các ví dụ.
  • Đây là mã golf để câu trả lời ngắn nhất trong byte thắng.

3
Bạn có thể vui lòng bao gồm một định nghĩa về Đường cong Hilbert trong bài đăng của bạn và thông số kỹ thuật chính xác về cách thức phiên bản ASCII được xây dựng không?
Loovjo

@Bobas_Pett: Không phức tạp
kolmogorov


@Loovjo Tôi đã thêm vào một điểm về độ dài của dấu gạch dưới (_) và thanh dọc (|) trong phần "Làm rõ", nếu vẫn cần thêm thông tin hoặc định nghĩa nghiêm ngặt, vui lòng cho tôi biết.
Bobas_Pett

@shooqie tôi đã xóa thẻ
Bobas_Pett

Câu trả lời:


5

Befunge, 444 368 323 byte

&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
! "#%$
%$"#!
 !!##%
|||_
 _ __

Hãy thử trực tuyến!

Cách tiếp cận điển hình để vẽ Hilbert Curve là đi theo đường dẫn dưới dạng một chuỗi các nét và biến, hiển thị kết quả thành một bitmap hoặc một số vùng nhớ, sau đó viết ra kết xuất đó khi đường dẫn hoàn thành. Điều này chỉ không khả thi trong Befunge khi chúng ta chỉ có 2000 byte bộ nhớ để làm việc và bao gồm nguồn của chính chương trình.

Vì vậy, cách tiếp cận chúng tôi đã thực hiện ở đây là đưa ra một công thức cho chúng ta biết chính xác nhân vật nào sẽ xuất cho tọa độ x, y đã cho. Để hiểu cách thức hoạt động này, đó là dễ dàng nhất để bỏ qua render ASCII để bắt đầu, và chỉ cần nghĩ về đường cong như tạo thành từ các nhân vật hộp: , , , , , và .

Khi chúng ta nhìn vào đường cong như vậy, chúng ta có thể thấy ngay phía bên tay phải là một tấm gương chính xác của phía bên tay trái. Các ký tự bên phải có thể được xác định đơn giản bằng cách tra cứu đối tác của họ ở bên trái và phản ánh nó theo chiều ngang (nghĩa là sự xuất hiện của được hoán đổi, như là ).

Đường cong Hilbert cấp 3 cho thấy sự phản chiếu qua trục dọc

Sau đó nhìn vào góc dưới bên trái, một lần nữa chúng ta có thể thấy rằng nửa dưới là sự phản chiếu của nửa trên. Do đó, các ký tự ở phía dưới được xác định đơn giản bằng cách tra cứu đối tác của chúng ở trên và phản ánh nó theo chiều dọc (nghĩa là sự xuất hiện của được hoán đổi, như là ).

Đường cong Hilbert cấp 3 cho thấy sự phản chiếu qua trục ngang ở góc dưới bên trái

Nửa còn lại của góc này là một chút ít rõ ràng. Khối bên tay phải có thể được bắt nguồn từ một phản xạ dọc của khối theo đường chéo liền kề với nó.

Hilbert Đường cong cấp 3 cho thấy cách khối trên cùng bên phải của góc dưới bên trái có thể được bắt nguồn

Và khối bên tay trái có thể được bắt nguồn từ sự phản xạ dọc của khối ở góc trên cùng bên trái của đường cong đầy đủ.

Hilbert Đường cong cấp 3 cho thấy cách khối trên cùng bên trái của góc dưới bên trái có thể được bắt nguồn

Tại thời điểm này, tất cả những gì chúng ta còn lại là góc trên cùng bên trái, chỉ là một lần lặp khác của Hilbert Curve. Về lý thuyết, bây giờ chúng ta chỉ cần lặp lại quá trình một lần nữa, nhưng có một chút khó khăn - ở cấp độ này, nửa bên trái và bên phải của khối không phải là gương chính xác của nhau.

Vì vậy, ở bất cứ thứ gì ngoài cấp cao nhất, các ký tự góc dưới cùng cần được xử lý như một trường hợp đặc biệt, trong đó ký tự được phản ánh là ký tự được phản ánh là .

Hilbert Đường cong cấp 3 cho thấy cách khối trên cùng bên trái của góc dưới bên trái có thể được bắt nguồn

Nhưng khác với điều đó, chúng tôi thực sự có thể lặp lại quá trình này một cách đệ quy. Ở cấp độ cuối cùng, chúng tôi mã hóa ký tự trên cùng bên trái là và ký tự bên dưới là .

Trình tự các hình ảnh cho thấy các phần còn lại của đường cong được tạo ra như thế nào

Bây giờ chúng ta có một cách để xác định hình dạng của đường cong tại một tọa độ x, y cụ thể, làm thế nào để chúng ta dịch nó thành kết xuất ASCII? Đây thực sự chỉ là một ánh xạ đơn giản giúp chuyển từng ô có thể thành hai ký tự ASCII.

  • trở thành  _(không gian cộng với dấu gạch dưới)
  • trở thành   (hai không gian)
  • trở thành |_(thanh dọc cộng với dấu gạch dưới)
  • trở thành (thanh dọc cộng với không gian)
  • trở thành (một thanh dọc cộng với không gian)
  • trở thành __(hai dấu gạch dưới)

Ánh xạ này ban đầu không trực quan, nhưng bạn có thể thấy nó hoạt động như thế nào khi nhìn vào hai kết xuất tương ứng cạnh nhau.

Hilbert Curve cấp 2 biểu hiện như nghệ thuật ASCII và với các ký tự hộp

Và đó là cơ bản tất cả là có nó. Trên thực tế, việc thực hiện thuật toán này trong Befunge là một vấn đề khác, nhưng tôi sẽ để lại lời giải thích đó cho một lần khác.


2

C, 267 byte

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ãy thử trực tuyến!

h()sử dụng đệ quy để tạo các nét của đường cong hlibert. t()chỉ in ra ký tự nét nếu vị trí bút pbằng với vị trí đầu ra hiện tạiq .

Điều này là không hiệu quả nhưng đơn giản.

Nếu đường cong bắt đầu từ trên cùng bên trái, mã có thể được giảm xuống còn 256 byte.


Đề xuất puts("")thay vì putchar(10)"..."+l*8+d*2thay vì &"..."[l*8+d*2]n--?h(d+r...-r,n):0thay vìn--&&(h(d+r...-r,n))
trần nhà
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.