Solución:
Kotlin, 283 218 octetos
Lambda sin nombre (con una función anidada, je).
Golf
{i:String,x:Int,y:Int->val m=i.lines().map{it.toCharArray()};fun v(x:Int,y:Int){try{if(m[y][x]=='#'){m[y][x]='%';for(c in-1..1)for(d in-1..1)if(!(c==0&&d==0))v(x+c,y+d)}}catch(e:Exception){}};v(x, y);m.map(::println)}
Sin golf
fun zombies(input: String, startX: Int, startY: Int) {
val m = input.lines().map(String::toCharArray) // build game map
fun invade(x: Int, y: Int) { // nested functions, woo!
try {
if (m[y][x] == '#') { // if land
m[y][x] = '%' // mark as invaded
for (dx in -1..1) { // generate neighbour tiles
for (dy in -1..1) {
if (!(dx == 0 && dy == 0)) {
invade(x + dx, y + dy) // attempt to invade neighbours
}
}
}
}
} catch(e: Exception) {} // catches ArrayIndexOutOfBounds
}
invade(startX, startY) // start the invasion
m.map(::println) // print final state
}
Se ahorraron bastantes bytes al cambiar a una solución recursiva.
JavaScript (ES6), 144 bytes
(s,x,y,l=s.search`n`,g=s=>s==(s=s.replace(eval(`/(#|%)(.?[^]{${l-1}}.?)?(?!\1)[#%]/`),`%$2%`))?s:g(s))=>g(s.slice(0,x+=y*l)+`%`+s.slice(x+1))
Dónde n
representa el carácter literal de nueva línea. Toma coordenadas con índice 0.
Befunge, 324 323 octetos
&00p&10p20p~$v<p02+g02*!g02:+1$$$$<
#<%>"P"/8+p>1+:::~:0`!#v_:85+`!#^_2%2%3*1+*2/:"P"%"P"/8+g+2/:"P"
:+**73"="+g00*g02g010$$$$<v
02:-<v/"P"%"P":/2::_|#:$<:+1+g02+g02:-1+g02:+1:-1:+1-g
:20g^>g:30p2%3*1+/4%1->#^_::2%6*2+30g+2/:"P"%"P"/p:20g-1-
0<v2g+8/"P"%"P":/2::<[email protected]#`0:-g
2^>%3*1+/4%1g,1+:20g%#^_1+55+,
¡Pruébelo en línea!
Explicación
Implementar esto en Befunge fue un poco complicado porque estamos limitados a 80×25 caracteres de “memoria” que deben compartirse con el código fuente. El truco para ajustar un mapa de 50×50 en esa área era aplanar el mapa 2D en una matriz 1D con dos ubicaciones de mapa por byte. Esta matriz 1D se vuelve a envolver en una matriz 2D para que pueda caber en el ancho de 80 caracteres del campo de juego de Befunge.
El algoritmo de infección comienza convirtiendo las coordenadas iniciales en un desplazamiento en la matriz 1D que empuja a la pila. El bucle principal toma un valor de la pila y busca el estado del mapa para ese desplazamiento. Si es tierra no infectada, se marca como infectada y se introducen ocho nuevas compensaciones en la pila (que representan la tierra alrededor de la posición actual). Este proceso continúa hasta que la pila está vacía.
Para evitar tener que buscar valores fuera de rango, el mapa se almacena con un borde de agua de un carácter alrededor de todos los bordes.