Percorsi casuali idraulici


23

Scrivi un programma o una funzione che accetta tre numeri interi, una larghezza w, un'altezza he un conteggio dei passi s. Disegnerai una camminata casuale non autointersecante slungo su un'immagine 5*wper 5*hpixel in cui ogni cella di 5 per 5 pixel è vuota (beige puro) o una di queste dodici semplici "pipe":

tubi allargati

L'immagine sopra è ingrandita per mostrare i dettagli. Ecco i tubi di dimensioni reali:

tubi

(Le linee grigie servono solo a separare i tipi di tubo.)

La camminata casuale sarà un singolo percorso di tubo continuo che inizia in corrispondenza di un punto finale del tubo (uno dei quattro tipi di tubo in basso) e termina in un altro punto finale del tubo.

Inizia con un vuoto wdih griglia e scegli casualmente una cella come punto di partenza. Quindi scegli una delle quattro direzioni in modo casuale per iniziare e disegnare il punto finale del tubo corrispondente. Questa cella iniziale segna il primo passo della tua camminata e ogni volta che disegni una nuova cella o ne sovrascrivi una esistente, conta come un altro passo fatto.

Ora, ripetutamente, scegli casualmente di andare a destra, a sinistra o dritto, disegnando la cella del tubo appropriata se la direzione scelta è valida. Tornare indietro e scegliere nuovamente se una direzione non è valida fino a quando non sviene formato il percorso completo . Il percorso dovrebbe terminare con un endpoint del tubo, che potrebbe trovarsi in qualsiasi punto della griglia, a seconda del percorso seguito dal percorso.

È molto importante notare che solo le due celle a tubo diritto possono essere sovrascritte e solo dalla cella a tubo diritto con orientamento opposto, il risultato è una cella di intersezione. Altrimenti, tutti i tubi devono essere posizionati in celle vuote.

Quando viene disegnata un'intersezione, la parte del percorso che si trova più lontano dalla cella iniziale deve essere disegnata in alto.

Spetta a te se la griglia ha o meno condizioni al contorno periodiche (PBC), ovvero se un tubo che esce da un lato della griglia uscirà dall'altro lato. Senza PBC il confine della griglia conta come una barriera che puoi incontrare proprio come le altre pipe.

Casi speciali

  • Quando sè 0 senza tubi devono essere compilati e l'uscita dovrebbe essere uno sbozzato 5*wda5*h immagine (cioè tutto beige).
  • Quando sè 1 un moncone monotubo

    troncone tubo allargato(Dimensioni reali: troncone per tubo)

    dovrebbe essere disegnato nella cella iniziale scelta casualmente.

Altri dettagli

  • Puoi supporre che ssia al massimo w*hquindi un percorso sarà sempre possibile. (Anche se sono possibili percorsi più lunghi a causa delle intersezioni.)
  • we hsarà sempre positivo.
  • Tutte le scelte casuali devono essere uniformemente casuali. ad es. non dovresti evitare di fare intersezioni quando sono possibili anche se questo semplifica il problema. Sono consentiti generatori di numeri pseudo-casuali.
  • È possibile utilizzare tre colori visivamente distinti al posto del nero, del blu e del beige.
  • Le tue immagini di output possono essere ingrandite in modo che siano realmente 5*w*kdi 5*h*kpixel in cui kè un numero intero positivo. (Si consiglia di ingrandire qualsiasi esempio che pubblichi anche se hai k1.)
  • È possibile utilizzare qualsiasi formato di file immagine lossless comune e l'immagine può essere salvata in un file, visualizzata o emessa grezza su stdout.

Vince il codice più breve in byte.

Esempi

(Tutto ampliato del 500%.)

Se l'ingresso è w=2, h=1, s=0allora l'uscita sarà sempre:

Se l'input è w=2, h=1, s=1allora l'output sarà una di queste immagini con uguale probabilità:

Se l'ingresso è w=2, h=1, s=2allora l'uscita sarà

o forse

se si presume che la griglia abbia PBC.

