Haskell , 1080 1033 byte
;
f=
g
ij=f
a =hi
hi = g
hij= ij
g ' ' =0
g '"' =0;
g '$' =0;
g '&' =0-0
g '(' =0-0-0
g '*' =0-0-0;
g ',' =0-0-0;
g '.' =0-0-0-0
g '0' =0-0-0-0-0
g '2' =0-0-0-0-0;
g '4' =0-0-0-0-0;
g '6' =0; g '8' =0
g ':' =0; g '<' =0-0
g '>' =0; g '@' =0-0;
g 'B' =0; g 'D' =0-0;
g 'F' =0; g 'H' =0-0-0
g 'J' =0; g 'L' =0-0-0-0
g 'N' =0; g 'P' =0-0-0-0;
g 'R' =0; g 'T' =0-0-0-0;
g 'V' =0; g 'X' =0-0-0-0-0
g 'Z' =0; g '^' =0; g '`' =0
g 'b' =0; g 'd' =0; g 'f' =0;
g 'h' =0; g 'j' =0; g 'l' =0;
g 'n' =0; g 'p' =0; g 'r' =0-0
g 't' =0; g 'v' =0; g 'x' =0-0-0
g 'z' =0; g '\92' =0-0; g '|' =0;
g '~' =0; g y = 1 ;z=0; i(-0)z=z;
i m('\10':y ) ="y"; ; ; ; ; ; ; ;
i m(mnmnmnmnm:y ) = i(m - 1 ) y ; ;
i k m ="y"; ; k i [ ] =01<1010101010;
k m('\10':y ) = k(m + 1 )(i m y ) ; ;
k m y =01>10; m o = k 1$'\10':o ; ; ;
o i('\10':y ) = o i y ; ; ; ; ; ; ; ; ;
o i(k:y )|g k<i = o(1 - i ) y ; ; ; ; ; ;
o i(k:y )|g k>i = o(1 - i ) y ; ; ; ; ; ;
o i [ ] =01<10; o i y =01>10;v=01>10101010
s y|o 1 y = m y|o(-0) y = m y ; s y =v; ; ;
Hãy thử trực tuyến!
Giải trình
Đây là nhiệm vụ khá thú vị đối với Haskell.
Ngang bằng
Để bắt đầu, chúng ta cần một số cách xác định xem một ký tự có điểm mã chẵn hay lẻ. Cách thông thường mà người ta có thể làm là lấy điểm mã và sửa đổi nó bằng 2. Tuy nhiên, như người ta có thể biết, việc lấy điểm mã của một ký tự yêu cầu nhập, do hạn chế nguồn có nghĩa là không thể đã sử dụng. Một Haskeller có kinh nghiệm hơn sẽ nghĩ sử dụng đệ quy. Char
Là một phần của kiểu chữ Enum
để chúng ta có thể có được những người tiền nhiệm và người kế nhiệm của họ. Tuy nhiên pred
và succ
cả hai đều không sử dụng được vì chúng không xen kẽ byte chẵn lẻ.
Vì vậy, điều này khiến chúng tôi khá bế tắc, chúng tôi gần như không thể thực hiện bất kỳ thao tác nào với ký tự. Giải pháp cho vấn đề này là mã hóa mọi thứ. Chúng ta có thể đại diện (hầu hết) ngay cả các ký tự là chữ, tỷ lệ cược chúng ta gặp rắc rối vì '
là số lẻ nên không thể ở bên cạnh char khiến cho nghĩa đen không thể diễn tả hầu hết các ký tự lẻ. Vì vậy, chúng tôi cứng mã tất cả các byte chẵn, và sau đó thêm một bắt tất cả cho các byte lẻ ở cuối.
Vấn đề Byte
Bạn có thể nhận thấy rằng có một số byte chẵn mà chữ không thể được tạo ra bằng cách gói nó trong dấu ngoặc đơn. Họ là những người không thể in, dòng mới và \
. Chúng tôi không cần phải lo lắng về việc không thể in được miễn là chúng tôi không sử dụng bất kỳ ứng dụng nào trong số chúng tôi không cần xác minh. Trong thực tế, chúng ta vẫn có thể sử dụng những thứ không thể in được, như tab, cuối cùng tôi không cần. Dòng mới có thể bị bỏ qua một cách khó khăn bởi vì dù sao nó cũng sẽ bị cắt khỏi chương trình. (Chúng tôi có thể bao gồm dòng mới, vì đó là điểm mã khá thuận tiện, nhưng chúng tôi không cần). Lá này \
, hiện \
có mã số 92, thuận tiện là một số lẻ theo sau là một số chẵn, do đó, \92
xen kẽ giữa evens và tỷ lệ cược theo nghĩa đen'\92'
là hoàn toàn hợp lệ. Sau này khi chúng tôi cần đại diện cho dòng mới, chúng tôi sẽ nhận thấy rằng nó may mắn có cùng tài sản này '\10'
.
Vấn đề khoảng cách
Bây giờ để bắt đầu viết mã thực tế, chúng ta cần có thể đặt một số lượng lớn các ký tự trên một dòng. Để làm điều này, tôi đã viết nắp:
;
f=
g
ij=f
a =hi
hi = g
hij= ij
Mũ không làm bất cứ điều gì ngoại trừ Haskell hợp lệ. Ban đầu tôi đã hy vọng đưa ra các định nghĩa sẽ giúp chúng tôi viết mã sau, nhưng không được. Cũng có những cách dễ dàng hơn để tạo giới hạn, ví dụ như khoảng trắng và dấu chấm phẩy, nhưng chúng không lưu byte theo cách này vì vậy tôi không bận tâm thay đổi nó.
Bộ giải mã
Vì vậy, bây giờ tôi có đủ không gian trên một dòng, tôi bắt đầu mã hóa giá trị. Điều này chủ yếu là khá nhàm chán, nhưng có một vài điều quan tâm. Đối với một lần, các dòng bắt đầu dài hơn nữa, chúng ta có thể sử dụng ;
để đặt nhiều khai báo trên một dòng, giúp chúng ta tiết kiệm được rất nhiều byte.
Thứ hai là vì chúng ta không thể luôn bắt đầu một dòng với g
thường xuyên nên chúng ta phải thụt dòng một chút. Bây giờ Haskell thực sự quan tâm đến vết lõm, vì vậy nó sẽ phàn nàn về điều này. Tuy nhiên, nếu dòng cuối cùng trước khi dòng thụt lề kết thúc bằng dấu chấm phẩy thì nó sẽ cho phép nó. Tại sao? Tôi không phải là người mờ nhạt nhất, nhưng nó hoạt động. Vì vậy, chúng ta chỉ cần nhớ đặt dấu chấm phẩy ở cuối dòng.
Khối xây dựng chức năng
Một khi trình mã hóa cứng được thực hiện, nó sẽ thuận buồm xuôi gió đến cuối chương trình. Chúng ta cần xây dựng một vài chức năng đơn giản. Đầu tiên tôi xây dựng một phiên bản drop
, được gọi là i
. i
khác với drop
ở chỗ nếu chúng ta cố gắng thả qua phần cuối của chuỗi thì nó chỉ trả về "y"
. i
khác với thả cũng ở chỗ nếu nó cố gắng bỏ dòng mới thì nó sẽ trả về "y"
, Chúng sẽ hữu ích vì sau này khi chúng tôi xác minh rằng chương trình là một hình tam giác, điều này sẽ cho phép chúng tôi quay lại False
khi dòng cuối cùng không hoàn thành hoặc khi nào một dòng kết thúc sớm.
k
k
nSSTrue
nk
n + 1False
Sau đó chúng tôi thực hiện một bí danh cho k
, m
. m
chỉ k
với 1
trong đối số thứ nhất và một dòng mới được thêm vào đối số thứ hai.
Tiếp theo chúng ta có o
. o
lấy một số và một chuỗi. Nó xác định nếu các byte chuỗi (bỏ qua dòng mới) thay thế theo chẵn lẻ (sử dụng của chúng tôi g
) bắt đầu bằng số đầu vào.
Cuối cùng, chúng ta có s
chạy o
với cả hai 1
và 0
, nếu thành công, nó sẽ làm theo m
. Nếu thất bại cả hai nó chỉ trở về False
. Đây là chức năng chúng tôi muốn. Nó xác định rằng đầu vào là hình tam giác và xen kẽ.