Zeichne einen zufälligen Hexaglyphen

23

Bildbeschreibung hier eingeben

Das obige Bild wird als Hexaglyphe bezeichnet. Hexaglyphen sind einige coole Muster, die ich während meiner DiffEq-Klasse erstellt habe. So machst du eins:

  1. Betrachten Sie die folgenden Punkte, die wie ein reguläres Hexagramm geformt sind. Das innere Sechseck enthält die letzte Glyphe, während die äußeren 6 Punkte einen Stern bilden und dort beginnen, unsere Linien zu zeichnen.

Bildbeschreibung hier eingeben

  1. Wählen Sie aus den äußeren sechs Punkten zufällig ein Paar aus. Aus Effizienzgründen sollte mindestens ein weiterer Punkt zwischen den beiden ausgewählten Punkten liegen (andernfalls hat dies keine Auswirkungen auf die endgültige Zahl). Wirf dann von jedem der beiden Punkte einen Strahl auf den anderen. Dieser Strahl wird durch vorherige Zeilen blockiert .

Bildbeschreibung hier eingeben

  1. Wiederholen Sie diesen Vorgang, bis alle 9 Kanten gebildet wurden, wie in den nächsten Bildern gezeigt.

Bildbeschreibung hier eingeben

  1. Hier ist ein Beispiel für das Blockieren von Strahlen. Die Enden des Strahlsegments sind noch sichtbar, aber der mittlere Teil wird von den ersten beiden Segmenten, die wir gezeichnet haben, verdeckt.

Bildbeschreibung hier eingeben

  1. Diese beiden Strahlen werden ebenfalls "blockiert", dies verursacht jedoch keinen sichtbaren Unterschied, da sie von derselben anderen Linie blockiert werden.

Bildbeschreibung hier eingeben

  1. Schnellvorlauf, bis alle 9 Linien gezeichnet sind. Wenn Sie eine detailliertere Erläuterung dieser übersprungenen Schritte wünschen, kann ich dies erläutern.

Bildbeschreibung hier eingeben

  1. Zum Schluss entfernen Sie die Punkte des Sterns. Damit es schöner aussieht, werden auch die dicken Punkte entfernt.

Bildbeschreibung hier eingeben

Die Herausforderung

Sie müssen eine visuelle Darstellung eines zufälligen Hexaglyphen ausgeben. Das ist Code-Golf, die wenigsten Bytes gewinnen.

  1. Alle möglichen Hexaglyphen sollten mit einer positiven Wahrscheinlichkeit erscheinen. Durch Ändern der Reihenfolge, in der die 9 Kanten gezeichnet werden, werden verschiedene Hexaglyphen erzeugt.

  2. Außerdem müssen alle von Ihrem Programm ausgegebenen Bilder gültige Hexaglyphen sein. Bestimmte Muster (z. B. ein vollständiger Umriss des inneren Sechsecks) können möglicherweise nicht als Hexaglyphen dargestellt werden. Sie dürfen diese also nicht ausgeben.

  3. Die Ausgabe sollte ein grafisches Bild sein (auf dem Bildschirm oder in einer Datei gedruckt).

  4. Das Sechseck muss regelmäßig sein, kann aber in beliebiger Ausrichtung erscheinen.

  5. Reflexionen / Rotationen werden nicht als einzigartig angesehen. (Dies könnte die Einhaltung von Anforderung 1 erleichtern.)

PhiNotPi
quelle
8
I made up while doodling during my DiffEq class. So geschehen alle großen Entdeckungen ...: P
Rɪᴋᴇʀ
Was sind die Mindestanforderungen an das Bild? Inwieweit muss eine ASCII-Kunst erkennbar sein, solange jede Kante dargestellt und vage an der richtigen Stelle platziert wird?
John Dvorak
@JanDvorak Ich habe die ASCII-Art-Option der Challenge entfernt (etwa innerhalb von 2 Minuten nach dem Posten), da Programme, die ASCII-Art- und Grafikausgaben erzeugen, nicht einfach vergleichbar sind.
PhiNotPi
was ist dann mit Pixelkunst? Ein PPM-Header ist nicht zu schwer, und der einzige Unterschied besteht in der Verwendung '01'von Space Interleaved anstelle von ' *'.
John Dvorak
@ JanDvorak Output wäre dann eine richtig formatierte Bilddatei, oder? Dann sehe ich nichts falsch daran.
PhiNotPi

Antworten:

18

Mathematica, 273 268 264 242 Bytes

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]],{_,__}]]

