먼저, 몇 가지 용어 ( 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
*
. 그렇지 않으면 충분할 것입니다.
[[0,1,1],[1,0,1],[1,1,1]]
유효한 입력은? (입력에는 "구멍"이 없지만 자기 교차로 근처에 성가신 코너가 있습니다.)