Disegna un hexa-glifo casuale


23

inserisci qui la descrizione dell'immagine

L'immagine sopra è chiamata hexa-glifo. Gli esa-glifi sono alcuni fantastici schemi che ho creato mentre scarabocchiavo durante la mia lezione DiffEq. Ecco come ne crei uno:

  1. Considera la seguente serie di punti, a forma di esagramma regolare. L'esagono interno è ciò che conterrà il glifo finale, mentre i 6 punti esterni formano una stella e sono dove inizieremo a disegnare le nostre linee.

inserisci qui la descrizione dell'immagine

  1. Dai sei punti esterni, seleziona casualmente una coppia. Per efficienza, dovrebbe esserci almeno un altro punto tra i due punti selezionati (altrimenti, non avrebbe alcun effetto sulla cifra finale). Quindi, da ciascuno dei due punti, lancia un raggio verso l'altro. Questo raggio è bloccato dalle righe precedenti.

inserisci qui la descrizione dell'immagine

  1. Ripetere questo processo fino a quando non sono stati formati tutti e 9 i bordi, come mostrato nelle prossime immagini.

inserisci qui la descrizione dell'immagine

  1. Ecco un esempio di raggi bloccati. Le estremità del segmento di raggio sono ancora visibili, ma la porzione centrale è occlusa dai primi due segmenti che abbiamo disegnato.

inserisci qui la descrizione dell'immagine

  1. Anche questi due raggi sono "bloccati", ma ciò non causa alcuna differenza visibile perché sono bloccati dalla stessa altra linea.

inserisci qui la descrizione dell'immagine

  1. Avanzamento rapido fino a quando non vengono tracciate tutte e 9 le linee. Se vuoi una spiegazione più dettagliata di questi passaggi saltati, posso esporre.

inserisci qui la descrizione dell'immagine

  1. Infine, rimuovi i punti della stella. Per renderlo più bello, vengono rimossi anche i punti spessi.

inserisci qui la descrizione dell'immagine

La sfida

