Сначала немного терминологии ( источник ):
- Шатровая крыша является (цитирую Википедию) «тип крыши , где все края склона вниз к стенам, как правило , с довольно пологим наклоном»
- Склон - это плоская поверхность, являющаяся частью крыши.
- Гребень - это край, где встречаются два противоположных ската крыши
- Бедро представляет собой выпуклый край, где встречаются два склона, принадлежащих перпендикулярным стенам
- Долина - это вогнутый край, где встречаются два склона, принадлежащих перпендикулярным стенам.
- Бедра и впадины должны совместно называться диагональными краями.
Возможный ввод:
** * ***
********
** * **
Соответствующий вывод:
+-------+ +---+ +-----------+
|\ /| |\ /| |\ /|
| \ / | | V | | \ ^---< |
| \ / | | | | | \ / \ \|
+---+ V +---+ | +---+ X +---+
|\ \ | / \|/ \ / \ |
| >---> | <-------X-------V > |
|/ / | \ /|\ /| |
+---+ ^ +---+ | +-------+ | +---+
| / \ | | | | | |/ /|
| / \ | | ^ | | /---< |
|/ \| |/ \| |/ \|
+-------+ +---+ +-------+
Еще пара тестов:
** *** * * * *
* *** *****
** ***** *****
* * * *** *** ***
* **** * * *
Соответствующие выводы:
+-------+ +-----------+ +---+ +---+ +---+ +---+
|\ /| |\ /| |\ /| |\ /| |\ /| |\ /|
| \---< | | >-------< | | V | | V | | V | | X |
| |\ \| |/ \| | | | | | | | | | |/ \|
| | +---+ +-----------+ +---+ | +---+ | | +-----------+ | | +---+
| | | |\ \|/ /| | |/ \| |
| ^ | | \ V / | | < > |
|/ \| | \ / | | \ / |
+---+ +-------+ +---+ \ / +---+ | \-----------/ |
|\ /| |\ \ \ / / /| | |\ /| |
| >---/ | | >---> X <---< | | | \ / | |
|/ /| | |/ / / \ \ \| | | \ / | |
+---+ +---+ +---+ | | +---+ / \ +---+ +---+ ^ +---+ ^ +---+
|\ /| |\ /| | | | | / \ | |\ \ / \ | | / \ / /|
| V | | V | | | | | / ^ \ | | >---V > | | < V---< |
| | | | | | | | | |/ /|\ \| |/ /| | | |\ \|
| | | | | +-------+ | | +---+ | +---+ +-------+ | | | | +-------+
| | | | |/ \| | | | | | | | | | |
| ^ | | /-----------\ | | ^ | | ^ | | ^ |
|/ \| |/ \| |/ \| |/ \| |/ \|
+---+ +---------------+ +---+ +---+ +---+
Ваш ввод будет растровым изображением - двумерным массивом квадратных пикселей - области, которая должна быть покрыта крышей. Вы можете предположить, что граница этой области будет кривой Иордана, то есть непрерывной и не пересекающейся, то есть крытая область будет непрерывной, без отверстий и никогда не будет четырех стен, встречающихся в одной точке. Допустимые форматы ввода включают в себя одну строку с разделителями новой строки, список строк и двумерный массив символов или логических значений.
Правила строительства крыши :
- Каждый прямой участок крыши (далее именуемый стеной) должен иметь ровно один прилегающий уклон. Склон поднимется от стены. Каждый склон должен иметь по крайней мере одну прилегающую стену, а все стены, прилегающие к склону, должны быть коллинеарными.
- Все склоны должны иметь одинаковый (ненулевой) угол относительно горизонтальной поверхности. То есть они должны иметь одинаковую высоту.
- Склоны должны образовывать поверхность, граница которой является границей крыши. То есть никакие поверхности, кроме склонов, не могут быть использованы.
- Любой сценарий, в котором в данной спецификации допускается более одного решения (вплоть до вертикального масштабирования), считается ошибкой в спецификации. Любые исправления применяются задним числом.
Эквивалентно, крыша может быть определена правилом, согласно которому каждая точка крыши расположена как можно выше, не превышая максимальный уклон для этой крыши, измеренный с использованием расстояния Чебышева на виде сверху вниз.
Ваш вывод должен быть ASCII-изображением крыши - либо одной строкой, содержащей символы новой строки, либо массивом строк, каждая из которых обозначает одну строку вывода. Крыша должна быть визуализирована в виде сверху вниз в масштабе 4x, то есть каждый квадрат плана этажа должен воздействовать на область 5x5 на выходе так, чтобы углы этой области 5x5 были общими с соседними квадратами (так, чтобы каждый на символ угла влияют четыре различных квадрата ввода), как показано в примере вывода. Допускаются дополнительные пробелы, если сохранена выходная форма. Символы на выходе должны быть:
- должен использоваться маркер новой строки, определяемый средой (обычно U + 000A, U + 000D или пара обоих), если выходные данные представлены в виде одной строки
(Пространство U + 0020) представляет собой точку за пределами зоны крыши или внутреннюю точку склона
+
(Знак плюс U + 002B) представляет собой точку, к которой примыкают две перпендикулярные стены-
(U + 002D дефис-минус) представляет собой стену или гребень, ориентированный горизонтально (восток-запад)/
(U + 002F солидус) представляет собой бедро или долину, ориентированную с северо-востока на юго-восток, или точку, примыкающую к двум из них.<
(Знак минус 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]]
действительным вход? (На входе нет «дыр», но есть досадный угол почти самопересечения.)