По-перше, деяка термінологія ( джерело ):
- Шатровий дах є (цитую Вікіпедію) «тип даху , де всі краї схилу вниз до стін, як правило , з досить пологим нахилом»
- Схил - це плоска поверхня, яка є частиною даху
- Хребет - це край, де зустрічаються два протилежні схили даху
- Стегно - це опуклий край, де зустрічаються два схили, що належать до перпендикулярних стінок
- Долина - це увігнутий край, де зустрічаються два схили, що належать до перпендикулярних стін
- Стегна і долини разом називаються діагональними ребрами.
Можливий вхід:
** * ***
********
** * **
Відповідний вихід:
+-------+ +---+ +-----------+
|\ /| |\ /| |\ /|
| \ / | | V | | \ ^---< |
| \ / | | | | | \ / \ \|
+---+ V +---+ | +---+ X +---+
|\ \ | / \|/ \ / \ |
| >---> | <-------X-------V > |
|/ / | \ /|\ /| |
+---+ ^ +---+ | +-------+ | +---+
| / \ | | | | | |/ /|
| / \ | | ^ | | /---< |
|/ \| |/ \| |/ \|
+-------+ +---+ +-------+
Ще кілька тестових випадків:
** *** * * * *
* *** *****
** ***** *****
* * * *** *** ***
* **** * * *
Відповідні результати:
+-------+ +-----------+ +---+ +---+ +---+ +---+
|\ /| |\ /| |\ /| |\ /| |\ /| |\ /|
| \---< | | >-------< | | V | | V | | V | | X |
| |\ \| |/ \| | | | | | | | | | |/ \|
| | +---+ +-----------+ +---+ | +---+ | | +-----------+ | | +---+
| | | |\ \|/ /| | |/ \| |
| ^ | | \ V / | | < > |
|/ \| | \ / | | \ / |
+---+ +-------+ +---+ \ / +---+ | \-----------/ |
|\ /| |\ \ \ / / /| | |\ /| |
| >---/ | | >---> X <---< | | | \ / | |
|/ /| | |/ / / \ \ \| | | \ / | |
+---+ +---+ +---+ | | +---+ / \ +---+ +---+ ^ +---+ ^ +---+
|\ /| |\ /| | | | | / \ | |\ \ / \ | | / \ / /|
| V | | V | | | | | / ^ \ | | >---V > | | < V---< |
| | | | | | | | | |/ /|\ \| |/ /| | | |\ \|
| | | | | +-------+ | | +---+ | +---+ +-------+ | | | | +-------+
| | | | |/ \| | | | | | | | | | |
| ^ | | /-----------\ | | ^ | | ^ | | ^ |
|/ \| |/ \| |/ \| |/ \| |/ \|
+---+ +---------------+ +---+ +---+ +---+
Вашим вкладом буде растрова карта - двовимірний масив квадратних пікселів - площі, яку слід покрити дахом. Ви можете припустити, що межею цієї області буде крива Йордану - тобто безперервна та непересічна, що перетинається - тобто дахова ділянка буде суцільною, без дірок, і ніколи не буде зустрічатися чотири стіни в одній точці. Дійсні формати введення включають один рядок з роздільниками нового рядка, списком рядків та 2D масивом символів або булів.
Правила будівництва даху :
- Кожен прямий відрізок покрівельної ділянки (відтепер називається стіною) повинен мати рівно один сусідній ухил. Ухил повинен підніматися від стіни. Кожен схил повинен мати принаймні одну сусідню стіну, а всі стіни, що прилягають до схилу, повинні бути колінеарними.
- Усі схили повинні мати однаковий (ненульовий) кут щодо горизонтальної поверхні. Тобто вони повинні мати однаковий крок.
- Схили утворюють поверхню, межа якої є межею даху. Тобто ніякі поверхні, крім схилів, не можуть використовуватися.
- Будь-який сценарій, де дана специфікація дозволено більше ніж одне рішення (до вертикального масштабування), вважається помилкою у специфікації. Будь-які виправлення застосовуються заднім числом.
Еквівалентно дах може бути визначений правилом, що кожну точку даху розміщують якомога вище, не перевищуючи максимальний нахил даної покрівлі, виміряний, використовуючи відстань Чебишева у вигляді зверху вниз.
Ваш вихід повинен бути ASCII мистецтво подання даху - або одна рядки , що містить символи нового рядка або масив рядків, кожна з позначають одну рядки виведення. Дах повинен бути виведений вгорі вгору в масштабі 4х - тобто кожен квадрат планування поверху повинен впливати на 5х5 площу виходу, щоб кути цієї площі 5х5 були спільними з сусідніми квадратами (таким, що кожен на кутовий символ впливають чотири різні вхідні квадрати), як зазначено у прикладі виводу. Додатковий пробіл дозволений до тих пір, поки збережена форма виводу. Символи на виході повинні бути:
- слід використовувати визначений середовищем маркер нового рядка (зазвичай U + 000A, U + 000D або пара обох), якщо вихід є у вигляді однієї рядка
(Простір U + 0020) являє собою точку поза покрівельною ділянкою або точкову внутрішню частину до схилу
+
(Знак U + 002B плюс) являє собою точку з двома перпендикулярними стінками, прилеглими до неї-
(U + 002D дефіс-мінус) являє собою стіну або кряж, орієнтовані горизонтально (схід-захід)/
(U + 002F solidus) являє собою стегно або долину, орієнтовану на північний схід на південний схід, або точку, прилеглу до двох із них<
(U + 003C менше знака) являє собою точку з двома діагональними ребрами, прилеглими до неї на сході>
(U + 003E більший за знак) являє собою точку з двома діагональними ребрами, прилеглими до неї на захід\
(U + 005C зворотний солідус) являє собою стегно або долину, орієнтовану з північного заходу на південний схід, або точку, прилеглу до двох із них^
(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]]
дійсний вхід? (На вході немає «дірок», але є кумедний кут біля самопересічення.)