Dessinez un hexa-glyphe aléatoire

23

entrez la description de l'image ici

L'image ci-dessus est appelée hexa-glyphe. Les hexa-glyphes sont des modèles sympas que j'ai créés en griffonnant pendant ma classe DiffEq. Voici comment vous en créez un:

  1. Considérez l'ensemble de points suivant, en forme d'hexagramme régulier. L'hexagone intérieur est ce qui contiendra le glyphe final, tandis que les 6 points extérieurs forment une étoile et c'est là que nous commencerons à dessiner nos lignes.

entrez la description de l'image ici

  1. À partir des six points extérieurs, sélectionnez au hasard une paire. Pour plus d'efficacité, il devrait y avoir au moins un autre point entre les deux points sélectionnés (sinon, cela n'aurait aucun effet sur le chiffre final). Ensuite, à partir de chacun des deux points, lancez un rayon vers l'autre. Ce rayon est bloqué par les lignes précédentes.

entrez la description de l'image ici

  1. Répétez ce processus jusqu'à ce que les 9 bords aient été formés, comme le montrent les images suivantes.

entrez la description de l'image ici

  1. Voici un exemple de rayons bloqués. Les extrémités du segment de rayon sont toujours visibles, mais la partie médiane est occluse par les deux premiers segments que nous avons dessinés.

entrez la description de l'image ici

  1. Ces deux rayons sont également "bloqués", mais cela ne cause aucune différence visible car ils sont bloqués par la même autre ligne.

entrez la description de l'image ici

  1. Avance rapide jusqu'à ce que les 9 lignes soient dessinées. Si vous souhaitez une explication plus détaillée de ces étapes ignorées, je peux l'exposer.

entrez la description de l'image ici

  1. Enfin, supprimez les pointes de l'étoile. Pour le rendre plus joli, les points épais sont également supprimés.

entrez la description de l'image ici

Le défi

