以ASCII渲染臀部屋顶的俯视图


23

首先,一些术语(来源):

  • 一个坡屋顶的(引自维基百科)“一个类型的屋顶,所有边向下倾斜的墙壁,通常有一个相当缓坡”
  • 斜坡是作为屋顶一部分的平面
  • 脊是两个相对的屋顶坡相交的边缘
  • 臀部是凸边,属于垂直壁的两个坡度相交
  • 山谷是凹边,属于垂直壁的两个坡面汇合
  • 臀部和山谷统称为对角线边缘。

可能的输入:

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

对应的输出:

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

还有几个测试用例:

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

相应的输出:

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

您的输入将是屋顶应覆盖区域的位图-正方形像素的2D数组。您可能会假设此区域的边界为约旦曲线-即连续且非自相交-也就是说,屋顶区域将是连续的,没有孔,并且单个点永远不会有四面墙相遇。有效的输入格式包括带有换行符的单个字符串,字符串列表以及2D字符或布尔数组。

建造屋顶的规则是:

  • 屋顶区域的每个直段(以下称为墙)应恰好有一个相邻的坡度。斜坡应远离墙壁。每个斜坡都应至少有一个邻接的壁,并且邻接一个斜坡的所有壁必须共线。
  • 所有斜面与水平面的夹角应相同(非零)。也就是说,它们必须具有相同的音高。
  • 斜坡应形成其边界为屋顶区域边界的表面。即,除了坡度之外,不能使用其他表面。
  • 本规范允许使用多个解决方案(最大垂直缩放)的任何情况都被视为规范中的错误。任何更正均追溯适用。

等效地,可以通过以下规则来定义屋顶:将屋顶的每个点放置在尽可能高的位置,而不会超过使用自顶向下视图中的切比雪夫距离测量的那个屋顶的最大斜率。

您的输出应为屋顶的ASCII艺术表现形式-包含换行符的单个字符串或字符串数​​组,每个字符串表示输出的一行。屋顶应以自顶向下的视图以4倍的比例进行渲染-也就是说,平面图的每个正方形都应影响输出的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'9

@ mbomb007添加。给定他们占用的空间-我应该再增加一点吗?
John Dvorak

@JanDvorak也许添加测试用例*。否则,这可能就足够了。
mbomb007'9

[[0,1,1],[1,0,1],[1,1,1]]有效的输入?(输入没有“空洞”,但是附近自我相交处有一个讨厌的角。)
Lynn 16'9

@Lynn您不必担心这种情况,它不是有效的输入。您提到的拐角确实算作自相交的边界(或更确切地说,不是曲线的边界)。
John Dvorak

Answers:


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
R. Kap
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.