Perl 5 , -p0
105 101 96 93 90 89 bytes
Usa em b
vez de 1
na entrada.
Verifique se a matriz no STDIN é finalizada com uma nova linha
#!/usr/bin/perl -p0
s%b%$_="$`z$'";s:|.:/
/>s#(\pL)(.{@{-}}|)(?!\1)(\pL)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg
Experimente online!
Usa 3 níveis de substituição!
Esta versão de 87 bytes é mais fácil de interpretar nos formatos de entrada e saída, mas não está competindo, pois usa 3 caracteres diferentes na saída:
#!/usr/bin/perl -0p
s%b%$_="$`z$'";s:|.:/
/>s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg
Experimente online!
É fácil salvar outro byte (o s
modificador regex ) nas duas versões usando algum caractere diferente (não alfanumérico) como terminador de linha (em vez de nova linha), mas isso torna a entrada bastante ilegível novamente.
Como funciona
Considere a substituição
s#(\w)(.{columns}|)(?!1)(\w)#c$2c#s
Ele encontrará duas letras diferentes e próximas umas das outras na horizontal ou na vertical e as substituirá por c
. Em um labirinto cujos caminhos consistem inteiramente na letra, b
nada acontecerá, pois as letras são as mesmas, mas assim que uma das letras for substituída por outra (por exemplo z
), essa letra e um vizinho serão substituídos por c
uma aplicação repetida. inundação do componente conectado com a c
partir da semente z
.
Neste caso, no entanto, não quero um preenchimento completo. Eu quero preencher apenas um dos braços vizinhos z
, então, após o primeiro passo, quero z
ir embora. Isso já funciona com a c$2c
substituição, mas depois pretendo reiniciar um preenchimento de inundação ao longo de outro braço, começando do mesmo ponto e não sei mais qual deles c
era originalmente z
. Então, ao invés, eu uso
s#(\w)(.{columns}|)(?!\1)(\w)#$&|a.$2.a#se
b | a
é c
, b | c
é c
e z | a
é {
. Assim, em um labirinto com caminhos compostos b
e uma semente z
no primeiro passo b
será substituída c
e z
substituída pela {
que não é uma letra e não corresponde \w
e, portanto, não causará preenchimentos adicionais. No c
entanto, isso manterá um novo preenchimento de inundação e um braço vizinho da semente será preenchido. Por exemplo, começando de
b c
b c
bbzbb becomes bb{bb
b b
b b
Posso, então, substituir todos os c por alguns carta não (por exemplo -
) e substitua {
por z
outra vez para reiniciar a inundação-fill:
- -
- -
bbzbb becomes cc{bb
b b
b b
e repita esse processo até que todos os vizinhos da semente tenham sido convertidos. Se eu substituir novamente {
por z
e preencher:
- -
- -
--z-- stays --z--
- -
- -
Os z
restos ficam para trás no final, porque não há vizinho com quem fazer uma transformação. Isso deixa claro o que acontece no seguinte fragmento de código:
/\n/ >
Encontre a primeira nova linha. O deslocamento inicial está agora em@-
s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se
O regex discutido acima com @{-}
o número de colunas (uma vez que plain @-
confunde o analisador perl e não o substitui adequadamente)
&&
O /\n/
sempre é bem-sucedido e a substituição é verdadeira desde que ainda possamos inundar. Portanto, a parte seguinte &&
é executada se o preenchimento de um braço for concluído. Caso contrário, o lado esquerdo é avaliado como uma sequência vazia
y/{c/z / > 0
Reinicie o preenchimento e retorne 1 se o preenchimento anterior tiver feito alguma coisa. Caso contrário, retorne a string vazia. Todo esse código está envolvido
s:|.: code :seg
Portanto, se isso for executado em uma string inicial $_
com a z
na posição inicial, o código dentro será executado muitas vezes retornando nada, mas 1
sempre que um braço vizinho for inundado. Efetivamente $_
é destruído e substituído por tantos 1
s quantos componentes conectados estiverem conectados z
. Observe que o loop precisa ser executado até a soma dos tamanhos dos componentes + número de vezes de armas, mas isso é bom, pois ele "número de caracteres, incluindo novas linhas * 2 + 1" vezes.
O labirinto é desconectado se não houver 1
(corda vazia, um vértice isolado) ou se houver mais de 1 braço (mais de 2 1
s). Isso pode ser verificado usando o regex /\B/
(isso fornece, em 0
vez de 1
versões perl mais antigas. É discutível qual deles está errado). Infelizmente, se não corresponder, isso dará uma string vazia em vez de 0
. No entanto, o s:|.: code :seg
foi projetado para sempre retornar um número ímpar, fazendo um &
com /\B/
isso dará 0
ou 1
.
Tudo o que resta é caminhar por toda a matriz de entrada e, em cada posição caminhável, semear z
e contar os braços conectados. Isso é feito facilmente com:
s%b%$_="$`z$'"; code %eg
O único problema é que nas posições não passíveis de passagem o valor antigo é mantido. Como precisamos de 0
s lá, isso significa que a matriz de entrada original deve ter 0
nas posições não passíveis de passagem e 0
correspondências \w
na substituição original e provocaria enchentes. É por isso que eu uso \pL
(apenas as letras correspondentes).