Primero, alguna terminología ( fuente ):
- Un techo de cadera es (citando Wikipedia) "un tipo de techo donde todos los lados se inclinan hacia las paredes, generalmente con una pendiente bastante suave"
- Una pendiente es una superficie plana que forma parte del techo.
- Una cresta es un borde donde se encuentran dos pendientes opuestas del techo
- Una cadera es un borde convexo donde se encuentran dos pendientes que pertenecen a paredes perpendiculares
- Un valle es un borde cóncavo donde se encuentran dos pendientes que pertenecen a paredes perpendiculares
- Las caderas y los valles se denominarán colectivamente bordes diagonales.
Posible entrada:
** * ***
********
** * **
Salida correspondiente:
+-------+ +---+ +-----------+
|\ /| |\ /| |\ /|
| \ / | | V | | \ ^---< |
| \ / | | | | | \ / \ \|
+---+ V +---+ | +---+ X +---+
|\ \ | / \|/ \ / \ |
| >---> | <-------X-------V > |
|/ / | \ /|\ /| |
+---+ ^ +---+ | +-------+ | +---+
| / \ | | | | | |/ /|
| / \ | | ^ | | /---< |
|/ \| |/ \| |/ \|
+-------+ +---+ +-------+
Un par de casos de prueba más:
** *** * * * *
* *** *****
** ***** *****
* * * *** *** ***
* **** * * *
Salidas correspondientes:
+-------+ +-----------+ +---+ +---+ +---+ +---+
|\ /| |\ /| |\ /| |\ /| |\ /| |\ /|
| \---< | | >-------< | | V | | V | | V | | X |
| |\ \| |/ \| | | | | | | | | | |/ \|
| | +---+ +-----------+ +---+ | +---+ | | +-----------+ | | +---+
| | | |\ \|/ /| | |/ \| |
| ^ | | \ V / | | < > |
|/ \| | \ / | | \ / |
+---+ +-------+ +---+ \ / +---+ | \-----------/ |
|\ /| |\ \ \ / / /| | |\ /| |
| >---/ | | >---> X <---< | | | \ / | |
|/ /| | |/ / / \ \ \| | | \ / | |
+---+ +---+ +---+ | | +---+ / \ +---+ +---+ ^ +---+ ^ +---+
|\ /| |\ /| | | | | / \ | |\ \ / \ | | / \ / /|
| V | | V | | | | | / ^ \ | | >---V > | | < V---< |
| | | | | | | | | |/ /|\ \| |/ /| | | |\ \|
| | | | | +-------+ | | +---+ | +---+ +-------+ | | | | +-------+
| | | | |/ \| | | | | | | | | | |
| ^ | | /-----------\ | | ^ | | ^ | | ^ |
|/ \| |/ \| |/ \| |/ \| |/ \|
+---+ +---------------+ +---+ +---+ +---+
Su entrada será un mapa de bits, una matriz 2D de píxeles cuadrados, del área que debe estar cubierta por el techo. Puede suponer que el límite de esta área será una curva de Jordania, es decir, continua y sin intersección propia, es decir, el área cubierta será continua, sin agujeros y nunca habrá cuatro paredes que se unan en un solo punto. Los formatos de entrada válidos incluyen una sola cadena con separadores de nueva línea, una lista de cadenas y una matriz 2D de caracteres o booleanos.
Las reglas para construir el techo son:
- Cada segmento recto del área cubierta (de ahora en adelante denominado muro) debe tener exactamente una pendiente contigua. La pendiente se levantará lejos de la pared. Cada pendiente debe tener al menos un muro contiguo, y todos los muros adyacentes a una pendiente deben ser colineales.
- Todas las pendientes deben tener el mismo ángulo (distinto de cero) contra la superficie horizontal. Es decir, deben tener el mismo tono.
- Las pendientes formarán una superficie cuyo límite es el límite del área cubierta. Es decir, no se pueden utilizar otras superficies que no sean las pendientes.
- Cualquier escenario en el que esta especificación permita más de una solución (hasta escala vertical) se considera un error en la especificación. Cualquier corrección se aplica retroactivamente.
De manera equivalente, el techo puede definirse por la regla de que cada punto del techo se coloca lo más alto posible sin exceder la pendiente máxima para ese techo, medido utilizando la distancia de Chebyshev en una vista de arriba hacia abajo.
Su salida será una representación artística ASCII del techo, ya sea una sola cadena que contenga caracteres de nueva línea o una matriz de cadenas, cada una de las cuales denota una sola línea de la salida. El techo se debe representar en una vista de arriba hacia abajo a una escala de 4x, es decir, cada cuadrado del plano de planta debe afectar un área de 5x5 de la salida de modo que las esquinas de esta área de 5x5 se compartan con los cuadrados vecinos (de modo que cada el carácter de esquina se ve afectado por cuatro cuadrados de entrada diferentes), como lo indica la salida de ejemplo. Se permite un espacio en blanco adicional siempre que se conserve la forma de salida. Los caracteres en la salida serán:
- se utilizará un marcador de nueva línea definido por el entorno (generalmente U + 000A, U + 000D o un par de ambos) si la salida tiene la forma de una sola cadena
(Espacio U + 0020) representa un punto fuera de un área cubierta o un punto interior a una pendiente
+
(U + 002B signo más) representa un punto con dos paredes perpendiculares adyacentes-
(U + 002D guión-menos) representa un muro o una cresta orientada horizontalmente (este-oeste)/
(U + 002F solidus) representa una cadera o un valle orientado de nordeste a sureste, o un punto contiguo a dos de esos<
(U + 003C menor que el signo) representa un punto con dos bordes diagonales unidos al este>
(U + 003E mayor que el signo) representa un punto con dos bordes diagonales unidos al oeste\
(U + 005C solidus inverso) representa una cadera o un valle orientado del noroeste al sureste, o un punto contiguo a dos de esos^
(U + 005E acento circunflejo) representa un punto con dos bordes diagonales unidos al surV
(U + 0056 letra mayúscula latina v) representa un punto con dos bordes diagonales unidos al norteX
(U + 0058 letra mayúscula latina x) representa un punto con bordes diagonales unidos a él en los cuatro lados|
(U + 007C barra vertical) representa una pared o una cresta orientada verticalmente (norte-sur)
Tenga en cuenta que no es posible que un número impar de aristas diagonales termine en el mismo punto (excepto en paredes). Podemos visualizar eso dividiendo la vecindad de cada punto en la pendiente norte + pendiente sur y en la pendiente este + pendiente oeste. El límite entre ambas particiones tiene que estar compuesto de bordes diagonales.
Si su entorno utiliza una codificación de caracteres incompatible con ASCII, puede utilizar los caracteres equivalentes (el mismo glifo o el más cercano disponible) en la codificación de caracteres que utiliza su entorno.
La siguiente implementación de referencia (fea) en Ruby es normativa con respecto a la salida sin espacios en blanco. Tenga en cuenta particularmente el render
método:
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
*
. De lo contrario, probablemente sea suficiente.
[[0,1,1],[1,0,1],[1,1,1]]
una entrada válida? (La entrada no tiene "agujeros", pero hay una esquina molesta cerca de la auto-intersección.)