Perl 5 , -p0
105 101 96 93 90 89 octets
Utilise b
au lieu de1
dans l'entrée.
Assurez-vous que la matrice sur STDIN se termine par une nouvelle ligne
#!/usr/bin/perl -p0
s%b%$_="$`z$'";s:|.:/
/>s#(\pL)(.{@{-}}|)(?!\1)(\pL)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg
Essayez-le en ligne!
Utilise 3 niveaux de substitution!
Cette version de 87 octets est à la fois au format d'entrée et de sortie plus facile à interpréter, mais n'est pas en concurrence car elle utilise 3 caractères différents dans la sortie:
#!/usr/bin/perl -0p
s%b%$_="$`z$'";s:|.:/
/>s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg
Essayez-le en ligne!
Il est facile d'enregistrer un autre octet (l'expression rationnelle s
modificateur d' régulière) dans les deux versions en utilisant un caractère différent (non alphanumérique) comme terminateur de ligne (au lieu de la nouvelle ligne), mais cela rend à nouveau l'entrée assez illisible.
Comment ça fonctionne
Considérez la substitution
s#(\w)(.{columns}|)(?!1)(\w)#c$2c#s
Cela trouvera deux lettres différentes et côte à côte horizontalement ou verticalement et les remplacera par c
. Dans un labyrinthe dont les chemins sont entièrement constitués de la lettre, b
rien ne se passera car les lettres sont les mêmes, mais dès qu'une des lettres est remplacée par une autre (par exemple z
), cette lettre et un voisin seront remplacés c
et une application répétée est un inondation du composant connecté avec c
de la semence z
.
Dans ce cas, je ne veux cependant pas un remplissage complet. Je veux remplir un seul des bras voisins z
, donc après la première étape, je veux qu'ils z
disparaissent. Cela fonctionne déjà avec le c$2c
remplacement, mais plus tard, je veux redémarrer un remplissage d'inondation le long d'un autre bras à partir du même point et je ne sais plus lequel des c
s était à l'origine z
. Donc à la place j'utilise
s#(\w)(.{columns}|)(?!\1)(\w)#$&|a.$2.a#se
b | a
est c
, b | c
est c
et z | a
est {
. Donc, dans un labyrinthe avec des chemins composés b
et une graine z
dans la première étapeb
sera remplacée par c
et z
sera remplacée par {
ce qui n'est pas une lettre et ne correspond pas \w
et ne provoquera donc pas de remplissages supplémentaires. Le c
cependant gardera un nouveau remplissage d'inondation aller et un bras voisin de la graine est rempli. Par exemple à partir de
b c
b c
bbzbb becomes bb{bb
b b
b b
Je peux ensuite remplacer tous les c par des non-lettres (par exemple -
) et les remplacer {
à z
nouveau pour redémarrer le remplissage:
- -
- -
bbzbb becomes cc{bb
b b
b b
et répétez ce processus jusqu'à ce que tous les voisins de la graine aient été convertis. Si je remplace ensuite {
par z
et remplit:
- -
- -
--z-- stays --z--
- -
- -
Le z
reste reste à la fin car il n'y a pas de voisin avec qui faire une transformation. Cela montre clairement ce qui se passe dans le fragment de code suivant:
/\n/ >
Trouvez la première nouvelle ligne. Le décalage de départ est maintenant@-
s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se
L'expression régulière discutée ci-dessus avec @{-}
comme nombre de colonnes (puisque plain@-
confond l'analyseur perl et ne le remplace pas correctement)
&&
Le /\n/
réussit toujours et la substitution est vraie tant que nous pouvons encore remplir. Donc la partie après&&
est exécutée si le remplissage d'un bras est effectué. Sinon, le côté gauche correspond à une chaîne vide
y/{c/z / > 0
Redémarrez le remplissage et retournez 1 si le remplissage précédent a fait quelque chose. Sinon, retourne la chaîne vide. Tout ce morceau de code est enveloppé à l'intérieur
s:|.: code :seg
Donc, si cela est exécuté sur une chaîne de départ $_
avec un z
à la position de départ, le morceau de code à l'intérieur sera exécuté plusieurs fois, la plupart du temps, ne retournant rien, mais à 1
chaque fois qu'un bras voisin est rempli. Effectivement$_
détruit et remplacé par autant de 1
s qu'il y a de composants connectés z
. Notez que la boucle doit être exécutée jusqu'à la somme des tailles des composants + nombre de fois d'armements mais c'est OK car il y aura "nombre de caractères y compris les sauts de ligne * 2 + 1" fois.
Le labyrinthe se déconnecte s'il n'y en a pas 1
(chaîne vide, sommet isolé) ou s'il y a plus de 1 bras (plus de 2 1
s). Cela peut être vérifié en utilisant l'expression régulière /\B/
(cela donne 0
au lieu de 1
sur les anciennes versions de Perl. On peut dire laquelle est fausse). Malheureusement, s'il ne correspond pas, cela donnera une chaîne vide au lieu de 0
. Cependant, le a s:|.: code :seg
été conçu pour toujours renvoyer un nombre impair donc en faisant un &
avec /\B/
cela donnera 0
ou 1
.
Il ne reste plus qu'à parcourir l'ensemble du réseau d'entrée et à chaque position de marche avec z
et compter les bras connectés. Cela se fait facilement avec:
s%b%$_="$`z$'"; code %eg
Le seul problème est que dans les positions non accessibles à pied, l'ancienne valeur est conservée. Puisque nous avons besoin de 0
s, cela signifie que le tableau d'entrée d'origine doit avoir 0
dans les positions non accessibles et 0
correspond \w
dans la substitution d'origine et déclencherait des remplissages. C'est pourquoi j'utilise à la \pL
place (uniquement des lettres de correspondance).