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;}//
Yakın zamanda GNU'nun işlev özellikleri ve en ilginç constructor
olanı, bu soruna daha önceki yaklaşımımda yaptığım şeyin daha dolambaçlı bir şekilde uygulanmasını sağlayan özellik.
Fikrin itişi, önceki ile aynıdır: Kodun hangi tetris bloğunun düzenlendiğini tanımlamak için bir dize oluşturun ve onu listede arayın. Bu, her biri dizeye bir karakter ekleyen işlevler çağırarak yapılır. Komplikasyon, fonksiyon sayısının değişkenlik gösterdiğini ve devam ettiğini gösteriyor.
Bir fonksiyonla tanımlamak, fonksiyonun girilmesinden attribute((constructor(x)))
önce çalışmasını sağlar main()
, isteğe bağlı x
önceliklidir (düşük ise daha önce çalıştırıldığı anlamına gelir). Bu, makro, bazı bildirimler ve çağıran zinciri düşürmemize izin veren işlev işaretçilerine olan ihtiyacı ortadan kaldırır.
Kullanımı __LINE__
öncelik öncelik düzeyleri beri 0-100 saklıdır, şüpheli olduğunu. Ancak, hatalarla sonuçlanmaz, sadece uyarılar ve golf oynarken bunlar çoktur, peki birkaç tane daha var mı?
Öncelikleri hiç kullanmamak için başka bir sütunun kesilmesine yardımcı olabilirdi, ancak yürütmenin sırası tanımlanmadı gibi görünüyor. (Bu durumda bunlar ters çevrilir, ancak diğer testler sonuçsuzdur.)
Burada L v2 örneği
Daha eski, daha taşınabilir, yaklaşım
#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;} //
En sevdiğim sorunlardan biri bu sitede çözdüm.
Her bloğun bir şekilde kendi koordinatlarını ilahi edeceğini düşünerek başladım. Satırlar kolaydır __LINE__
ve yatay olarak bitişik blokların sayısı, bir değişmez dizenin uzunluğu kullanılarak bulunabilir:
char*s=//char*s=//
" "" "
; ;
Elde edilen dizginin uzunluğunu alın ve uygun bir sayıya bölün ve genişliğe sahip olursunuz. Ne yazık ki, bloktan önceki herhangi bir boş alan bu yöntemle görünmez. Boşluk sadece gibi şeyler, çok nadiren dizeleri dışında anlamı vardır çünkü hala şüpheli dizeleri, çözüm olacaktır a+++b
vs. a+ ++b
. Kısaca böyle bir şey düşündüm, ama yararlı bir şey bulamadım. Diğer bir olasılık, tanımlayıcıların blokların birleştiği yerde birbirine "yapıştırılmış" olmalarını sağlamak olabilirdi:
A BA B
Bu hala ilginç bir çözüm bulabilseydi şaşırmam.
Sadeliği rağmen, bu blok parçasına dayanan string çözümünü bulmam biraz zaman aldı:
s=//
" \
";//
Parçanın yatay bir komşusu yoksa, ikinci satırdaki yeni satır ters eğik çizgiden kaçar, bir uzunluk 2 dizesi oluşturur. Bununla birlikte, bir komşusu varsa, ters eğik çizgi satırın başındaki tırnak işaretinden çıkacaktır. Bir sonraki bloğun 2 tanesi:
s=//s=//
" \" \
";//";//
Bu, 5 uzunluğundaki "\" "dizesini oluşturur.
Daha da önemlisi, bu aynı zamanda bloktan önce boş alanın algılanmasını sağlar:
s=//
" \
";//
Yine, newline kaçar ve boş bloğun sola boşluğunun boşluğu, 6 uzunluğundaki "" dizgisine dahil edilir.
Toplamda, üst üste endişelenmemiz gereken yedi farklı blok konfigürasyonu vardır ve hepsi benzersiz uzunluklarda dizgiler yapar:
2 " "
---
s=//
" \
";//
5 " \" "
---
s=//s=//
" \" \
";//";//
6 " "
---
s=//
" \
";//
9 " \" "
----
s=//s=//
" \" \
";//";//
10 " "
---
s=//
" \
";//
8 " \" \" "
---
s=//s=//s=//
" \" \" \
";//";//";//
11 " \" \" \" "
----
s=//s=//s=//s=//
" \" \" \" \
";//";//";//";//
Nihai bloklar elbette bu kadar kısa olmayacaktır, ancak prensip blok büyüklüğünden bağımsız olarak aynıdır. Bu aynı zamanda genişlik tespiti için ayrı bir mekanizmanın gerekli olmadığına da sahip. Sonuç dizisine bu dizginin uzunluğuna karşılık gelen bir karakter eklenerek, 19 konfigürasyonun her biri, tüm bloklar çalıştırıldıktan sonra sadece uygun bir listeyle karşılaştırılması gereken benzersiz bir dizge verir.
Bu bir kez sıralandığında, bir sonraki büyük problem her bir blok satırı "nasıl ziyaret edeceğimiz" idi. C de, fonksiyonlar dışında yapılabileceklerle sınırlıyız. Ayrıca main()
görünmemiz gerekiyor , ama sadece bir kez. İkincisi, bazıları tarafından kolayca elde edilir #define
, ancak sonraki blokların kodunun içine alınmasını istiyorsak main()
, son kapanış kıvrık braketinin ne zaman yerleştirileceğini bilme sorunu. Sonuçta, kaç blok satırın gerçekten kullanılacağını bilmiyoruz. Bu yüzden main()
statik olmak zorundayız ve bir şekilde dinamik olması gerekiyor.
Diğer blok satırları kendi kendine yetecekse, işlevler olmalıdır, ancak her bir işlevin kendine özgü bir adın olduğundan ve aynı zamanda çağrılabilecek kadar öngörülebilir olduğundan emin olmamız gerekir main()
. Ayrıca hangi işlevlerin çağrılacağını bilmek için bir mekanizmaya da ihtiyacımız var. Benzersiz isimler üretmek yardımcı makrolar tarafından çözülür:
#define M(a,b) a##b //
#define W(z,x)M(z,x) //
#define F W(f,__LINE__) //
#define A W(a,__LINE__) //
Arama F
, adı f ile başlayan ve satır numarasıyla biten bir tanımlayıcı oluşturacaktır. A
aynısını yapar, ancak çözüm işaretleyicisinin ikinci kısmı için kullanılan ve işlev işaretçileri olan bir ön ek ile. Bu tür dört göstericiyi ilan ediyoruz:
typedef(*T)();T a17,a36,a55,a74;
Bunlar global değişkenler olarak bildirildiğinden, uygun olarak NULL olarak ayarlanır. Daha sonra, her blok satır aşağıdaki kod parçasına sahip olacaktır:
F();T A=F;F()
Bu, önce bir işlevi bildirir, o işlevi işaret etmek için uygun işlev işaretçisini tanımlar (yalnızca bir kez globaller tanımlayabiliriz, ancak önceki bildirim NULL olarak başlatılsa bile) bir tanım olarak sayılmaz ve ardından fiili tanımlanır. işlevi. Bu main()
NULL olmayan herhangi bir fonksiyon göstergesini çağırmanıza izin verir (a17 asla NULL olmayacaktır):
a17(),a36&&a36(),a55&&a55(),a74&&a74()
Bunu yapmak r
daha sonra dizgiler tablosunda aranan dizgeyi oluşturacaktır ve bulunursa uygun harf çıktısı alınacaktır .
Geriye kalan tek hile, belirsizlikten kaçınılması veya örtüşen dizgilerin birleştirilmesiyle eşleşecek dizelerin listesinin kısaltılmasıdır.
Burada L v2 örneği