Ricerca dei quadrati in marcia


9

Marching Squares è un algoritmo di computer grafica, che viene utilizzato per recuperare isocontours 2D da una griglia di campioni (vedi anche il suo fratello maggiore Marching Cubes per le impostazioni 3D). L'idea è di elaborare ogni cella della griglia in modo indipendente e determinare i contorni che attraversano quella cella in base ai valori ai suoi angoli.

Il primo passo in questo processo è determinare quali bordi sono collegati da contorni, in base al fatto che gli angoli siano al di sopra o al di sotto del valore del contorno. Per semplicità, prenderemo in considerazione solo i contorni lungo il valore 0, in modo tale da interessarci se gli angoli sono positivi o negativi. Ci sono casi per distinguere:24 = 16

inserisci qui la descrizione dell'immagine
Fonte immagine: Wikipedia

L'identificazione di bianco e nero non ha molta importanza qui, ma per sicurezza dire che il bianco è positivo e il nero è negativo. Ignoreremo i casi in cui uno degli angoli è esattamente 0.

I punti della sella (casi 5 e 10) forniscono una piccola difficoltà in più: non è chiaro quali diagonali debbano essere usate solo guardando gli angoli. Questo può essere risolto trovando la media dei quattro angoli (cioè un'approssimazione del valore centrale) e scegliendo le diagonali in modo tale che i contorni separino il centro dagli angoli con il segno opposto. Se la media è esattamente 0, è possibile scegliere entrambi i casi.

Normalmente, questi 16 casi sono semplicemente memorizzati in una tabella di ricerca. Questo è ottimo per l'efficienza, ma ovviamente preferiremmo che il codice fosse breve qui. Quindi il tuo compito è quello di eseguire questo passaggio di ricerca e stampare una rappresentazione ASCII del caso nel minor codice possibile.

La sfida

Ti vengono dati i valori dei quattro angoli (numeri interi diversi da zero) in un ordine fisso a tua scelta. Dovresti quindi generare il layout corretto dei contorni, risolvendo correttamente i casi dei punti della sella.

È possibile scrivere un programma o una funzione, prendendo l'input tramite STDIN (o l'alternativa più vicina), l'argomento della riga di comando o l'argomento della funzione e producendo il risultato tramite STDOUT (o l'alternativa più vicina), il valore di ritorno della funzione o il parametro della funzione (out).

L'input può essere preso in qualsiasi formato stringa o elenco conveniente.

I 16 casi saranno rappresentati nell'arte ASCII usando uno dei seguenti blocchi 5x5:

o---o  o---o  o---o
|   |  |   |  | | |
|   |  |---|  | | |
|   |  |   |  | | |
o---o  o---o  o---o

o---o  o---o  o---o  o---o
|/  |  |  \|  |   |  |   |
|   |  |   |  |   |  |   |
|   |  |   |  |\  |  |  /|
o---o  o---o  o---o  o---o

o---o  o---o
|/  |  |  \|
|   |  |   |
|  /|  |\  |
o---o  o---o

Non è necessario stampare spazi bianchi iniziali o finali, ma è possibile stampare una nuova riga opzionale.

Questo è il golf del codice, quindi vince la risposta più breve (in byte).

Casi test

I casi di test presuppongono che l'input sia dato nell'ordine in alto a sinistra , in alto a destra , in basso a sinistra , in basso a destra . I casi di test sono presentati in 9 gruppi, uno corrispondente a ciascuna delle 9 rappresentazioni fornite sopra (nello stesso ordine, a partire dalla cella vuota, per finire con i due punti della sella).

[1, 2, 1, 3]
[-9, -2, -2, -7]

[4, 5, -1, -2]
[-1, -2, 3, 4]

[7, -7, 7, -7]
[-5, 5, -5, 5]

[1, -6, -4, -1]
[-2, 3, 3, 4]

[-1, 6, -4, -1]
[2, -3, 3, 4]   

[-1, -6, 4, -1]
[2, 3, -3, 4]

[-1, -6, -4, 1]
[2, 3, 3, -4]

[3, -8, -9, 2]
[-3, 8, 9, -2]

[8, -3, -2, 9]
[-8, 3, 2, -9]

Inoltre, i seguenti casi di test possono restituire uno dei punti della sella (a scelta):

[1, -4, -2, 5]
[-1, 4, 2, -5]

Risposte:


4

Rubino, 201 180 176

Questa è una funzione lambda anonima, da chiamare nel modo mostrato nell'esempio non golfato.

Questo non contiene variabili s. Nella versione non golfata viene assegnata un'espressione complessa sper chiarezza, prima che venga utilizzata. 4 byte vengono salvati nella versione golfata mettendola in linea. L'unica altra differenza tra le versioni è lo spazio bianco e i commenti.

Se è accettabile restituire l'output come un array di cinque stringhe di cinque caratteri, anziché stampare su stdout, è possibile salvare un altro byte.

->a{p=t=0
4.times{|i|t+=a[i]*=a[3];p+=a[i]>>9&1<<i}
q=p==6&&t>0?19:'@AC@P*10'[p].ord
puts c='o---o',(0..2).map{|i|b=p*i==3?'|---|':'|   |';b[q%4]='|/|\|/'[q%4+(i&2)];q/=4;b},c}

Sono soddisfatto dell'analisi dell'array, ma penso che potrebbero esserci modi più brevi per formare l'output.

Tutti e quattro gli elementi dell'array di input vengono moltiplicati per l'ultimo elemento. Ciò garantisce che l'ultimo elemento sia positivo e riduce il numero di casi da 16 a 8. Gli elementi sono spostati in 9 posizioni, in modo che tutti i numeri positivi diventino 0 e tutti i numeri negativi diventino -1 (almeno nell'intervallo di input dati nei casi di test). Vengono quindi AND 1<<array indexper fornire un numero binario a 3 bit che indica il modello (in realtà a 4 bit, ma poiché l'ultimo elemento è sempre positivo, il 4o bit è sempre zero).

Questo numero da 0 a 7 viene quindi inviato a una tabella di ricerca (sospiro) per determinare quali caratteri di ogni riga sono non bianchi. È in questa fase che vengono gestiti i due diversi display per la custodia da sella, con un'alternativa al numero nella tabella di ricerca utilizzato se il totale è positivo (la domanda dice di considerare la "media", ma poiché siamo solo interessato al segno, non importa se consideriamo invece il totale.)

Il modo in cui funziona la visualizzazione dell'output è chiaro dai commenti nel codice.

non golfato nel programma di test

f=->a{p=t=0
  4.times{|i|                      #for each number in the input
    t+=a[i]*=a[3];                   #multiply each number by a[3]; totalize the sum in t
    p+=a[i]>>9&1<<i                  #shift right to find if negative; AND with 1<<i to build index number for pattern 
  }                                #q is a 3-digit base 4 number indicating which character of each line is non-whitespace (if any). 
  q=p==6&&t>0?19:'@AC@P*10'[p].ord #It's encoded in the magic string, except for the case of saddles with a positive total, which is encoded by the number 19.
  s=(0..2).map{|i|                 #build an array of 3 strings, indexes 0..2
    b=p*i==3?'|---|':'|   |';        #IF p is 3 and we are on row 1, the string is |---| for the horizontal line case. ELSE it is |   |.
    b[q%4]='|/|\|/'[q%4+(i&2)];      #The numbers in q indicate which character is to be modified. The characters in the string indicate the character to replace with.
    q/=4;                            #If q%4=0, the initial | is replaced by | (no change.) i&2 shifts the string index appropriately for the last row.
    b                                #divide q by 4, and terminate the loop with the expression b so that this is the object loaded into array s.  
  }
puts c='o---o',s,c}                #print the array s, capped with "o---o" above and below.


[[1, 2, 1, 3],
[-9, -2, -2, -7],

[4, 5, -1, -2],
[-1, -2, 3, 4],

[7, -7, 7, -7],
[-5, 5, -5, 5],

[1, -6, -4, -1],
[-2, 3, 3, 4],

[-1, 6, -4, -1],
[2, -3, 3, 4],

[-1, -6, 4, -1],
[2, 3, -3, 4],

[-1, -6, -4, 1],
[2, 3, 3, -4],

[3, -8, -9, 2],
[-3, 8, 9, -2],

[8, -3, -2, 9],
[-8, 3, 2, -9],

[1, -4, -2, 5],
[-1, 4, 2, -5]].each{|k|f.call(k)}
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.