Das rendert Tin Mathematica als hochgestellt und ist ein Postfix-Transponierungsoperator.

Das Aussortieren der Fehler hat ewig gedauert ... gegen Ende habe ich ein paar Dinge zusammen gehackt, damit es funktioniert, also ist das definitiv nicht optimal. Ich frage mich auch, ob es insgesamt besser wäre, die Spezifikation wörtlich über die Linien im äußeren Sechseck zu implementieren und die Geometriefunktionen von Mathematica die Schnittpunkte handhaben zu lassen.

Beachten Sie, dass dies ein vollständiges Programm ist. Wenn Sie den Code innerhalb einer einzelnen REPL-Sitzung mehrmals ausführen möchten, müssen Sie ihm ein Präfix voranstellen Clear[b].

Hier sind die Ergebnisse von 20 Läufen:

Bildbeschreibung hier eingeben

Erläuterung

Bei dieser Lösung werden die äußeren Sternpunkte überhaupt nicht verwendet. Stattdessen wird direkt mit den Punkten gearbeitet, die Teil der Hexaglyphe sind, und mit den Linien, die jeweils drei davon abdecken.

Beschriften wir die Punkte:

Bildbeschreibung hier eingeben

1beginnt in einer etwas seltsamen Ecke, ist aber auf das (auch etwas seltsame) Standardverhalten von zurückzuführen CirclePoints. Das Sechseck von dort aus zu starten, stellte sich als am billigsten heraus.

Nun wollen wir die relevanten Linien durch drei dieser Punkte finden, die den verbundenen Punkten des äußeren Sterns entsprechen. Die um das Sechseck herum sind natürlich nur 3 benachbarte Punkte (Modulo 12), beginnend mit einer ungeraden Zahl. Die , die in der Mitte bestehen aus einer geraden Zahl n, 13und n+6.

Darstellungen dieser Linien (in Form von Listen mit drei Punkten werden durch den folgenden Code generiert):

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

Das Partitionerzeugt die Linien um das Sechseck und Arraydie Linien durch die Mitte. Um beide Strahlen zu verarbeiten, ordnen wir diese Funktion der Linienliste zu:

{#,Reverse@#}&

Jetzt mischen wir diese mit RandomSample, um sie in zufälliger Reihenfolge zu verarbeiten. Join @@Reduziert die Liste der Paare, sodass wir eine Liste der Strahlen haben.

Kurze Pause: Um zu verfolgen, welche Punkte bereits gesperrt sind, verwenden wir eine Lookup-Funktion b, die Truefür alle Werte von initialisiert wird b@_=k=1>0;. Bei der Bearbeitung eines Strahls behalten wir alle Punkte bis zum ersten Punkt bei, der b[n] == False( einschließlich desjenigen) hat:

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

Ich bin der Meinung, dass dies der derzeit am besten geeignete Teil ist. Die Verwendung von zwei temporären Variablen zum Spielen von Mastermind scheint sehr teuer zu sein. Das Ergebnis gibt uns jedenfalls die Punkte in einer Linie, die wir zeichnen dürfen. Diese Funktion wird nun auf jeden dieser Punkte abgebildet:

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

Der erste Teil generiert die Liste aller 13 Punkte unter Verwendung der verschachtelten Ergebnisse von zwei Aufrufen nach CirclePoints(mit unterschiedlichen Radien für die Kantenmitten und die Ecken des Sechsecks). Beachten Sie, dass dadurch der b@#=!kWert der Nachschlagetabelle für den aktuellen Punkt Falseso festgelegt wird, dass kein weiterer Strahl durch den Punkt treten kann. Schließlich wird der Wert als Index in die Koordinatenliste übernommen, um den richtigen 2D-Punkt zu erhalten.

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

Dadurch werden alle Einzelelementlisten verworfen, da sie als einzelne (und sichtbare) Punkte gerendert werden. Zum Schluss rendern wir das Ergebnis:

Graphics[Line/@...]
Martin Ender
quelle
b@_=1>0=b=1>0&
CalculatorFeline
@CatsAreFluffy Ich glaube nicht, dass das funktioniert, da ich später einzelne Werte überschreiben muss.
Martin Ender
Gute Verwendung von CirclePoints.
DavidC
Ich schätze diesen Youtube-Link.
DanTheMan
8

Schuhe (Rubin) Rev. C 184 Bytes

Durch die Übertragung der Verantwortung für die Überprüfung, ob eine bestimmte halbe Linie vom Hauptprogramm zur Zeichenmethode gezogen werden soll, werden 12 Byte gespart. Das Hauptprogramm muss jedoch noch prüfen, ob die gesamte Leitung vollständig gesperrt ist.

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)}}

