Rendering della vista dall'alto verso il basso di un tetto a padiglione in ASCII


23

Innanzitutto, alcuni termini ( fonte ):

  • Un tetto a padiglione è (citando Wikipedia) "un tipo di tetto in cui tutti i lati inclinano verso il basso verso le pareti, di solito con una pendenza abbastanza delicata"
  • Una pendenza è una superficie piana che fa parte del tetto
  • Una cresta è un bordo in cui si incontrano due pendenze del tetto opposte
  • Un fianco è un bordo convesso in cui si incontrano due pendii appartenenti a pareti perpendicolari
  • Una valle è un bordo concavo in cui si incontrano due pendii appartenenti a pareti perpendicolari
  • I fianchi e le valli devono essere definiti collettivamente come bordi diagonali.

Possibile input:

 ** * ***
******** 
 ** *  **

Uscita corrispondente:

    +-------+   +---+   +-----------+
    |\     /|   |\ /|   |\         /|
    | \   / |   | V |   | \   ^---< |
    |  \ /  |   | | |   |  \ / \   \|
+---+   V   +---+ | +---+   X   +---+
|\   \  |  /     \|/     \ / \  |
| >---> | <-------X-------V   > |
|/   /  |  \     /|\         /| |
+---+   ^   +---+ | +-------+ | +---+
    |  / \  |   | | |       | |/   /|
    | /   \ |   | ^ |       | /---< |
    |/     \|   |/ \|       |/     \|
    +-------+   +---+       +-------+

Un altro paio di casi di test:

** ***   *    *   * *
*       ***   *****  
    ** *****  *****  
* *  *  ***  *** *** 
* ****   *     * *   

Uscite corrispondenti:

+-------+   +-----------+           +---+               +---+           +---+   +---+
|\     /|   |\         /|           |\ /|               |\ /|           |\ /|   |\ /|
| \---< |   | >-------< |           | V |               | V |           | V |   | X |
| |\   \|   |/         \|           | | |               | | |           | | |   |/ \|
| | +---+   +-----------+       +---+ | +---+           | | +-----------+ | |   +---+
| | |                           |\   \|/   /|           | |/             \| |
| ^ |                           | \   V   / |           | <               > |
|/ \|                           |  \     /  |           |  \             /  |
+---+           +-------+   +---+   \   /   +---+       |   \-----------/   |
                |\     /|   |\   \   \ /   /   /|       |   |\         /|   |
                | >---/ |   | >--->   X   <---< |       |   | \       / |   |
                |/   /| |   |/   /   / \   \   \|       |   |  \     /  |   |
+---+   +---+   +---+ | |   +---+   /   \   +---+   +---+   ^   +---+   ^   +---+
|\ /|   |\ /|       | | |       |  /     \  |       |\   \ / \  |   |  / \ /   /|
| V |   | V |       | | |       | /   ^   \ |       | >---V   > |   | <   V---< |
| | |   | | |       | | |       |/   /|\   \|       |/       /| |   | |\       \|
| | |   | | +-------+ | |       +---+ | +---+       +-------+ | |   | | +-------+
| | |   | |/         \| |           | | |                   | | |   | | |
| ^ |   | /-----------\ |           | ^ |                   | ^ |   | ^ |
|/ \|   |/             \|           |/ \|                   |/ \|   |/ \|
+---+   +---------------+           +---+                   +---+   +---+

Il tuo input sarà una bitmap - una matrice 2D di pixel quadrati - dell'area che dovrebbe essere coperta dal tetto. Si può presumere che il confine di quest'area sarà una curva della Giordania - cioè, continua e non autointersecante - cioè l'area coperta sarà continua, senza buchi e non ci saranno mai quattro pareti che si incontrano in un unico punto. I formati di input validi includono una singola stringa con separatori newline, un elenco di stringhe e un array 2D di caratteri o booleani.

