힙 지붕의 하향식 뷰를 ASCII로 렌더링


23

먼저, 몇 가지 용어 ( source ) :

  • 고관절 지붕 (위키 인용)는 "지붕의 종류 여기서 벽 사방 경사 아래쪽 보통 비교적 완만"
  • 경사는 지붕의 일부인 평면 표면입니다.
  • 능선은 두 개의 반대 지붕 경사가 만나는 가장자리입니다.
  • 엉덩이는 수직 벽에 속하는 두 개의 경사가 만나는 볼록한 가장자리입니다.
  • 계곡은 수직 벽에 속하는 두 개의 경사가 만나는 오목한 모서리입니다.
  • 엉덩이와 골을 총칭하여 대각선 가장자리라고합니다.

가능한 입력 :

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

해당 출력 :

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

몇 가지 테스트 사례 :

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

해당 출력 :

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

입력 정사각형 픽셀의 2D 배열 - - 루프에 포함되어야하는 영역의 비트 맵이 될 것이다. 이 영역의 경계가 연속적이고 자체 교차하지 않는 요르단 곡선이라고 가정 할 수 있습니다. 즉, 지붕이있는 영역은 구멍이없고 연속적이며 단일 지점에서 4 개의 벽이 만나지 않습니다. 유효한 입력 형식에는 줄 바꾸기 구분 기호가있는 단일 문자열, 문자열 목록 및 2D 배열의 문자 또는 부울이 포함됩니다.

지붕을 짓는 규칙 은 다음과 같습니다.

  • 지붕 면적의 각 직선 세그먼트 (이후 벽이라고 함)는 정확히 하나의 인접한 경사를 가져야합니다. 경사는 벽에서 멀어져 야합니다. 각 경사면에는 인접한 벽이 하나 이상 있어야하며 경사면에 인접한 모든 벽은 동일 선상에 있어야합니다.
  • 모든 경사면은 수평면에 대해 동일한 (0이 아닌) 각도를 가져야합니다. 즉, 동일한 피치를 가져야합니다.
  • 경사는 경계가 지붕 면적의 경계인 표면을 형성해야합니다. 즉, 경사 이외의 표면은 사용될 수 없다.
  • 이 스펙에서 둘 이상의 솔루션 (수직 스케일링까지)이 허용되는 모든 시나리오는 스펙의 버그로 간주됩니다. 모든 수정 사항은 소급 적용됩니다.

마찬가지로, 지붕은 위에서 아래로 볼 때 체비 쇼프 거리 를 사용하여 측정 된 지붕의 최대 경사를 초과하지 않고 지붕의 각 지점이 가능한 한 높게 배치되는 규칙에 의해 정의 될 수 있습니다 .

출력 개행 문자 또는 문자열의 배열을 포함하는 단일 스트링 중 각 출력의 한 라인을 나타내는 - 지붕의 ASCII 아트 표현한다. 지붕은 4x 스케일로 하향식보기로 렌더링되어야합니다. 즉, 평면도의 각 정사각형은 출력의 5x5 영역에 영향을 주어이 5x5 영역의 모서리가 인접한 정사각형과 공유되도록합니다 (각각 예제 출력에서 ​​알 수 있듯이 모서리 문자는 네 개의 다른 입력 사각형의 영향을받습니다. 출력 모양이 유지되는 한 추가 공백이 허용됩니다. 출력되는 문자는 다음과 같아야합니다.

  • 출력이 단일 문자열 형태 인 경우 환경 정의 개행 마커 (보통 U + 000A, U + 000D 또는 둘 다)를 사용해야합니다.
  • (U + 0020 공간)은 지붕 영역 외부의 점 또는 경사 내부의 점을 나타냅니다.
  • + (U + 002B 더하기 부호)는 두 개의 수직 벽이 인접한 점을 나타냅니다.
  • - (U + 002D 하이픈-마이너스)는 수평 (동 서쪽) 방향의 벽 또는 융기 부를 나타냅니다
  • / (U + 002F solidus)는 북동쪽에서 남동쪽으로 향한 엉덩이 또는 계곡 또는 그 중 두 지점에 인접한 지점을 나타냅니다.
  • < (U + 003C 부호보다 작음)은 동쪽에 인접한 두 개의 대각선 가장자리가있는 점을 나타냅니다.
  • > (U + 003E보다 큰 부호)는 서쪽에 두 개의 대각선 가장자리가 인접한 점을 나타냅니다.
  • \ (U + 005C reverse solidus)는 북서쪽에서 남동쪽으로 향한 고관절 또는 계곡 또는 그 중 2 개에 인접한 점을 나타냅니다.
  • ^ (U + 005E 곡절 악센트)는 남쪽에 인접한 두 개의 대각선 가장자리가있는 점을 나타냅니다.
  • V (U + 0056 라틴 대문자 v)는 북쪽에서 두 개의 대각선 가장자리가 인접한 점을 나타냅니다.
  • X (U + 0058 라틴 대문자 x)는 사방에 대각선 가장자리가 인접한 점을 나타냅니다.
  • | (U + 007C 세로 막대)는 세로 방향 (북-남)으로 벽 또는 융기 부분을 나타냅니다.

홀수의 대각선 가장자리가 같은 지점에서 끝나는 것은 불가능합니다 (벽 제외). 각 점의 주변을 북쪽 경사 + 남쪽 경사 및 동쪽 경사 + 서쪽 경사로 분할하여 시각화 할 수 있습니다. 두 파티션 사이의 경계는 대각선 가장자리로 구성되어야합니다.

환경에서 ASCII와 호환되지 않는 문자 인코딩을 사용하는 경우 환경에서 사용하는 문자 인코딩에 동등한 문자 (동일한 문자 모양 또는 가장 가까운 문자)를 사용할 수 있습니다.

Ruby에서 다음과 같은 (추악한) 참조 구현 은 공백이 아닌 출력과 관련하여 규범 적입니다. 특히 render방법에 유의하십시오 .

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
더 많은 테스트 사례를 추가해야합니다.
mbomb007

@ mbomb007 추가되었습니다. 그들이 차지하는 공간이 주어지면 더 추가해야합니까?
John Dvorak

@JanDvorak 테스트 케이스를 추가하십시오 *. 그렇지 않으면 충분할 것입니다.
mbomb007

[[0,1,1],[1,0,1],[1,1,1]]유효한 입력은? (입력에는 "구멍"이 없지만 자기 교차로 근처에 성가신 코너가 있습니다.)
Lynn

@Lynn이 경우에 대해 걱정할 필요가 없습니다. 유효한 입력이 아닙니다. 언급 한 모서리는 자체 교차 경계 (또는 곡선이 아닌 경계)로 계산됩니다.
John Dvorak

답변:


11

파이썬 2, 500 바이트

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

골프를 타는 것에 지 쳤고, 나는 좋은 라운드 점수를 얻었습니다. 그래서 여기 있습니다.

8 칸 들여 쓰기는 탭입니다.

다음과 같이 STDIN을 통해 이진 행렬을 전달하십시오.

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]]"

완전히 골프를 타거나하지 않는 것은 놀라운 일입니다. 잘 했어. +1
R. Kap
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.