(Notare che l'avvio di un percorso del genere renderebbe impossibile un secondo passo.)


Ecco alcune possibili uscite per w=3, h=2, s=6, supponendo PBC:


Ecco un possibile output per w=3, h=3, s=9, supponendo PBC:

Si noti che il percorso non ha dovuto coprire tutte le celle a causa dell'intersezione che conta come due passaggi. Inoltre, possiamo dedurre che l'endpoint dell'angolo era la cella iniziale poiché il cavalcavia dell'intersezione deve essere stato disegnato in seguito. Quindi possiamo dedurre la sequenza di scelte casuali fatte:

start at top left, facing east
go straight
go right
go right
go right
go straight
go left
go right
end

Infine, ecco alcuni esempi di w=4, h=5, s=20e w=4, h=5, s=16:


1
L'intera idea è solo una passeggiata casuale, giusto?
Akangka,

Riga 2: You will be drawing a non-self-intersecting random walk... è autointersecante o no?
edc65,

@ChristianIrwan Beh, non proprio. Le passeggiate casuali di solito possono raddoppiare su se stesse o non intersecarsi affatto. Questo è un caso unico poiché vengono fatte intersezioni ma non contano come ripercorrere lo stesso terreno. E sì, questo potrebbe essere in un formato ASCII-Art o qualcosa del genere, ma mi piace l'idea di creare immagini dall'aspetto gradevole.
Calvin's Hobbies,

2
@ChristianIrwan Ho già risposto che quando ho detto "E sì, questo potrebbe essere in un formato ASCII-Art o qualcosa del genere, ma mi piace l'idea di creare immagini dall'aspetto gradevole". Ho scelto di non coinvolgere ascii-art.
Hobby di Calvin il

1
I "nodi" sono ammessi?
aditsu,

Risposte:


4

CJam, 274

q~:K;:B;:A;{0aA*aB*:M5*5f*:I;K{[Bmr:QAmr:P]5f*:R;3Ym*{R.+:)2{1$0=I=2$W=@tI@0=@t:I;}:F~}/R2f+1FK({MQ=P=:EY4mr:D#&1{{MQMQ=PE2D#+tt:M;}:G~7,1>[W0_1_0_W]2/D=:Off*{[QP]5f*2f+.+_:H1F_OW%.+2FOW%.m2F}/H2FO~P+:P;Q+:Q;MQ=P=:E_5YD2%-*=!JK2-=+*1{D2+4%:D;G}?}?}fJ]}0?}g'P2NA5*SI,N2NI:+N*

Provalo online

Utilizza PBC, output in formato PGM. È possibile rimuovere :+quasi alla fine per ottenere un output visivo più gradevole nel browser.

È molto lento per input più grandi, specialmente se il conteggio dei passi è vicino all'area.

Esempio di risultato per l'input 4 3 10(ridimensionato del 500%):

esempio

Breve spiegazione:

L'approccio generale è:

  • ripetere tutti i seguenti passaggi fino al completamento:
  • inizializza 2 matrici: una registra quali lati vengono utilizzati in ciascuna cella e una per l'immagine
  • se s = 0, abbiamo finito, altrimenti:
  • scegli una cella casuale e disegna un quadrato, quindi esegui le seguenti s-1 volte:
  • scegli una direzione casuale; se quel lato è già utilizzato, fallire e ricominciare
  • segna il lato come usato e disegna il tubo reale nell'immagine (disegnando 3 linee adiacenti di lunghezza 6, iniziando a destra "dopo" il pixel centrale della cella corrente, quindi aggiungendo un punto per chiudere l'estremità del tubo)
  • aggiorna la posizione corrente (passando alla cella successiva)
  • controlla se la cella è vuota o è un incrocio valido; in caso contrario, fallire e ricominciare
  • segna il lato nella direzione opposta come usato in questa cella, quindi continua il ciclo

1

QBasic, 517 516 byte

RANDOMIZE TIMER
SCREEN 9
INPUT w,h,s
1CLS
IF s=0GOTO 9
x=5*INT(RND*w)
y=5*INT(RND*h)
GOSUB 7
FOR k=1TO s-1
r=INT(RND*4)+1
a=x+5*((r=2)-(r=4))
b=y+5*((r=1)-(r=3))
c=(POINT(a,b+2)*POINT(a+4,b+2)+POINT(a+2,b)*POINT(a+2,b+4))*(0=POINT((a+x)\2+2,(b+y)\2+2))
IF((0=POINT(a+2,b+2))+c)*(a>=0)*(b>=0)*(a<5*w)*(b<5*h)=0GOTO 1
x=a
y=b
GOSUB 7
o=1AND r
p=x-2+3*o-5*(r=2)
q=y+1-3*o-5*(r=1)
u=p+3-o
v=q+2+o
LINE(p,q)-(u,v),7,B
LINE(p+o,q+1-o)-(u-o,v-1+o),1
NEXT
9IF c GOTO 1
END
7LINE(x+1,y+1)-(x+3,y+3),7,B
PSET(x+2,y+2),1
RETURN
  • Prende w, he sdall'input dell'utente, separato da virgola.
  • L'output viene disegnato sullo schermo. Mentre il programma è alla ricerca di una soluzione, è possibile che le soluzioni parziali sfarfallino.
  • Non utilizza condizioni al contorno periodiche. Ho trovato più facile disegnare e testare i tubi di collegamento senza doversi preoccupare che metà del tubo si trovasse da un lato della griglia e metà dall'altro.

L'approccio qui è quello di provare una direzione casuale ad ogni passo e ricominciare dall'inizio se risulta in una mossa non valida. Disegniamo i tubi quando vengono decise le direzioni e li usiamo POINTper testare i punti sullo schermo per le nostre condizioni di validità. Una mossa è valida se non va oltre i confini della griglia e:

  1. La cella spostata in è vuota; o
  2. Tutti e due
    1. La cella spostata contiene un tubo che passa dritto, sia in orizzontale che in verticale, e
    2. La nuova sezione del tubo non raddoppia una sezione del tubo esistente

Come la risposta CJam di aditsu , questo codice è molto lento e può essere incredibilmente lento se sè una frazione significativa di w*h. Nella mia configurazione di QB64, viene fornita una risposta 5,5,19abbastanza rapidamente, ma impiega più tempo di quanto volessi aspettare5,5,20 .

Se vuoi eseguire esempi più grandi / più densi, ecco il mio approccio originale usando una ricerca approfondita . È molto più efficiente, al costo di ben 300 byte extra.

RANDOMIZE TIMER
SCREEN 9
INPUT w,h,s
DIM t(s),m(s)
0
FOR z=1TO s
t(z)=-1
NEXT
i=5*INT(RND*w)
j=5*INT(RND*h)
k=1
1CLS
IF s=0GOTO 9
x=i
y=j
GOSUB 7
FOR z=1TO k-1
r=m(z)
GOSUB 6
x=a
y=b
GOSUB 7
o=1AND r
p=x-2+3*o-5*(r=2)
q=y+1-3*o-5*(r=1)
u=p+3-o
v=q+2+o
LINE(p,q)-(u,v),7,B
LINE(p+o,q+1-o)-(u-o,v-1+o),1
NEXT
IF c*(k=s)THEN k=k-1:GOTO 1 ELSE IF k=s GOTO 9
IF k<1GOTO 0
IF t(k)>=0GOTO 4
t(k)=0
f=30
WHILE f
r=INT(RND*4)+1
IF f AND 2^r THEN t(k)=t(k)*5+r:f=f-2^r
WEND
4r=t(k)MOD 5
m(k)=r
t(k)=t(k)\5
GOSUB 6
c=(POINT(a,b+2)*POINT(a+4,b+2)+POINT(a+2,b)*POINT(a+2,b+4))*(0=POINT((a+x)\2+2,(b+y)\2+2))
IF((0=POINT(a+2,b+2))+c)*(a>=0)*(b>=0)*(a<5*w)*(b<5*h)THEN k=k+1 ELSE IF t(k)>0GOTO 4 ELSE t(k)=-1:k=k-1
GOTO 1
6a=x+5*((r=2)-(r=4))
b=y+5*((r=1)-(r=3))
RETURN
7LINE(x+1,y+1)-(x+3,y+3),7,B
PSET(x+2,y+2),1
RETURN
9

Esempio di output per input 10, 10, 100, dimensione effettiva:Impianto idraulico casuale 10x10

Una versione ancora più elaborata è disponibile in questa sintesi . Oltre ad essere ungolf e commentato a fondo, aumenta l'output di un fattore costante e consente un ritardo impostato tra i passaggi, consentendo di guardare l'algoritmo DFS al lavoro. Ecco un esempio:

deluxe plumbing.bas in azione

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.