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;}//
J'ai récemment été informé des attributs de fonction de GNU et, plus intéressant encore, du constructor
attribut, ce qui permet une mise en œuvre plus concise de ce que je faisais de manière plus détournée dans mon approche précédente de ce problème.
L’idée de base est la même que précédemment: créez une chaîne et recherchez-la dans une liste pour identifier le bloc de tétris dans lequel le code est présenté. Ceci est fait en appelant des fonctions, chacune ajoutant un caractère à la chaîne. La complication était et reste que le nombre de fonctions varie.
Définir une fonction avec attribute((constructor(x)))
permet d’exécuter la fonction avant de la main()
saisir, avec le paramètre optionnelx
étant la priorité (plus faible signifie qu'elle est exécutée plus tôt). Cela supprime le besoin de pointeurs de fonction, ce qui nous permet de supprimer une macro, certaines déclarations et la chaîne d'appel.
En utilisant __LINE__
de la priorité est incertaine, car les niveaux de priorité 0 à 100 sont réservés. Cependant, cela n'entraîne pas d'erreurs, mais uniquement des avertissements, et ceux-ci sont nombreux lorsque vous jouez au golf.
Il aurait été utile de ne pas utiliser de priorités du tout dans une autre colonne, mais l'ordre d'exécution ne semble pas être défini. (Ils sont inversés dans ce cas, mais les autres tests ne sont pas concluants.)
Exemple de L v2 ici
Une approche plus ancienne et plus portable
#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;} //
Un de mes problèmes préférés que j'ai résolus sur ce site.
J'ai commencé par imaginer que chaque bloc devinerait ses propres coordonnées. Les rangées sont faciles avec __LINE__
, et le nombre de blocs adjacents horizontalement pourrait être trouvé en utilisant la longueur d'un littéral de chaîne, comme ceci:
char*s=//char*s=//
" "" "
; ;
Prenez la longueur de la chaîne résultante et divisez-la par un nombre approprié et vous aurez la largeur. Malheureusement, tout espace vide avant le bloc est invisible grâce à cette méthode. Je cordes encore suspectées serait la solution, puisque les espaces n'a de sens en dehors des cordes très rarement, dans des choses comme a+++b
contre a+ ++b
. J'ai brièvement envisagé quelque chose comme ça, mais je n'ai rien trouvé d'utile. Une autre possibilité aurait été de laisser les identifiants être "collés" lorsque les blocs se rencontreraient:
A BA B
Je ne serais pas surpris si cela pouvait encore constituer une solution intéressante.
Malgré sa simplicité, il m'a fallu un certain temps pour trouver la solution de chaîne basée sur ce fragment de bloc:
s=//
" \
";//
Si le fragment n'a pas de voisins horizontaux, le retour à la ligne de la deuxième ligne est échappé par la barre oblique inverse, créant ainsi une chaîne de longueur 2. Si, toutefois, il a un voisin, la barre oblique inverse échappera à la marque de mouvement au début de la ligne. 2 du bloc suivant:
s=//s=//
" \" \
";//";//
Cela créera la chaîne "\" "de longueur 5.
Plus important encore, cela permet également de détecter l’espace vide avant le bloc:
s=//
" \
";//
Encore une fois, la nouvelle ligne est échappée et les espaces du bloc vide à gauche sont inclus dans la chaîne résultante "" de longueur 6.
Au total, il y a sept configurations différentes de blocs sur une ligne dont nous devons nous préoccuper, et toutes créent des chaînes de longueurs uniques:
2 " "
---
s=//
" \
";//
5 " \" "
---
s=//s=//
" \" \
";//";//
6 " "
---
s=//
" \
";//
9 " \" "
----
s=//s=//
" \" \
";//";//
10 " "
---
s=//
" \
";//
8 " \" \" "
---
s=//s=//s=//
" \" \" \
";//";//";//
11 " \" \" \" "
----
s=//s=//s=//s=//
" \" \" \" \
";//";//";//";//
Les derniers blocs n'auront bien sûr pas une longueur aussi courte, mais le principe est le même quelle que soit la taille du bloc. Cela a également l'avantage qu'un mécanisme séparé pour détecter la largeur n'est pas nécessaire. En ajoutant un caractère correspondant à la longueur de cette chaîne à une chaîne de résultats, chacune des 19 configurations génère une chaîne unique, qu'il suffit de comparer à une liste appropriée une fois que tous les blocs ont été exécutés.
Une fois cela réglé, le problème suivant était de savoir comment "visiter" chaque rangée de blocs. En C, nous sommes très limités à ce qui peut être fait en dehors des fonctions. Nous devons également main()
comparaître, mais une seule fois. Ce dernier est facilement réalisé par certains #define
s, mais si nous voulons que le code des blocs suivants soit à l’intérieur de main()
, le problème est de savoir quand mettre l’accolade de fermeture finale. Après tout, nous ne savons pas combien de rangées de blocs seront réellement utilisées. Nous avons donc besoin d'avoirmain()
statique et le reste pour être dynamique.
Si les autres lignes de bloc doivent être autonomes, elles doivent être des fonctions, mais nous devons nous assurer que chaque fonction a un nom unique, tout en étant suffisamment prévisible pour pouvoir être appelé main()
. Nous avons également besoin d'un mécanisme pour savoir quelles fonctions sont réellement appelées. La génération de noms uniques est résolue par les macros helper:
#define M(a,b) a##b //
#define W(z,x)M(z,x) //
#define F W(f,__LINE__) //
#define A W(a,__LINE__) //
L'appel F
créera un identifiant dont le nom commence par un f et se termine par le numéro de ligne. A
fait de même, mais avec un préfixe as, utilisé pour la deuxième partie de la solution, à savoir les pointeurs de fonction. Nous déclarons quatre de ces pointeurs:
typedef(*T)();T a17,a36,a55,a74;
Comme elles sont déclarées en tant que variables globales, elles ont la valeur NULL. Plus tard, chaque bloc-ligne aura le code suivant:
F();T A=F;F()
Cela va d'abord déclarer une fonction, définir le pointeur de fonction approprié pour pointer sur cette fonction (nous ne pouvons définir qu'une seule fois les globales, mais la déclaration précédente ne comptait pas comme une définition, même si elle était initialisée à NULL), puis définissait la valeur réelle. une fonction. Cela permet main()
d’appeler n’importe quel pointeur de fonction non NULL (a17 ne sera jamais NULL):
a17(),a36&&a36(),a55&&a55(),a74&&a74()
Cela va construire la chaîne r
, qui sera ensuite recherchée dans la table des chaînes et, si elle est trouvée, la lettre appropriée est générée.
La seule astuce restante consiste à raccourcir la liste des chaînes à comparer, chaque fois que l’ambiguïté peut être évitée, ou à fusionner les chaînes qui se chevauchent.
Exemple de L v2 ici