Cette question est inspirée de la couverture du livre "Godel, Escher, Bach":
Le défi ici est d'écrire une fonction qui indique si trois lettres données peuvent produire une sculpture 3D qui peut être lue sur trois côtés.
Pour cet exercice, les seules lettres que vous pouvez utiliser sont 26 bitmaps 5px * 5px:
Ou en binaire (A à Z):
01110 11110 01111 11110 11111 11111 11111 10001 11111 11111 10001 10000 10001 10001 01110 11110 01110 11110 01111 11111 10001 10001 10001 10001 10001 11111
10001 10001 10000 10001 10000 10000 10000 10001 00100 00100 10010 10000 11011 11001 10001 10001 10001 10001 10000 00100 10001 10001 10001 01010 01010 00010
10001 11110 10000 10001 11100 11110 10011 11111 00100 00100 11100 10000 10101 10101 10001 10001 10001 11111 01110 00100 10001 01010 10001 00100 00100 00100
11111 10001 10000 10001 10000 10000 10001 10001 00100 10100 10010 10000 10001 10011 10001 11110 10011 10010 00001 00100 10001 01010 10101 01010 00100 01000
10001 11110 01111 11110 11111 10000 11111 10001 11111 11100 10001 11111 10001 10001 01110 10000 01111 10001 11110 00100 01110 00100 01010 10001 00100 11111
La sculpture est formée de trois lettres dans l'ordre suivant:
- lettre un sur le dessus,
- lettre deux à gauche
- lettre trois à droite
- le bas de la lettre un est lié au haut de la lettre deux.
Exemple:
Votre fonction peut accepter en entrée trois lettres majuscules (trois caractères ou trois chaînes d'une lettre) et produire un booléen (vrai / faux ou 0/1) indiquant si la sculpture correspondante peut exister.
Exemple:
f("B","E","G") // true (because if you "sculpt out" B on top + E on the left + G on the right, and watch the three sides of the sculpture, you'll see exactly B, E and G as they are defined)
f("B","G","E") // false (because if you "sculpt out" B on top + G on the left + E on the right, and watch the three sides of the sculpture, you won't see a complete G and a complete E. Their shapes bother each other)
NB: vous pouvez retourner vrai même si la sculpture contient des "pixels volants" (cubes ou groupe de cubes attachés à rien).
Des échappatoires standard s'appliquent.
Plus précisément, vous ne pouvez pas utiliser d'entrée externe en plus des trois lettres, et vous ne pouvez pas coder en dur les 17576 réponses possibles dans votre code source
La réponse la plus courte en caractères dans n'importe quelle langue gagne!
S'amuser :)
Réponses:
Mathematica 423
J'ai ajouté une section intitulée "Comment fonctionne le blocage".
Non golfé
(* Les données binaires de l'alphabet sont stockées sous la forme d'une seule chaîne
s
. L'vars
importent et les convertissent en tableau.)Exemple
Le cube est-il
{"B", "G", "E"}
valide? (c.-à-d. les trois lettres se projetteront-elles correctement sur les murs?)Des illustrations
Les figures ci-dessous montrent comment le BGE est rendu. La rangée supérieure de figures prend des perspectives orthogonales, comme si le spectateur était positionné à des distances infinies du cube. La rangée inférieure montre à quoi ressembleraient les blocs de près. Les figures 3D peuvent être tournées manuellement pour inspecter précisément où les cubes unitaires individuels sont positionnés.
Un problème se produit avec la lettre "G". Il n'y a rien qui relie l'empattement au reste de la lettre.
BEG, cependant, devrait fonctionner correctement.
Comment fonctionne le blocage?
Veuillez m'excuser si cela semble évident, mais peut-être que certaines personnes voudront voir comment les lettres interfèrent les unes avec les autres, annulant leurs pixels 3D.
Suivons ce qui arrive à la lettre G, dans le rendu du cube BGE.
Nous porterons une attention particulière au voxel (pixel 3D ou cube d'unité) ci-dessous. C'est le pixel qui disparaît dans le cube BGE. Il s'agit du pixel correspondant à la ligne 4, à la colonne 5 dans le tableau de bits et dans le tracé de tableau correspondant.
Dans le plan xy, le pixel correspond au disque gris au point (5,2). Mais parce que nous allons travailler en 3D, nous devons considérer les 5 positions dans l' arbre de (5,1,2) à (5,5,2). Si l'un de ces pixels survit à la sculpture par les lettres B et E, nous serons en mesure de voir le pixel d'intérêt dans la projection 3D sur le mur.
Les lettres interfèrent lorsque les pixels sont supprimés du bloc solide. A gauche, la flèche noire représente la découpe des pixels, correspondant au bit en bas à droite; il a la valeur 0 pour la lettre B. La découpe supprime le pixel en (5,1,2), ainsi que ceux directement au-dessus et en dessous. Quatre pixels restent à prendre en compte.
Mais comme le montre le volet droit, la lettre E sculpte les pixels d'intérêt restants, (5,2,2) (5,3,2), (5,4,2) et (5,5,2). (Cela est dû au fait que la lettre E a des bits égaux à 0 dans la quatrième ligne, de la colonne 2 à la colonne 5.) Par conséquent, aucun pixel ne reste parmi ceux qui étaient nécessaires pour assurer l'ombre au point (5 , 2) sur le mur du fond (pour la lettre G). Au lieu de cela, il y aura un point lumineux correspondant à un trou dans la lettre G! Le cube BGE n'est pas bon car il rend incorrectement G.
Golfé 423 caractères
La fonction a
h
joué le même rôle quevalidQ
dans le code non golfé. La fonction de renduperspective
, n'est pas incluse car elle ne contribue pas et n'est pas requise par le défi.la source
Prolog,
440, 414Le programme est appelé comme ceci:
Prolog
semblait être un bon choix, car il est facile de représenter le problème dans une logique de premier ordre.Prolog
Fournit également des fonctionnalités puissantes pour résoudre ce type de problème.Cependant, comme le code est joué, je suppose que je devrais ajouter quelques explications.
Version légèrement golfée
Les coordonnées correspondant aux pixels de chaque côté des dés peuvent être facilement converties en un système de coordonnées 3D. J'utilise
T
,L
etR
pour le haut (1), le côté gauche (2) et le côté droit (3).u
etv
sont utilisés pour les coordonnées dans les images:(u,v) -> (4-v, ?, u)
(u,v) -> (?, v, u)
(u,v) -> (u, v, ?)
Les résultats pour chaque pixel actif (c'est-à-dire noir) sont combinés à un ensemble de «pixels 3D» qui peuvent être activés sans changer l'apparence de l'objet de ce côté. L'intersection des ensembles pour chaque côté sont tous des pixels 3D, qui peuvent être activés sans ajouter de pixels, qui obstrueraient la vue (c'est-à-dire qu'en regardant d'au moins un côté, il y aurait un pixel qui ne devrait pas être là).
Il ne reste plus qu'à vérifier de chaque côté, s'il y a un pixel dans l'intersection qui bloque la vue, là où c'est nécessaire.
Cela conduit aux prédicats du programme:
c : recherche le pixel dans l'image d'une lettre. La chaîne peut sembler un peu étrange, mais ce n'est qu'un moyen compact de stocker les données d'image. Il s'agit simplement d'une séquence de caractères avec les valeurs suivantes (notation hexadécimale):
Chacun de ces caractères stocke les données de 3 lignes de pixels dans une ou plusieurs images de lettre (= 15 pixels). Les pixels sont également réorganisés de sorte que les données soient stockées à un emplacement et non divisées sur plusieurs lignes, comme les données de l'OP.
Formulation mathématique
Des données d'entrée
Conversion de pixel dans un caractère en un ensemble de pixels 3D qui obstruent la vue de ce pixel
Pixels qui peuvent être ajoutés en toute sécurité (sans obstruer la vue au mauvais endroit)
Vérifie de chaque côté que les pixels qui doivent être obstrués peuvent être obstrués en toute sécurité
Combinaison de chèques de chaque côté
la source
J -
223197191 caractèresUne fonction prenant comme argument une liste de trois caractères.
Ce golf repose en grande partie sur une puissante caractéristique de J appelée rank , qui nous donne presque gratuitement la fonction "sculpter" et "regarder" des opérations. Pour le simplifier un peu, le rang fait référence à la dimensionnalité d'un nom ou des arguments naturels d'un verbe.
J a des tableaux multidimensionnels, et il est évident que, disons, un tableau 3D peut être interprété comme un tableau 3D unique, ou comme une liste de matrices, ou un tableau 2D de vecteurs, ou un tableau 3D de scalaires. Ainsi, chaque opération dans J peut avoir son application contrôlée par rapport à la répartition sur l'argument. Le rang 0 signifie appliquer sur les scalaires, le rang 1 signifie appliquer sur les vecteurs, etc.
Cela devient très puissant lorsque vous introduisez des fonctions dyadiques (à deux arguments), car si les formes des deux arguments (après avoir pris en compte le rang) sont agréables, J fera une boucle implicite:
Lorsque toutes vos formes sont agréables et que vous pouvez spécifier le rang vous-même, il existe plusieurs façons de combiner les arguments. Ici, nous montrons quelques-unes des façons dont vous pouvez multiplier une matrice 2D et un tableau 3D.
Vous remarquerez que cela ne s'inscrit pas réellement dans les lettres dans l'orientation que demande la question, il les écrit simplement mais est pratique pour la logique de classement. Sauf si nous inversons ou faisons pivoter les lettres avant de les appliquer, cela ne fonctionnera pas correctement. Mais corriger des choses comme ça prendrait des caractères précieux, donc à la place, nous encoderons les lettres de telle sorte que, lorsque J les découpera naturellement, un triple de visages sera dans les bonnes orientations et positions relatives. Il s'avère que la solution la plus courte consiste à faire pivoter toutes les lettres d'un quart de tour dans le sens antihoraire. Considérant la troisième dimension de J pour représenter l'axe d'avant en arrière, le diagramme brut ci-dessous montre pourquoi ce schéma fonctionne.
Figure A: Les trois côtés du cube dans lesquels J sculpte. Figure B: Les trois côtés qui ont les lettres orientées comme le demande la question.
Ce choix d'encodage enregistre 12 caractères par rapport à la méthode précédente et rend le tout plus net. Le golf proprement dit crée le cube à partir du
"1
et"2
sculpte avec une logique funky, en raison d'une optimisation indépendante.Ensuite, nous devons vérifier les visages. Puisque nous chiffrons le bloc comme 1 et de 0, nous pouvons simplement résumer le long de chaque axe de la manière que nous voulons (ce sont les
+/"1
,+/"2
et les+/
bits), adapter à booléens (0<
), puis les comparer directement à 90 ° d' origine - lettres tournées.Le schéma de compression code chaque ligne de 5 pixels de chaque lettre comme représentation de base 32 d'un nombre binaire. En exploitant un certain nombre de sucres syntaxiques et de surcharges d'opérateurs,
".'1b',"#:
c'est le moyen le plus court de transformer la liste de caractères en nombres de base 36. Eh bien, techniquement, en base 32, mais J pense que c'est unaire, alors qui compte?L'utilisation est ci-dessous. Notez que les chaînes sont des tableaux de caractères en J, donc une liste de trois éléments
'A','B','C'
peut être écrite'ABC'
pour faire court. De plus, les booléens sont 1/0.la source
Python,
687682671Appelez avec
v
:Tout ce qui suit est de ma précédente version non golfée qui comprend des fonctions de dessin utiles. N'hésitez pas à l'utiliser comme point de départ.
Appelez
valid
pour l'exécuter:À l'heure actuelle, le code est configuré pour tester la validité
B E G
et imprimer les faces résultantes:En l'exécutant,
B G E
nous pouvons voir que le G est incorrect:la source
g=[[0 for j in s]for i in s]
peut être raccourcig=map(list,[[0]*5]*5)
. Vous pouvez également éviter indenter blocs si elles sont une seule instruction:if c[e]:g[e[a]][e[a-2]]=1
.Python 3 + numpy, 327C
Cette solution de golf a besoin d'une bibliothèque externe, numpy, qui est assez populaire, donc je pense que c'est bien de l'utiliser.
La chaîne unicode est en 41 caractères, tandis que la même chose dans la réponse prologue de @ fabian est 44.
Le plus intéressant ici est celui de l'indexation du tableau numpy. Dans
a[ix]
,ix
peut être un tableau booléen de même forme quea
. C'est la même chose que de direa[i, j, k] where ix[i, j, k] == True
.Version non golfée
Script pour compresser la table
la source