Le regole per la costruzione del tetto sono:

  • Ogni segmento rettilineo dell'area coperta (d'ora in poi denominato muro) deve avere esattamente una pendenza adiacente. La pendenza deve alzarsi dal muro. Ogni pendenza deve avere almeno una parete adiacente e tutte le pareti adiacenti a una pendenza devono essere collineari.
  • Tutte le pendenze devono avere lo stesso angolo (diverso da zero) rispetto alla superficie orizzontale. Cioè, devono avere lo stesso tono.
  • Le pendenze devono formare una superficie il cui confine è il confine dell'area coperta. Cioè, nessuna superficie diversa dalle pendenze può essere utilizzata.
  • Qualsiasi scenario in cui più di una soluzione (fino al ridimensionamento verticale) è consentito da questa specifica è considerato un bug nella specifica. Eventuali correzioni si applicano retroattivamente.

Equivalentemente, il tetto può essere definito dalla regola secondo cui ciascun punto del tetto è posizionato il più in alto possibile senza superare la pendenza massima per quel tetto misurata usando la distanza di Chebyshev in vista dall'alto verso il basso.

Il tuo output deve essere una rappresentazione in arte ASCII del tetto - una singola stringa contenente caratteri di nuova riga o una matrice di stringhe, ognuna delle quali indica una singola riga dell'output. Il tetto deve essere reso in vista dall'alto verso il basso su una scala 4x, ovvero ogni quadrato della pianta del pavimento dovrebbe interessare un'area 5x5 dell'uscita in modo tale che gli angoli di questa area 5x5 siano condivisi con i quadrati vicini (in modo tale che il carattere dell'angolo è influenzato da quattro diversi quadrati di input), come indicato dall'output di esempio. Spazio bianco extra è consentito purché la forma di output sia preservata. I caratteri in uscita devono essere:

  • deve essere usato un marker newline definito dall'ambiente (di solito U + 000A, U + 000D o una coppia di entrambi) se l'output ha la forma di una singola stringa
  • (U + 0020 spazio) rappresenta un punto esterno a un'area coperta o un punto interno a una pendenza
  • + (U + 002B segno più) rappresenta un punto con due pareti perpendicolari adiacenti
  • - (U + 002D trattino-meno) rappresenta una parete o una cresta orientata orizzontalmente (est-ovest)
  • / (U + 002F solidus) rappresenta un'anca o una valle orientata da nord-est a sud-est, o un punto attiguo a due di quelli
  • < (U + 003C segno meno di) rappresenta un punto con due bordi diagonali adiacenti ad est
  • > (U + 003E maggiore del segno) rappresenta un punto con due bordi diagonali adiacenti ad esso a ovest
  • \ (U + 005C solidus inverso) rappresenta un'anca o una valle orientata da nord-ovest a sud-est, o un punto attiguo a due di quelli
  • ^ (Accento circonflesso U + 005E) rappresenta un punto con due bordi diagonali adiacenti ad esso a sud
  • V (U + 0056 lettera maiuscola latina v) rappresenta un punto con due bordi diagonali adiacenti ad esso a nord
  • X (U + 0058 lettera maiuscola latina x) rappresenta un punto con bordi diagonali adiacenti su tutti e quattro i lati
  • | (U + 007C barra verticale) rappresenta una parete o una cresta orientata verticalmente (nord-sud)

Si noti che non è possibile che un numero dispari di bordi diagonali finisca nello stesso punto (tranne sui muri). Possiamo visualizzarlo suddividendo il vicinato di ciascun punto in pendenza nord + pendenza sud e in pendenza est + pendenza ovest. Il confine tra le due partizioni deve essere composto da bordi diagonali.

Se l'ambiente utilizza una codifica dei caratteri incompatibile con ASCII, è possibile utilizzare i caratteri equivalenti (stesso glifo o il più vicino disponibile) nella codifica dei caratteri utilizzata dal proprio ambiente.

La seguente (brutta) implementazione di riferimento in Ruby è normativa rispetto all'output di spazi non bianchi. Nota in particolare il rendermetodo:

def pad ary
  row = ary.first.map{-1}
  ([row] + ary + [row]).map{|r| [-1] + r + [-1]}
end

def parse str
  str.split("\n").map{|r| r.chars.map(&{" " => -1, "*" => Float::INFINITY})}
end

def squares ary, size
  ary.each_cons(size).map do |rows|
    rows.map{|row| row.each_cons(size).to_a}.transpose
  end
end

def consmap2d ary, size
  squares(ary, size).map{|sqrow| sqrow.map{|sq| yield sq}}
end

def relax ary
  loop do
    new = consmap2d(pad(ary), 3){|sq| sq[1][1] == -1 ? -1 : sq.flatten.min + 1}
    return new if new == ary
    ary = new
  end
end

def semidouble ary, op
  ary.zip(ary.each_cons(2).map{|r1,r2|r1.zip(r2).map(&op)}).flatten(1).compact.transpose
end

def heightmap str
  relax(semidouble(semidouble(semidouble(semidouble(pad(parse str),:max),:max),:min),:min))
end

def render heightmap
  puts consmap2d(heightmap, 3){|sq|
    next " " if sq[1][1] == -1
    hwall = sq[0][1] == -1 || sq[2][1] == -1
    vwall = sq[1][0] == -1 || sq[1][2] == -1
    next "+" if hwall && vwall
    next "-" if hwall
    next "|" if vwall
    next "+" if sq.flatten.min == -1

    nws = sq[0][1] == sq[1][0]
    nes = sq[0][1] == sq[1][2]
    sws = sq[2][1] == sq[1][0]
    ses = sq[2][1] == sq[1][2]

    next "X"  if nws && nes && sws && ses
    next "V"  if nws && nes
    next "^"  if sws && ses
    next ">"  if nws && sws
    next "<"  if nes && ses
    next "/"  if nes && sws
    next "\\" if nws && ses
    next " "  if sq[0][1] != sq[2][1] || sq[1][0] != sq[1][2]
    next "|"  if sq[0][1] == sq[1][1]
    next "-"  if sq[1][0] == sq[1][1]
    ??
  }.map(&:join)
end

render heightmap $<.read if __FILE__ == $0 

1
È necessario aggiungere altri casi di test.
mbomb007,

@ mbomb007 Aggiunto. Dato lo spazio che occupano, dovrei aggiungere altro?
John Dvorak,

@JanDvorak Forse aggiungi il caso di test *. Altrimenti probabilmente è abbastanza.
mbomb007,

L' [[0,1,1],[1,0,1],[1,1,1]]input è valido? (L'ingresso non ha "buchi", ma c'è un fastidioso angolo quasi autointersezione.)
Lynn

@Lynn Non devi preoccuparti di quel caso, non è un input valido. L'angolo menzionato conta come un confine autointersecante (o meglio, un confine che non è una curva).
John Dvorak,

Risposte:


11

Python 2, 500 byte

z=input()
W=4*len(z[0])+1
H=4*len(z)+1
R=range
s=[-~W*[0]for _ in R(-~H)]
for y in R(H/4):
 for x in R(W/4):
        for h in R(25):s[y*4+h%5][x*4+h/5]|=z[y][x]
F=[(x/3-1,x%3-1)for x in[1,7,3,5,0,6,8,2]]
exec'for y in R(H):\n for x in R(W):s[y][x]+=0<s[y][x]<=min(s[y+d][x+e]for(e,d)in F)\n'*H
for y in R(H):
 l=''
 for x in R(W):h=s[y][x];a=[s[y+d][x+e]for(e,d)in F[:4]];l+=r' XabcVde^f ||g>h\\+//+<<jk<l//+\\+>>m --^^oVVqrX'[h and int(''.join(`int(n==h)`for n in a),2)*3+((h==1)*2or max(a)==h)+1]
 print l

Stanco di giocare a golf, e ho ottenuto un bel punteggio rotondo, quindi eccolo qui.

Il rientro di otto spazi è una scheda.

Passa una matrice binaria su STDIN, in questo modo:

python2.7 roof.py <<<"[[1,1,0,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0], [1,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,0], [0,0,0,0,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,0], [1,0,1,0,0,1,0,0,1,1,1,0,0,1,1,1,0,1,1,1], [1,0,1,1,1,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0]]"

Completamente golf o no, questo è fantastico. Molto bene. +1
R. Kap
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.