C (gcc) , 26x20 = 520 25x19 = 475 23x17 = 391
#ifndef M //
#define M(a,b)a##b //
#define W(z,x)M(z,x) //
char*s,*S[]={"!!!!c",//
"8M !7! M8 878","77",//
"7!!MO887","788OM!!7"//
,"N7!78","7N87!"},r[5//
],*p=r;i=7;main(){for//
(;i--;)strstr(S[i],r)//
&&putchar("ITOJLSZ"[i//
]);} //
#endif //
__attribute__(( //
constructor(__LINE__)//
))W(f,__LINE__)(){s= //
" \
";*p++=strlen(s)+12;}//
Gần đây tôi đã được thông báo về các thuộc tính chức năng của GNU và điều thú vị nhất là constructor
thuộc tính này, cho phép thực hiện ngắn gọn hơn những gì tôi đang làm theo cách vòng vo hơn trong cách tiếp cận vấn đề trước đây của tôi.
Lực đẩy của ý tưởng vẫn giống như trước: Xây dựng một chuỗi và tìm kiếm nó trong một danh sách để xác định khối tetris nào mà mã được đặt ra là. Điều này được thực hiện bằng cách gọi các hàm, mỗi hàm thêm một ký tự vào chuỗi. Sự phức tạp đã và vẫn là số lượng các chức năng khác nhau.
Xác định một chức năng attribute((constructor(x)))
làm cho nó để chức năng được chạy trước main()
được nhập vào, với tùy chọn x
là ưu tiên (thấp hơn có nghĩa là nó được chạy trước đó). Điều này loại bỏ sự cần thiết của các con trỏ hàm, cho phép chúng ta bỏ một macro, một số khai báo và chuỗi gọi.
Sử dụng __LINE__
cho ưu tiên là iffy, vì mức độ ưu tiên 0-100 được bảo lưu. Tuy nhiên, nó không dẫn đến lỗi, chỉ có cảnh báo và những thứ đó rất phong phú khi chơi golf, vậy còn một vài điều nữa?
Nó sẽ giúp loại bỏ một cột khác để không sử dụng các ưu tiên, nhưng thứ tự thực hiện dường như không được xác định. (Chúng được đảo ngược trong trường hợp này, nhưng các xét nghiệm khác là không kết luận.)
Ví dụ về L v2 tại đây
Cũ hơn, di động hơn, cách tiếp cận
#ifndef M //
#define M(a,b) a##b //
#define W(z,x)M(z,x) //
#define F W(f,__LINE__)//
#define A W(a,__LINE__)//
char r[5],*S[]={"####k"//
,";<<US##;",";##SU<<;",//
";;",";T<;#","<S #;# S"//
"< <;<","T;#;<"},*s,*p=//
r;i;typedef(*T)();T a17//
,a36,a55,a74;main(){for//
(a17(),a36&&a36(),a55&&//
a55(),a74&&a74();i--;) //
strstr(S[i],r)&&putchar//
("ILJOZTS"[i]);}i=7; //
#endif //
F();T A=F;F(){s= //
" \
";*p++=strlen(s)+12;} //
Một trong những vấn đề yêu thích của tôi đã được giải quyết trên trang web này.
Tôi bắt đầu bằng cách hình dung mỗi khối sẽ thần thánh tọa độ của nó bằng cách nào đó. Các hàng dễ dàng với __LINE__
và có thể tìm thấy số khối liền kề theo chiều ngang bằng cách sử dụng độ dài của một chuỗi bằng chữ, như vậy:
char*s=//char*s=//
" "" "
; ;
Lấy độ dài của chuỗi kết quả và chia cho một số thích hợp và bạn có chiều rộng. Đáng buồn thay, bất kỳ không gian trống trước khối là vô hình bằng phương pháp này. Tôi vẫn nghi ngờ dây sẽ là giải pháp, vì khoảng trắng chỉ có ý nghĩa bên ngoài của dây rất hiếm khi, trong những thứ như a+++b
vs a+ ++b
. Tôi đã xem xét ngắn gọn một cái gì đó như thế, nhưng không thể đưa ra bất cứ điều gì hữu ích. Một khả năng khác có thể là để cho các định danh được "dán" lại với nhau nơi các khối gặp nhau:
A BA B
Tôi sẽ không ngạc nhiên nếu điều này vẫn có thể tạo ra một giải pháp thú vị.
Mặc dù đơn giản, tôi đã mất khá nhiều thời gian để tìm giải pháp chuỗi, dựa trên đoạn khối này:
s=//
" \
";//
Nếu đoạn không có hàng xóm nằm ngang, dòng mới trên dòng thứ hai được thoát bằng dấu gạch chéo ngược, tạo ra một chuỗi có độ dài 2. Tuy nhiên, nếu nó có hàng xóm, thì dấu gạch chéo ngược sẽ thoát khỏi dấu quotion ở đầu dòng 2 khối tiếp theo:
s=//s=//
" \" \
";//";//
Điều này sẽ tạo ra chuỗi "\" "có độ dài 5.
Quan trọng hơn, điều này cũng cho phép phát hiện không gian trống trước khối:
s=//
" \
";//
Một lần nữa, dòng mới được thoát và khoảng trắng của khối trống ở bên trái được bao gồm trong chuỗi kết quả "" có độ dài 6.
Tổng cộng có bảy cấu hình khác nhau của các khối trên một hàng mà chúng ta cần phải lo lắng và tất cả chúng đều tạo ra các chuỗi có độ dài duy nhất:
2 " "
---
s=//
" \
";//
5 " \" "
---
s=//s=//
" \" \
";//";//
6 " "
---
s=//
" \
";//
9 " \" "
----
s=//s=//
" \" \
";//";//
10 " "
---
s=//
" \
";//
8 " \" \" "
---
s=//s=//s=//
" \" \" \
";//";//";//
11 " \" \" \" "
----
s=//s=//s=//s=//
" \" \" \" \
";//";//";//";//
Các khối cuối cùng tất nhiên sẽ không có chiều dài ngắn như vậy, nhưng nguyên tắc là như nhau bất kể kích thước khối. Điều này cũng có phần thưởng là một cơ chế riêng biệt để phát hiện chiều rộng là không cần thiết. Bằng cách thêm một ký tự tương ứng với độ dài của chuỗi này vào chuỗi kết quả, mỗi cấu hình trong số 19 cấu hình sẽ tạo ra một chuỗi duy nhất, chỉ cần so sánh với một danh sách phù hợp khi tất cả các khối đã được chạy.
Khi điều này đã được sắp xếp, vấn đề lớn tiếp theo là làm thế nào để "truy cập" từng hàng khối. Trong C, chúng tôi rất hạn chế những gì có thể được thực hiện bên ngoài các chức năng. Chúng tôi cũng cần main()
phải xuất hiện, nhưng chỉ một lần. Cái sau có thể dễ dàng đạt được bởi một số #define
s, nhưng nếu chúng ta muốn mã của các khối tiếp theo nằm bên trong main()
, thì vấn đề là làm thế nào để biết khi nào nên đặt dấu ngoặc nhọn đóng cuối cùng. Rốt cuộc, chúng ta không biết có bao nhiêu hàng khối sẽ thực sự được sử dụng. Vì vậy, chúng ta cần phải có main()
tĩnh và bằng cách nào đó phần còn lại để được năng động.
Nếu các hàng khối khác phải khép kín, chúng cần phải là các hàm, nhưng chúng ta cần đảm bảo mỗi hàm có một tên duy nhất, trong khi cũng có thể dự đoán đủ để có thể gọi được main()
. Chúng ta cũng cần một cơ chế để biết chức năng nào thực sự được gọi. Tạo tên duy nhất được giải quyết bằng macro trợ giúp:
#define M(a,b) a##b //
#define W(z,x)M(z,x) //
#define F W(f,__LINE__) //
#define A W(a,__LINE__) //
Gọi F
sẽ tạo một định danh có tên bắt đầu bằng một f và kết thúc bằng số dòng. A
thực hiện tương tự nhưng với tiền tố là, được sử dụng cho phần thứ hai của giải pháp, đó là các con trỏ hàm. Chúng tôi tuyên bố bốn con trỏ như vậy:
typedef(*T)();T a17,a36,a55,a74;
Vì chúng được khai báo là biến toàn cục, nên chúng được đặt thuận tiện thành NULL. Sau đó, mỗi hàng khối sẽ có đoạn mã sau:
F();T A=F;F()
Điều này trước tiên sẽ khai báo một hàm, xác định con trỏ hàm thích hợp để trỏ đến hàm đó (chúng ta chỉ có thể xác định toàn cục một lần, nhưng khai báo trước đó không được tính là một định nghĩa, ngay cả khi nó đã khởi tạo cho NULL), sau đó xác định thực tế chức năng. Điều này cho phép main()
gọi bất kỳ con trỏ hàm nào không phải là NULL (a17 sẽ không bao giờ là NULL):
a17(),a36&&a36(),a55&&a55(),a74&&a74()
Làm như vậy sẽ xây dựng chuỗi r
, sau đó được tìm kiếm trong bảng chuỗi và nếu tìm thấy, chữ cái thích hợp là đầu ra.
Thủ thuật duy nhất còn lại là danh sách các chuỗi cần so sánh được rút ngắn bất cứ khi nào có thể tránh được sự mơ hồ hoặc các chuỗi chồng chéo có thể bị xáo trộn.
Ví dụ về L v2 tại đây