La tua sfida è quella di produrre una rappresentazione visiva di un glifo-glifo casuale. Questo è code-golf, vince meno byte.

  1. Tutti i possibili glifi glifi dovrebbero apparire con qualche probabilità positiva. Diversi hexa-glifi vengono generati cambiando l'ordine in cui vengono disegnati i 9 bordi.

  2. Inoltre, tutte le immagini emesse dal tuo programma devono essere glifi glifi validi. Alcuni schemi (come un contorno completo dell'esagono interno) non possono apparire come un glifo-esfo, e quindi il programma non deve emetterli.

  3. L'output dovrebbe essere un'immagine grafica (stampata su schermo o file).

  4. L'esagono deve essere regolare, ma può apparire in qualsiasi orientamento.

  5. Riflessioni / rotazioni non sono considerate uniche. (Ciò potrebbe rendere il requisito 1 più semplice da seguire).


8
I made up while doodling during my DiffEq class. Il modo in cui avvengono tutte le grandi scoperte ...: P
Rɪᴋᴇʀ

Quali sono i requisiti minimi per l'immagine? Fino a che punto un'arte ASCII deve essere riconoscibile fintanto che ciascun bordo è rappresentato e posizionato vagamente nel punto giusto?
John Dvorak,

@JanDvorak Ho rimosso l'opzione di arte ASCII della sfida (come entro 2 minuti dalla pubblicazione) perché i programmi che producono arte ASCII e output grafici non sono facilmente comparabili.
PhiNotPi

che dire di pixel art allora? Un'intestazione PPM non è troppo pesante, e in seguito l'unica differenza è usare '01'con spazio interlacciato invece di ' *'.
John Dvorak,

@JanDvorak L'output sarebbe quindi un file di immagine formattato correttamente, giusto? Quindi non vedo nulla di sbagliato in questo.
PhiNotPi

Risposte:


18

Mathematica, 273 268 264 242 byte

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

Il rendering come apice Tin Mathematica ed è un operatore di trasposizione postfix.

Risolvere i bug in questo ha impiegato un'eternità ... verso la fine ho hackerato alcune cose insieme per farlo funzionare, quindi questo è decisamente non ottimale. Mi chiedo anche se nel complesso potrebbe essere meglio implementare le specifiche in modo più letterale attraverso le linee attraverso l'esagono esterno e lasciare che le funzioni geometriche di Mathematica gestiscano le intersezioni.

Si noti che questo è un programma completo e se si desidera eseguire il codice più volte in una singola sessione REPL, è necessario prefissarlo Clear[b].

Ecco i risultati di 20 corse:

inserisci qui la descrizione dell'immagine

Spiegazione

Questa soluzione non utilizza affatto i punti stella esterni. Funziona invece direttamente con i punti che fanno parte dell'esaglyph e le linee che ne coprono tre alla volta.

Etichettiamo i punti:

inserisci qui la descrizione dell'immagine

1inizia in un angolo leggermente strano ma ciò è dovuto al comportamento predefinito (anche un po 'strano) di CirclePoints. Iniziare l'esagono da lì si è rivelato più economico.

Ora vogliamo trovare le linee pertinenti attraverso tre di quei punti che corrispondono ai punti collegati della stella esterna. Quelli attorno all'esagono sono ovviamente solo 3 punti adiacenti (modulo 12), a partire da un numero dispari. Quelli sul centro sono costituiti da un numero pari n, 13e n+6.

Rappresentazioni di queste righe (sotto forma di elenchi di tre punti sono generati dal seguente codice):

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

Il Partitiongenera le linee attorno all'esagono e Arrayle linee attraverso il centro. Per elaborare entrambi i raggi, mappiamo questa funzione sull'elenco delle linee:

{#,Reverse@#}&

Ora li mescoliamo con RandomSampleper elaborarli in un ordine casuale. Join @@appiattisce l'elenco delle coppie in modo da avere un elenco di raggi.

Intervallo breve: per tenere traccia di quali punti sono già bloccati utilizziamo una funzione di ricerca b, che viene inizializzata Trueper tutti i valori da b@_=k=1>0;. Durante l'elaborazione di una trave manteniamo tutti i punti fino al primo punto che ha b[n] == False( incluso quello):

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

Sento che questa è la parte più giocabile in questo momento ... l'uso di due variabili temporanee per giocare a Mastermind sembra davvero costoso. Ad ogni modo, il risultato di questo ci dà i punti in una linea che possiamo disegnare. Ora questa funzione è mappata su ciascuno di questi punti:

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

La prima parte genera l'elenco di tutti i 13 punti usando i risultati interlacciati di due chiamate a CirclePoints(con raggi diversi per i centri del bordo e gli angoli dell'esagono). Nota b@#=!kche ora imposta il valore della tabella di ricerca per il punto corrente in Falsemodo che nessun ulteriore raggio possa attraversarlo. Infine, il valore viene utilizzato come indice nell'elenco delle coordinate per ottenere il punto 2D corretto.

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

Questo elimina tutti gli elenchi a singolo elemento, poiché verrebbero visualizzati come punti singoli (e visibili). Infine rendiamo il risultato:

Graphics[Line/@...]

b@_=1>0=b=1>0&
Calcolatrice

@CatsAreFluffy Non penso che funzioni, perché in seguito dovrò essere in grado di sovrascrivere i singoli valori.
Martin Ender,

Buon uso di CirclePoints.
DavidC

Ho apprezzato quel link di Youtube.
DanTheMan,

8

Scarpe (rubino) Rev C 184 byte

12 byte salvati trasferendo la responsabilità di verificare se una particolare mezza linea deve essere disegnata dal programma principale al metodo di disegno. Tuttavia, il programma principale deve ancora verificare se l'intera riga è completamente bloccata.

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

Scarpe (Ruby) 205 ... Rev B 196 byte

Shoes è uno strumento basato su rubini per la creazione di GUI, ecc. È la prima volta che lo uso. mothereff.in/byte-counter conta il mio invio come 196 byte, ma per qualche ragione Shoes lo conta come 202.

Inoltre, Ruby ti consente di fare cose come t[a=i.ord]ma stranamente, sembra non funzionare come previsto con Shoes.

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

Spiegazione

Non considero le parti della linea al di fuori dell'esagono. Disegno solo la parte che deve essere disegnata. L'importante è se le linee attraversano le intersezioni (se disegniamo solo le parti che devono essere disegnate, ciò significa che iniziano / finiscono alle intersezioni).

La regola di base è che se entrambi gli endpoint di una linea sono stati visitati, la linea viene bloccata e non deve essere tracciata. Dato che le linee sono tracciate in due metà, dobbiamo anche verificare se il punto medio è stato visitato per vedere se ogni metà deve essere tracciata o meno.

Tengo traccia di quali punti sono stati visitati nell'array t[]. Questo finisce per contenere una voce per ogni coordinata fisica sulla griglia sottostante. Non esiste un array logico separato da 13 elementi. Alla fine, t[]può contenere 87 elementi, sebbene solo fino a 13 conterrà dati utili.

Internamente, le coordinate dei punti finali delle linee sono date da un singolo numero z, dove z% 6 è la coordinata y e z / 6 è la coordinata x. In questo sistema l'esagono viene appiattito. Quando le linee sono tracciate, la scala x viene moltiplicata per 8 e la scala y viene moltiplicata per 14, che è un'approssimazione razionale molto vicina al rapporto corretto: 14/8 = 1,75 vs sqrt (3) = 1,732.

Il sistema di coordinate interno è mostrato di seguito, con alcuni output di esempio.

inserisci qui la descrizione dell'immagine

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

Altre uscite campione

Questi sono stati fatti con una versione precedente del programma. L'unica differenza è che il posizionamento dell'esaglyph nella finestra ora è leggermente diverso.

inserisci qui la descrizione dell'immagine


mothereff.in/byte-counter counts my submission as 196 bytes, but for some reason Shoes counts it as 202.Non so al 100% se questo è vero, ma penso che il motivo per cui Shoes ha contato il tuo codice come 202 byte anziché 196 è perché le tue righe sono in realtà una sequenza di due caratteri "\ r \ n". In questo modo ogni newline viene contata due volte. Ecco una risposta di overflow dello stack relativa a \ r e \ n.
K Zhang,

Hehe non riesco a superare il nome Ruby con Shoes XD
Decadimento beta

3

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

Ho adattato l'idea di Level River St di verificare se una linea verrà bloccata controllando se entrambi gli endpoint della linea sono già stati visitati in precedenza. Ciò consente di risparmiare 27 byte. Suggerimenti di golf benvenuti.

Modifica: correzione di bug e golf g(p,q)per 3 byte. Golfato Lper un 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

Gli stessi glifi-glifi sono piuttosto piccoli poiché utilizziamo un esagono di 12 pixel come base (per motivi di golf). Ecco alcuni esempi di hexa-glifi (scuse per il povero ritaglio):

Un esempio hexa-glifo Un esempio hexa-glifo Un esempio hexa-glifo Un esempio hexa-glifo Un esempio hexa-glifo Un esempio hexa-glifo


Potrebbe salvare qualche byte:R=range;G=goto
Tim Čas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.