Écrivez un programme pour dessiner un diagramme 2D d'un nœud basé sur la structure du nœud. Un nœud est exactement ce à quoi il ressemble: une boucle de corde qui est attachée. En mathématiques, un diagramme de nœuds montre où un morceau de corde se croise sur ou sous lui-même pour former le nœud. Voici quelques exemples de diagrammes de nœuds:
Il y a une rupture dans la ligne où la corde se croise.
Entrée: l'entrée décrivant le nœud est un tableau d'entiers. Un nœud où la corde se croise sur elle-même n fois peut être représenté comme un tableau de n entiers, chacun avec une valeur dans la plage [0, n-1]. Appelons ce tableau K .
Pour obtenir le tableau décrivant un nœud, numérotez chacun des segments de 0 à n-1. Le segment 0 doit conduire au segment 1, qui doit conduire au segment 2, qui doit conduire au segment 3, et ainsi de suite jusqu'à ce que le segment n-1 boucle en arrière et mène au segment 0. Un segment se termine lorsqu'un autre segment de corde le traverse ( représenté par une coupure dans la ligne du diagramme). Prenons le nœud le plus simple - le nœud trèfle. Après avoir numéroté les segments, le segment 0 se termine lorsque le segment 2 le traverse; le segment 1 se termine lorsque le segment 0 le traverse; et le segment 2 se termine lorsque le segment 1 le traverse. Ainsi, le tableau décrivant le nœud est [2, 0, 1]. En général, le segment x commence là où le segment x-1 mod n s'est arrêté et se termine là où le segment K [x] le traverse.
L'image ci-dessous montre des diagrammes de nœuds, avec des segments étiquetés et les tableaux correspondants qui décrivent le nœud.
Les trois diagrammes supérieurs sont de vrais nœuds, tandis que les trois derniers sont des boucles de corde qui se croisent mais qui ne sont pas réellement nouées (mais qui ont toujours des codes correspondants).
Votre tâche consiste à écrire une fonction qui prend un tableau d'entiers K (vous pourriez l'appeler quelque chose de différent) qui décrit un nœud (ou une boucle de corde qui n'est pas réellement nouée), et qui produit le diagramme de nœud correspondant, comme décrit ci-dessus exemples. Si vous le pouvez, fournissez une version non golfée de votre code ou une explication, ainsi que des exemples de sorties de votre code. Le même nœud peut souvent être représenté de plusieurs façons différentes, mais si le diagramme de nœuds que votre sortie de fonction satisfait a l'entrée comme l'une de ses représentations possibles, votre solution est valide.
C'est le code-golf, donc le code le plus court en octets gagne. La ligne représentant la corde peut avoir une épaisseur de 1 pixel, mais les traversées et les franchissements doivent être clairement distinguables (la taille de la rupture de la corde doit être supérieure à l'épaisseur de la corde d'au moins un pixel de chaque côté) .
Je vais voter pour des réponses qui reposent sur des capacités de théorie des nœuds intégrées, mais celle qui est finalement sélectionnée ne peut pas s'appuyer sur des capacités de théorie des nœuds intégrées.
Tout ce que je sais de ma notation: je crois qu'il y a des séquences de valeurs qui ne semblent correspondre à aucun nœud ou à un nœud. Par exemple, la séquence [2, 3, 4, 0, 1] semble impossible à tracer.
En dehors de cela, supposez que vous prenez un croisement et, à partir de ce croisement, suivez le chemin de la corde dans une direction et étiquetez chaque croisement sans étiquette que vous rencontrez avec des valeurs intégrales successivement plus grandes. Pour les nœuds alternés, il existe un algorithme simple pour convertir ma notation en un tel étiquetage, et pour les nœuds alternés, il est trivial de convertir cet étiquetage en un code Gauss:
template<size_t n> array<int, 2*n> LabelAlternatingKnot(array<int, n> end_at)
{
array<int, n> end_of;
for(int i=0;i<n;++i) end_of[end_at[i]] = i;
array<int, 2*n> p;
for(int& i : p) i = -1;
int unique = 0;
for(int i=0;i<n;i++)
{
if(p[2*i] < 0)
{
p[2*i] = unique;
p[2*end_of[i] + 1] = unique;
++unique;
}
if(p[2*i+1] < 0)
{
p[2*i+1] = unique;
p[2*end_at[i]] = unique;
++unique;
}
}
return p;
}
template<size_t n> auto GetGaussCode(array<int, n> end_at)
{
auto crossings = LabelAlternatingKnot(end_at);
for(int& i : crossings) ++i;
for(int i=1;i<2*n;i+=2) crossings[i] = -crossings[i];
return crossings;
}
la source
KnotData
dans Mathematica ...: '(Knot
intégré! Exemple d'utilisation:<< Units`; Convert[Knot, Mile/Hour]
rendements1.1507794480235425 Mile/Hour
. (Je pense que c'est drôle, que ce soit vrai ou faux; mais c'est en fait vrai.)Réponses:
GNU Prolog,
622634668 octets dans la page de codes 850Mise à jour : la version précédente du programme faisait parfois des croisements si serrés qu'ils ne rendraient pas correctement, ce qui viole les spécifications. J'ai ajouté du code supplémentaire pour éviter cela.
Mise à jour : Apparemment, les règles PPCG nécessitent un code supplémentaire pour faire quitter le programme et restaurer l'état exactement comme il était au début. Cela rend le programme un peu plus long et n'y ajoute aucun intérêt algorithmique, mais dans l'intérêt de la conformité aux règles, je l'ai changé.
Programme golf
Utiliser GNU Prolog car il a une syntaxe de solveur de contraintes légèrement plus courte que la syntaxe arithmétique portable de Prolog, économisant quelques octets.
Algorithme
C'est l'un de ces problèmes où il est difficile de savoir par où commencer. Il n'est pas évident de déterminer la forme du nœud à partir de la notation donnée, car cela ne vous permet pas de savoir si vous êtes censé plier la ligne vers la gauche ou la droite à un endroit donné (et en tant que tel, le la notation peut être ambiguë). Ma solution était, en fait, d'utiliser l'ancienne veille de golf: écrire un programme incroyablement inefficace qui génère toutes les sorties possibles, puis voir si elles correspondent à l'entrée. (L'algorithme utilisé ici est légèrement plus efficace, car Prolog peut éliminer l'impasse occasionnelle, mais il n'a pas suffisamment d'informations pour améliorer la complexité de calcul.)
La sortie se fait via le terminal art. GNU Prolog semble vouloir un jeu de caractères à un seul octet compatible avec ASCII, mais ne se soucie pas de celui qui est utilisé (car il traite les caractères avec le bit élevé comme opaques). En conséquence, j'ai utilisé IBM850, qui est largement pris en charge et possède les caractères de dessin au trait dont nous avons besoin.
Sortie
Le programme recherche toutes les images de nœuds possibles, dans l'ordre de la taille de leur boîte englobante, puis se ferme lorsqu'il trouve la première. Voici à quoi ressemble la sortie
m([0]).
:Cela a pris 290,528 secondes pour s'exécuter sur mon ordinateur; le programme n'est pas très efficace. Je l'ai laissé fonctionner pendant deux heures
m([0,1])
et j'ai fini avec ceci:Version non golfée avec commentaires
Le surligneur de syntaxe de Stack Exchange semble avoir le mauvais symbole de commentaire pour Prolog, donc au lieu de
%
commentaires (que Prolog utilise réellement), cette explication utilise des% #
commentaires (qui sont bien sûr équivalents en raison du début%
, mais surlignent correctement).la source