Schuhe (Ruby) 205 ... Rev B 196 Bytes

Shoes ist ein Ruby-basiertes Tool zum Erstellen von GUIs usw. Es ist das erste Mal, dass ich es verwendet habe. mothereff.in/byte-counter zählt meine Einsendung als 196 Bytes, aber aus irgendeinem Grund zählt Shoes sie als 202.

Außerdem können Sie mit Ruby Dinge tun t[a=i.ord], die seltsamerweise nicht wie erwartet mit Schuhen funktionieren.

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)}}

Erläuterung

Ich betrachte die Teile der Linie außerhalb des Sechsecks nicht. Ich zeichne nur den Teil, der gezeichnet werden muss. Wichtig ist, ob die Linien die Schnittpunkte kreuzen (Wenn wir nur die Teile zeichnen, die gezeichnet werden müssen, bedeutet dies, dass sie an den Schnittpunkten beginnen / enden.)

Die Grundregel lautet, dass, wenn beide Endpunkte einer Linie besucht wurden, die Linie gesperrt ist und nicht gezeichnet werden soll. Da die Linien in zwei Hälften gezeichnet werden, müssen wir auch prüfen, ob der Mittelpunkt besucht wurde, um festzustellen, ob jede Hälfte gezeichnet werden soll oder nicht.

Ich verfolge, welche Punkte im Array besucht wurden t[]. Dies endet mit einem Eintrag für jede physikalische Koordinate im darunter liegenden Raster. Es gibt kein separates logisches Array mit 13 Elementen. Am Ende t[]können 87 Elemente vorhanden sein, obwohl nur bis zu 13 nützliche Daten enthalten.

Intern werden die Koordinaten der Endpunkte der Linien durch eine einzelne Zahl z angegeben, wobei z% 6 die y-Koordinate und z / 6 die x-Koordinate ist. In diesem System ist das Sechseck abgeflacht. Wenn die Linien gezeichnet werden, wird die x-Skala mit 8 und die y-Skala mit 14 multipliziert, was eine sehr enge rationale Annäherung an das korrekte Verhältnis darstellt: 14/8 = 1,75 vs sqrt (3) = 1,732.

Das interne Koordinatensystem wird unten mit einigen Beispielausgaben gezeigt.

Bildbeschreibung hier eingeben

Ungolfed

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
    )
  }
}

Weitere Beispielausgaben

Diese wurden mit einer älteren Version des Programms durchgeführt. Der einzige Unterschied besteht darin, dass die Positionierung des Hexaglyphen im Fenster nun leicht abweicht.

Bildbeschreibung hier eingeben

Level River St
quelle
mothereff.in/byte-counter counts my submission as 196 bytes, but for some reason Shoes counts it as 202.Ich weiß nicht zu 100%, ob dies zutrifft, aber ich glaube, dass Shoes Ihren Code mit 202 Bytes anstatt mit 196 gezählt hat, weil Ihre Zeilenumbrüche tatsächlich eine zweistellige Folge "\ r \ n" sind. Dadurch wird jede neue Zeile zweimal gezählt. Hier ist eine Stapelüberlaufantwort bezüglich \ r und \ n.
K Zhang
Hehe, ich komme nicht über den Namen Ruby with Shoes XD
Beta Decay hinweg.
3

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

Ich habe die Idee von Level River St angepasst, zu überprüfen, ob eine Leitung blockiert wird, indem überprüft wird, ob beide Endpunkte der Leitung bereits zuvor besucht wurden. Das spart 27 Bytes. Golfvorschläge sind willkommen.

Edit: Bugfixing und Golfen g(p,q)für 3 Bytes. Golf Lfür ein Byte.

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

Die Hexaglyphen selbst sind recht klein, da wir ein 12-Pixel-Sechseck als Basis verwenden (aus Golfgründen). Hier sind einige Beispiele für Hexaglyphen (Entschuldigung für das schlechte Zuschneiden):

Ein Beispiel Hexaglyphe Ein Beispiel Hexaglyphe Ein Beispiel Hexaglyphe Ein Beispiel Hexaglyphe Ein Beispiel Hexaglyphe Ein Beispiel Hexaglyphe

Sherlock9
quelle
Könnte ein paar Bytes sparen:R=range;G=goto
Tim Čas