Perl 5 , -p0
105 101 96 93 90 89 bytes
Utiliza en b
lugar de 1
en la entrada.
Asegúrese de que la matriz en STDIN termine con una nueva línea
#!/usr/bin/perl -p0
s%b%$_="$`z$'";s:|.:/
/>s#(\pL)(.{@{-}}|)(?!\1)(\pL)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg
Pruébalo en línea!
Utiliza 3 niveles de sustitución!
Esta versión de 87 bytes es más fácil de interpretar en formato de entrada y salida, pero no compite ya que utiliza 3 caracteres diferentes en la salida:
#!/usr/bin/perl -0p
s%b%$_="$`z$'";s:|.:/
/>s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg
Pruébalo en línea!
Es fácil guardar otro byte (el s
modificador regex ) en ambas versiones usando algún carácter diferente (no alfanumérico) como terminador de fila (en lugar de nueva línea), pero eso hace que la entrada sea completamente ilegible nuevamente.
Cómo funciona
Considera la sustitución
s#(\w)(.{columns}|)(?!1)(\w)#c$2c#s
Esto encontrará dos letras que son diferentes y una al lado de la otra horizontal y verticalmente y las reemplazará por c
. En un laberinto cuyas rutas consisten completamente en la letra, b
no pasará nada, ya que las letras son las mismas, pero tan pronto como una de las letras sea reemplazada por otra (por ejemplo z
), esa letra y un vecino serán reemplazados por c
una aplicación repetida. relleno de inundación del componente conectado con la c
semilla z
.
En este caso, sin embargo, no quiero un relleno de inundación completo. Quiero llenar solo uno de los brazos vecinos z
, así que después del primer paso quiero que se z
vaya. Eso ya funciona con el c$2c
reemplazo, pero luego quiero reiniciar un relleno de inundación a lo largo de otro brazo a partir del mismo punto y ya no sé cuál de los c
s era originalmente z
. Entonces en su lugar uso
s#(\w)(.{columns}|)(?!\1)(\w)#$&|a.$2.a#se
b | a
es c
, b | c
es c
y z | a
es {
. Por lo tanto, en un laberinto con caminos formados b
y una semilla z
en el primer paso b
será reemplazada por c
y z
será reemplazada por una {
que no es una letra y no coincide \w
y, por lo tanto, no causará más rellenos. Sin c
embargo, esto mantendrá un nuevo llenado de inundación y un brazo vecino de la semilla se llenará. Ej. A partir de
b c
b c
bbzbb becomes bb{bb
b b
b b
Entonces puedo reemplazar todo c por alguna letra que no sea (por ejemplo -
) y reemplazar {
de z
nuevo para reiniciar el relleno de inundación:
- -
- -
bbzbb becomes cc{bb
b b
b b
y repita este proceso hasta que todos los vecinos de la semilla se hayan convertido. Si luego, una vez más, reemplazo {
por z
y relleno de inundación:
- -
- -
--z-- stays --z--
- -
- -
Los z
restos quedan al final porque no hay ningún vecino con el que hacer una transformación. Eso deja en claro lo que sucede en el siguiente fragmento de código:
/\n/ >
Encuentra la primera línea nueva. El desplazamiento inicial ahora está en@-
s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se
La expresión regular discutida anteriormente con el @{-}
número de columnas (ya que simple @-
confunde el analizador perl y no sustituye adecuadamente)
&&
El /\n/
siempre tiene éxito y la sustitución es verdadera siempre que podamos llenarnos de inundaciones. Por lo tanto, la parte posterior &&
se ejecuta si se completa el relleno de un brazo. Si no, el lado izquierdo se evalúa como una cadena vacía
y/{c/z / > 0
Reinicie el relleno de inundación y devuelva 1 si el relleno de inundación anterior hizo algo. De lo contrario, devuelva la cadena vacía. Todo este código está envuelto dentro
s:|.: code :seg
Por lo tanto, si esto se ejecuta en una cadena de inicio $_
con una z
posición inicial, el código del interior se ejecutará muchas veces, en su mayoría, devolverá nada más que 1
cada vez que un brazo vecino se llene de inundaciones. Efectivamente $_
se destruye y se reemplaza por tantos 1
s como haya componentes conectados conectados z
. Tenga en cuenta que el bucle debe ejecutarse hasta la suma de los tamaños de los componentes + el número de veces de brazos, pero eso está bien ya que "número de caracteres, incluidas las nuevas líneas * 2 + 1" veces.
El laberinto se desconecta si no hay 1
's (cadena vacía, un vértice aislado) o si hay más de 1 brazos (más de 2 1
s). Esto se puede verificar usando la expresión regular /\B/
(esto da en 0
lugar de 1
versiones anteriores de perl. Es discutible cuál está mal). Desafortunadamente, si no coincide, esto dará una cadena vacía en lugar de 0
. Sin embargo, el s:|.: code :seg
fue diseñado para devolver siempre un número impar, por lo que al hacer un &
con /\B/
esto dará 0
o 1
.
Todo lo que queda es recorrer toda la matriz de entrada y en cada posición transitable se siembra z
y cuenta los brazos conectados. Eso se hace fácilmente con:
s%b%$_="$`z$'"; code %eg
El único problema es que en las posiciones no transitables se retiene el valor anterior. Como necesitamos 0
s allí, eso significa que la matriz de entrada original debe tener 0
en las posiciones y 0
coincidencias no transitables \w
en la sustitución original y provocaría rellenos de inundación. Es por eso que uso \pL
en su lugar (solo letras coincidentes).