Perl 5 , -p0
105 101 96 93 90 89 byte
Utilizza b
anziché 1
nell'input.
Assicurarsi che la matrice su STDIN sia terminata con una nuova riga
#!/usr/bin/perl -p0
s%b%$_="$`z$'";s:|.:/
/>s#(\pL)(.{@{-}}|)(?!\1)(\pL)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg
Provalo online!
Utilizza 3 livelli di sostituzione!
Questa versione da 87 byte è sia in formato input che output più semplice da interpretare, ma non è in competizione poiché utilizza 3 caratteri diversi nell'output:
#!/usr/bin/perl -0p
s%b%$_="$`z$'";s:|.:/
/>s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg
Provalo online!
È facile salvare un altro byte (il s
modificatore regex ) in entrambe le versioni utilizzando alcuni caratteri diversi (non alfanumerici) come terminatore di riga (anziché newline), ma ciò rende di nuovo l'input piuttosto illeggibile.
Come funziona
Considera la sostituzione
s#(\w)(.{columns}|)(?!1)(\w)#c$2c#s
Questo troverà due lettere diverse e una accanto all'altra in senso orizzontale o verticale e sostituirle con c
. In un labirinto i cui percorsi sono costituiti interamente dalla lettera b
non accadrà nulla poiché le lettere sono uguali, ma non appena una delle lettere viene sostituita da un'altra (ad es. z
) Quella lettera e un vicino verranno sostituiti c
e l'applicazione ripetuta è un riempimento di piena del componente collegato con c
da seme z
.
In questo caso, tuttavia, non voglio un riempimento completo. Voglio riempire solo una delle braccia vicine z
, quindi dopo il primo passo voglio z
andare. Funziona già con la c$2c
sostituzione, ma in seguito voglio ricominciare un riempimento inondazione lungo un altro braccio a partire dallo stesso punto e non so più quale delle c
s fosse originariamente z
. Quindi invece lo uso
s#(\w)(.{columns}|)(?!\1)(\w)#$&|a.$2.a#se
b | a
è c
, b | c
è c
ez | a
è {
. Quindi in un labirinto con percorsi costituiti b
e un seme z
nel primo passaggio b
verrà sostituito da c
e z
verrà sostituito da {
quale non è una lettera e non corrisponde \w
e quindi non causerà ulteriori riempimenti. Il c
tuttavia manterrà un ulteriore diluvio-fill in corso e un braccio vicino del seme si riempie. Ad esempio a partire da
b c
b c
bbzbb becomes bb{bb
b b
b b
Posso quindi sostituire tutte le lettere c con alcune non lettere (ad es. -
) E sostituirle {
di z
nuovo per riavviare il riempimento:
- -
- -
bbzbb becomes cc{bb
b b
b b
e ripetere questo processo fino a quando tutti i vicini del seme non sono stati convertiti. Se dunque io ancora una volta sostituire {
da z
e inondazioni riempimento:
- -
- -
--z-- stays --z--
- -
- -
Alla fine z
resta dietro perché non c'è un vicino con cui fare una trasformazione. Ciò chiarisce cosa succede nel seguente frammento di codice:
/\n/ >
Trova la prima newline. L'offset iniziale è ora in@-
s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se
La regex discussa sopra con @{-}
il numero di colonne (poiché plain @-
confonde il parser perl e non sostituisce correttamente)
&&
Il /\n/
riesce sempre e la sostituzione è vero finché possiamo ancora alluvione-fill. Quindi la parte successiva &&
viene eseguita se viene eseguito il riempimento di un braccio. In caso contrario, il lato sinistro restituisce una stringa vuota
y/{c/z / > 0
Riavviare il riempimento dell'inondazione e restituire 1 se il riempimento precedente ha fatto qualcosa. Altrimenti restituisce la stringa vuota. L'intero pezzo di codice è racchiuso all'interno
s:|.: code :seg
Quindi, se questo viene eseguito su una stringa iniziale $_
con un z
nella posizione seed, il pezzo di codice all'interno verrà eseguito molte volte principalmente restituendo nient'altro che un1
ogni volta che un braccio vicino viene riempito. $_
Viene efficacemente distrutto e sostituito da tanti 1
s quanti sono i componenti collegati collegati z
. Si noti che il ciclo deve essere eseguito fino alla somma delle dimensioni dei componenti + numero di tempi delle armi, ma va bene dato che sarà "numero di caratteri comprese le nuove righe * 2 + 1" volte.
Il labirinto viene disconnesso se non ci sono 1
(stringa vuota, un vertice isolato) o se ci sono più di 1 braccio (più di 2 1
s). Questo può essere verificato usando il regex /\B/
(questo 0
invece che 1
nelle versioni precedenti di perl. È discutibile quale sia sbagliato). Sfortunatamente se non corrisponde questo darà una stringa vuota invece di 0
. Tuttavia, è s:|.: code :seg
stato progettato per restituire sempre un numero dispari, quindi facendo un &
con/\B/
questo darà 0
o 1
.
Tutto ciò che rimane è camminare sull'intero array di input e in ogni posizione di walkable seed con z
e contare i bracci collegati. Questo è facile da fare con:
s%b%$_="$`z$'"; code %eg
L'unico problema è che nelle posizioni non percorribili viene mantenuto il vecchio valore. Dal momento che abbiamo bisogno di 0
s lì, ciò significa che l'array di input originale deve avere 0
posizioni non calpestabili e 0
corrispondenze \w
nella sostituzione originale e innescherebbe riempimenti. Ecco perché uso \pL
invece (solo lettere di corrispondenza).