Jadikan tampilan top-down atap hip di ASCII

23

Pertama, beberapa terminologi ( sumber ):

  • Sebuah atap pinggul adalah (mengutip Wikipedia) "jenis atap di mana semua pihak kemiringan ke bawah ke dinding, biasanya dengan kemiringan yang cukup lembut"
  • Kemiringan adalah permukaan planar yang merupakan bagian dari atap
  • Bubungan adalah tepi tempat dua lereng atap yang berseberangan bertemu
  • Pinggul adalah tepi cembung di mana dua lereng yang dimiliki oleh dinding tegak lurus bertemu
  • Sebuah lembah adalah tepi cekung di mana dua lereng yang dimiliki oleh dinding tegak lurus bertemu
  • Pinggul dan lembah secara kolektif disebut sebagai tepi diagonal.

Masukan yang mungkin:

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

Output yang sesuai:

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

Beberapa kasus tes lagi:

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

Output yang sesuai:

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

Input Anda akan berupa bitmap - array 2D piksel persegi - dari area yang harus ditutup oleh atap. Anda dapat mengasumsikan batas area ini adalah kurva Jordan - yaitu, kontinu dan tidak berpotongan-sendiri - yaitu, area beratap akan kontinu, tanpa lubang dan tidak akan pernah ada empat dinding yang bertemu pada satu titik. Format input yang valid termasuk string tunggal dengan pemisah baris baru, daftar string dan array karakter atau boole 2D.

Aturan membangun atap adalah:

  • Setiap segmen lurus dari area beratap (untuk selanjutnya disebut sebagai dinding) harus memiliki tepat satu lereng yang berdampingan. Kemiringan akan menjauh dari dinding. Setiap lereng harus memiliki setidaknya satu dinding yang bersebelahan, dan semua dinding yang bersebelahan dengan lereng harus berbentuk collinear.
  • Semua lereng harus memiliki sudut yang sama (bukan nol) terhadap permukaan horizontal. Artinya, mereka harus memiliki nada yang sama.
  • Lereng harus membentuk permukaan yang batasnya adalah batas area beratap. Artinya, tidak ada permukaan selain lereng yang dapat digunakan.
  • Setiap skenario di mana lebih dari satu solusi (hingga penskalaan vertikal) diizinkan oleh spesifikasi ini dianggap sebagai bug dalam spesifikasi. Setiap koreksi berlaku surut.

Secara ekivalen, atap dapat didefinisikan dengan aturan bahwa setiap titik atap ditempatkan setinggi mungkin tanpa melebihi kemiringan maksimum untuk atap itu yang diukur dengan menggunakan jarak Chebyshev dalam tampilan top-down.

Output Anda harus berupa representasi seni ASCII dari atap - baik string tunggal yang berisi karakter baris baru atau array string, masing-masing menunjukkan satu baris output. Atap akan ditampilkan dalam tampilan top-down pada skala 4x - yaitu, setiap kuadrat denah lantai harus memengaruhi area 5x5 dari output sehingga sudut-sudut area 5x5 ini dibagi dengan kotak tetangga (sehingga masing-masing karakter sudut dipengaruhi oleh empat kotak input yang berbeda), seperti ditunjukkan oleh contoh output. Ruang kosong ekstra diizinkan selama bentuk output dipertahankan. Karakter yang ditampilkan adalah:

  • penanda baris baru yang ditetapkan lingkungan harus digunakan (biasanya U + 000A, U + 000D atau sepasang keduanya) jika output dalam bentuk string tunggal
  • (Ruang U + 0020) mewakili titik di luar area beratap atau interior titik ke lereng
  • + (U + 002B tanda plus) mewakili titik dengan dua dinding tegak lurus berdampingan dengannya
  • - (U + 002D tanda hubung minus) mewakili dinding atau punggungan yang berorientasi horizontal (timur-barat)
  • / (U + 002F solidus) mewakili pinggul atau lembah yang berorientasi timur laut ke tenggara, atau titik yang disatukan dengan dua di antaranya.
  • < (U + 003C tanda kurang dari) merupakan titik dengan dua tepi diagonal yang disatukan di sebelah timur
  • > (U + 003E lebih besar dari tanda) mewakili titik dengan dua tepi diagonal yang disatukan di sebelah barat
  • \ (U + 005C membalikkan solidus) mewakili pinggul atau lembah yang berorientasi barat laut ke tenggara, atau titik yang disatukan dengan dua di antaranya.
  • ^ (U + 005E aksen sirkumfleksa) mewakili titik dengan dua tepi diagonal yang disatukan di selatan
  • V (U + 0056 huruf kapital latin v) merupakan titik dengan dua tepi diagonal yang disatukan di sebelah utara
  • X (U + 0058 huruf latin x) mewakili titik dengan tepi diagonal yang disatukan di keempat sisinya
  • | (U + 007C batang vertikal) mewakili dinding atau punggungan yang berorientasi secara vertikal (utara-selatan)

Perhatikan bahwa tidak mungkin jumlah tepi diagonal ganjil berakhir pada titik yang sama (kecuali di dinding). Kita dapat memvisualisasikannya dengan mempartisi lingkungan dari setiap titik ke lereng utara + lereng selatan dan ke lereng timur + lereng barat. Batas antara kedua partisi harus terdiri dari tepi diagonal.

Jika lingkungan Anda menggunakan pengkodean karakter yang tidak kompatibel dengan ASCII, Anda dapat menggunakan karakter yang setara (mesin terbang yang sama atau terdekat yang tersedia) dalam pengkodean karakter yang digunakan lingkungan Anda.

Implementasi referensi berikut (jelek) di Ruby adalah normatif sehubungan dengan output non-spasi. Perhatikan khususnya rendermetode ini:

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 
John Dvorak
sumber
1
Anda harus menambahkan lebih banyak test case.
mbomb007
@ mbomb007 Ditambahkan. Mengingat ruang yang mereka ambil - haruskah saya tambahkan lagi?
John Dvorak
@ JanDvorak Mungkin menambahkan test case *. Kalau tidak, itu mungkin sudah cukup.
mbomb007
Apakah [[0,1,1],[1,0,1],[1,1,1]]input yang valid? (Input tidak memiliki "lubang", tetapi ada sudut sial di dekat persimpangan-sendiri.)
Lynn
@ Lynn Anda tidak perlu khawatir tentang hal itu, itu bukan input yang valid. Sudut yang Anda sebutkan tidak dihitung sebagai batas berpotongan-sendiri (atau lebih tepatnya, batas yang bukan kurva).
John Dvorak

Jawaban:

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

Lelah bermain golf, dan saya mendapat skor bulat yang bagus, jadi ini dia.

Lekukan delapan spasi adalah tab.

Lewatkan matriks biner di atas STDIN, seperti:

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]]"
Lynn
sumber
Sepenuhnya bermain golf atau tidak, ini luar biasa. Sudah selesai dilakukan dengan baik. +1
R. Kap