Votre défi consiste à produire une représentation visuelle d'un hexaglyphe aléatoire. C'est le code-golf, le moins d'octets gagne.

  1. Tous les hexa-glyphes possibles devraient apparaître avec une certaine probabilité positive. Différents hexaglyphes sont générés en modifiant l'ordre dans lequel les 9 bords sont dessinés.

  2. De plus, toutes les images produites par votre programme doivent être des hexa-glyphes valides. Certains modèles (comme un contour complet de l'hexagone intérieur) ne peuvent pas apparaître comme un hexaglyphe, et vous ne devez donc pas les afficher.

  3. La sortie doit être une image graphique (imprimée à l'écran ou dans un fichier).

  4. L'hexagone doit être régulier, mais peut apparaître dans n'importe quelle orientation.

  5. Les réflexions / rotations ne sont pas considérées comme uniques. (Cela pourrait rendre l'exigence 1 plus facile à suivre).

PhiNotPi
la source
8
I made up while doodling during my DiffEq class.
Comme
Quelles sont les exigences minimales pour l'image? Dans quelle mesure un art ASCII doit-il être reconnaissable tant que chaque bord est représenté et placé vaguement au bon endroit?
John Dvorak
@JanDvorak J'ai supprimé l'option art ASCII du défi (comme dans les 2 minutes suivant la publication) parce que les programmes qui produisent de l'art ASCII et des sorties graphiques ne sont pas facilement comparables.
PhiNotPi
qu'en est-il du pixel art alors? Un en-tête PPM n'est pas trop lourd, et ensuite la seule différence est d'utiliser '01'avec de l'espace entrelacé au lieu de ' *'.
John Dvorak
@JanDvorak Output serait alors un fichier image correctement formaté, non? Ensuite, je ne vois rien de mal à cela.
PhiNotPi

Réponses:

18

Mathematica, 273 268 264 242 octets

c=CirclePoints;b@_=k=1>0;Graphics[Line/@Cases[Append[Join@@({c@6,{3^.5/2,-Pi/6}~c~6}),{0,0}][[b@#=!k;#]]&/@TakeWhile[#,t=k;(r=t;t=b@#;r)&]&/@Join@@RandomSample[{#,Reverse@#}&/@Partition[Range@12,3,2,1]~Join~Array[{2#,13,2#+6}&,3]],{_,__}]]

le rendu est un exposant Tdans Mathematica et est un opérateur de transposition de suffixe.

Il a fallu une éternité pour trier les bogues dans ce dossier ... vers la fin, j'ai piraté quelques éléments ensemble pour le faire fonctionner, donc c'est définitivement sous-optimal. Je me demande également s'il serait mieux dans l'ensemble d'implémenter la spécification plus littéralement via les lignes à travers l'hexagone externe et de laisser les fonctions de géométrie de Mathematica gérer les intersections.

Notez qu'il s'agit d'un programme complet et si vous souhaitez exécuter le code plusieurs fois au cours d'une même session REPL, vous devrez le préfixer avec Clear[b] .

Voici les résultats de 20 runs:

entrez la description de l'image ici

Explication

Cette solution n'utilise pas du tout les points étoiles externes. Au lieu de cela, il fonctionne directement avec les points qui font partie de l'hexaglyphe et les lignes qui couvrent trois d'entre eux à la fois.

Étiquetons les points:

entrez la description de l'image ici

1 commence dans un coin légèrement bizarre, mais cela est dû au comportement par défaut (également quelque peu bizarre) de CirclePoints . Le démarrage de l'hexagone à partir de là s'est avéré le moins cher.

Maintenant, nous voulons trouver les lignes pertinentes à travers trois de ces points qui correspondent aux points connectés de l'étoile extérieure. Ceux autour de l'hexagone ne sont bien sûr que 3 points adjacents (modulo 12), à partir d'un nombre impair. Celles du centre se composent d'un nombre pair n, 13etn+6 .

Les représentations de ces lignes (sous forme de listes de trois points sont générées par le code suivant):

Partition[Range@12,3,2,1]~Join~Array[{2#,13,2#+6}&,3]

Le Partitiongénère les lignes autour de l'hexagone et Arrayles lignes passant par le centre. Pour traiter les deux faisceaux, nous mappons cette fonction sur la liste des lignes:

{#,Reverse@#}&

Maintenant, nous les mélangeons avec RandomSample pour les traiter dans un ordre aléatoire. Join @@aplatit la liste des paires pour que nous ayons une liste de faisceaux.

Interruption courte: pour garder une trace des points qui sont déjà bloqués, nous utilisons une fonction de recherche b, qui est initialisée à Truepour toutes les valeurs par b@_=k=1>0;. Lors du traitement d'une poutre, nous gardons tous les points jusqu'au premier point qui a b[n] == False( y compris celui-ci):

TakeWhile[#,t=k;(r=t;t=b@#;r)&]&

J'ai l'impression que c'est la partie la plus jouable en ce moment ... l'utilisation de deux variables temporaires pour jouer à Mastermind semble vraiment chère. Quoi qu'il en soit, le résultat de cela nous donne les points dans une ligne que nous sommes autorisés à dessiner. Maintenant, cette fonction est mappée sur chacun de ces points:

Append[Join@@({c@6,{3^.5/2,-Pi/6}~c~6}),{0,0}][[b@#=!k;#]]&

La première partie génère la liste des 13 points en utilisant les résultats entrelacés de deux appels à CirclePoints(avec des rayons différents pour les centres des bords et les coins de l'hexagone). Notez le b@#=!kqui définit désormais la valeur de la table de recherche pour le point actuel Falseafin qu'aucun faisceau supplémentaire ne puisse le traverser. Enfin, la valeur est utilisée comme index dans la liste des coordonnées pour obtenir le point 2D correct.

Cases[...,{_,__}]

Cela supprime toutes les listes à élément unique, car elles s'afficheraient sous forme de points individuels (et visibles). Enfin, nous rendons le résultat:

Graphics[Line/@...]
Martin Ender
la source
b@_=1>0=b=1>0&
CalculatorFeline
@CatsAreFluffy Je ne pense pas que cela fonctionne, car je dois pouvoir remplacer les valeurs individuelles plus tard.
Martin Ender
Bonne utilisation de CirclePoints.
DavidC
J'ai apprécié ce lien Youtube.
DanTheMan
8

Chaussures (Ruby) Rev C 184 octets

12 octets économisés en transférant la responsabilité de vérifier si une demi-ligne particulière doit être tirée du programme principal vers la méthode de dessin. Cependant, le programme principal doit encore vérifier si toute la ligne est complètement bloquée.

Shoes.app{t=[]
d=->p,q{t[p]&&t[q]||line(p/6*8,p%6*14,q/6*8,q%6*14)}
%w{1I IW WM M5 5' '1 =A P. R,}.shuffle.map{|i|b=i.sum/2
c=b*2-a=i.ord
t[a]&&t[c]||(d[a,b]
d[b,c]
t[a]=t[b]=t[c]=1)}}

Chaussures (Ruby) 205 ... Rev B 196 bytes

Shoes est un outil à base de rubis pour créer des interfaces graphiques, etc. C'est la première fois que je l'utilise. mothereff.in/byte-counter compte ma soumission comme 196 octets, mais pour une raison quelconque, Shoes la compte comme 202.

De plus, Ruby vous permet de faire des choses comme, t[a=i.ord]mais étrangement, il ne semble pas fonctionner comme prévu avec des chaussures.

Shoes.app{t=[]
d=->p,q{line(p/6*8,p%6*14,q/6*8,q%6*14)}
%w{1I IW WM M5 5' '1 =A P. R,}.shuffle.map{|i|b=i.sum/2
c=b*2-a=i.ord
t[a]&&t[c]||(t[a]&&t[b]||d[a,b]
t[b]&&t[c]||d[b,c]
t[a]=t[b]=t[c]=1)}}

Explication

Je ne considère pas les parties de la ligne en dehors de l'hexagone. Je ne dessine que la partie à dessiner. L'important est de savoir si les lignes traversent les intersections (si nous ne dessinons que les parties qui doivent être dessinées, cela signifie qu'elles commencent / se terminent aux intersections.)

La règle de base est que si les deux extrémités d'une ligne ont été visitées, la ligne est bloquée et ne doit pas être dessinée. Comme les lignes sont tracées en deux moitiés, nous devons également vérifier si le point médian a été visité pour voir si chaque moitié doit être tracée ou non.

Je garde une trace des points qui ont été visités dans le tableau t[]. Cela finit par contenir une entrée pour chaque coordonnée physique sur la grille ci-dessous. Il n'y a pas de tableau logique séparé à 13 éléments. À la fin, t[]peut avoir 87 éléments, mais seulement 13 contiendront des données utiles.

En interne, les coordonnées des extrémités des lignes sont données par un seul nombre z, où z% 6 est la coordonnée y et z / 6 est la coordonnée x. Dans ce système, l'hexagone est aplati. Lorsque les lignes sont tracées, l'échelle x est multipliée par 8 et l'échelle y est multipliée par 14, ce qui est une approximation rationnelle très proche du rapport correct: 14/8 = 1,75 vs sqrt (3) = 1,732.

Le système de coordonnées interne est illustré ci-dessous, avec quelques exemples de sorties.

entrez la description de l'image ici

Non golfé

Shoes.app{
  t=[]                                          #Empty array for status tracking
  d=->p,q{line(p/6*8,p%6*14,q/6*8,q%6*14)}      #Drawing method. Convert p and q into x,y pairs, scale and draw line.
  %w{1I IW WM M5 5' '1 =A P. R,}.shuffle.map{|i|#take an array of the coordinates of the endpoints of each line, shuffle, then for each line
    b=i.sum/2                                   #b = midpoint of line, convert ASCII sum to number (average of the two coordinates)
    a=i.ord                                     #a = first endpoint of line, convert ASCII to number (no need to write i[0].ord)
    c=b*2-a                                     #c = second endpoint of line (calculating is shorter than writing i[1].ord)
    t[a]&&t[c]||(                               #if both endpoints have already been visited, line is completely blocked, do nothing. ELSE
      t[a]&&t[b]||d[a,b]                        #if first endpoint and midpoint have not both been visited, draw first half of line
      t[b]&&t[c]||d[b,c]                        #if second endpoint and midpoint have not both been visited, draw second half of line
      t[a]=t[b]=t[c]=1                          #mark all three points of the line as visited
    )
  }
}

Plus d'exemples de sorties

Cela a été fait avec une ancienne version du programme. La seule différence est que le positionnement de l'hexaglyphe dans la fenêtre est désormais légèrement différent.

entrez la description de l'image ici

Level River St
la source
mothereff.in/byte-counter counts my submission as 196 bytes, but for some reason Shoes counts it as 202.Je ne sais pas à 100% si c'est vrai, mais je pense que la raison pour laquelle Shoes a compté votre code comme 202 octets au lieu de 196 est parce que vos nouvelles lignes sont en fait une séquence de deux caractères "\ r \ n". Cela fait que chaque nouvelle ligne est comptée deux fois. Voici une réponse de débordement de pile concernant \ r et \ n.
K Zhang
Hehe, je ne peux pas surmonter le nom Ruby avec des chaussures XD
Beta Decay
3

Python, 604 591 574 561 538 531 536 534 528 493 483 452 431 420 419 415 388 385 384 octets

J'ai adapté l'idée de Level River St de vérifier si une ligne sera bloquée en vérifiant si les deux extrémités de la ligne ont déjà été visitées auparavant. Cela économise 27 octets. Suggestions de golf bienvenues.

Edit: correction de bugs et golf g(p,q)pour 3 octets. Golfé Lpour un octet.

from turtle import*
from random import*
R=range
G=goto
*L,=R(9)
shuffle(L)
a=[0]*13
ht()
T=12
c=[(j.imag,j.real)for j in(1j**(i/3)*T*.75**(i%2/2)for i in R(T))]+[(0,0)]
def g(p,q):pu();G(c[p]);a[p]*a[q]or pd();G(c[q])
for m in L:
 p=2*m;x,y,z=R(p,p+3)
 if m<6:
  if a[x]*a[z%T]<1:g(x,y);g(y,z%T);a[x]=a[y]=a[z%T]=1
 else:
  if a[p-11]*a[p-5]<1:g(p-11,T);g(p-5,T);a[p-11]=a[p-5]=a[T]=1

Ungolfing:

from turtle import*
from random import*

def draw_line(points, p_1, p_2):
    penup()
    goto(points[p_1])
    if not (a[p] and a[q]):
        pendown()
    goto(points[p_2])

def draw_glyph():
    ht()
    nine_lines = list(range(9))
    shuffle(nine_lines)
    size = 12
    center = [0,0]

    points = []
    for i in range(12):      # put in a point of a dodecagon
                             # if i is even, keep as hexagon point
                             # else, convert to hexagon midpoint
        d = 1j**(i/3) * 12   # dodecagon point
        if i%2:
            d *= .75**.5     # divide by sqrt(3/4) to get midpoint
        points += (d.imag, d.real)
    points.append(center)

    a = [0]*13
    for m in nine_lines:
        p = 2*m
        if m<6:
            x, y, z = p, p+1, p+2
            if not (a[x] and a[z%12]):
                draw_line(points, x, y)
                draw_line(points, y, z%12)
                a[x] = a[y] = a[z%12] = 1
        else:
            if not (a[p-11] and a[p-5]):
                draw_line(p-11, 12)
                draw_line(p-5, 12)
                a[p-11] = a[p-5] = a[12] = 1

Les hexa-glyphes eux-mêmes sont assez petits car nous utilisons un hexagone de 12 pixels comme base (pour des raisons de golf). Voici quelques exemples d'hexa-glyphes (excuses pour les mauvaises récoltes):

Un exemple d'hexa-glyphe Un exemple d'hexa-glyphe Un exemple d'hexa-glyphe Un exemple d'hexa-glyphe Un exemple d'hexa-glyphe Un exemple d'hexa-glyphe

Sherlock9
la source
Pourrait économiser quelques octets:R=range;G=goto
Tim Čas