Визуализация вид сверху на модную крышу в ASCII


23

Сначала немного терминологии ( источник ):

  • Шатровая крыша является (цитирую Википедию) «тип крыши , где все края склона вниз к стенам, как правило , с довольно пологим наклоном»
  • Склон - это плоская поверхность, являющаяся частью крыши.
  • Гребень - это край, где встречаются два противоположных ската крыши
  • Бедро представляет собой выпуклый край, где встречаются два склона, принадлежащих перпендикулярным стенам
  • Долина - это вогнутый край, где встречаются два склона, принадлежащих перпендикулярным стенам.
  • Бедра и впадины должны совместно называться диагональными краями.

Возможный ввод:

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

Соответствующий вывод:

    +-------+   +---+   +-----------+
    |\     /|   |\ /|   |\         /|
    | \   / |   | 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 

1
Вы должны добавить больше тестовых случаев.
mbomb007

@ mbomb007 Добавлено. Учитывая пространство, которое они занимают - я должен добавить еще?
Джон Дворжак

@JanDvorak Может быть, добавить тестовый пример *. В противном случае это, вероятно, достаточно.
mbomb007

Является [[0,1,1],[1,0,1],[1,1,1]]действительным вход? (На входе нет «дыр», но есть досадный угол почти самопересечения.)
Линн

@ Линн Вам не нужно беспокоиться об этом случае, это неверный ввод. Упомянутый вами угол считается самопересекающейся границей (точнее, границей, которая не является кривой).
Джон Дворжак

Ответы:


11

Python 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

Надоело играть в гольф, и я получил хороший результат, так что вот оно.

Отступ с восемью пробелами - это вкладка.

Передайте двоичную матрицу через 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
Р. Кап
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.