Perl 5 , -p0
105 101 96 93 90 89 bajtów
Używa b
zamiast 1
w danych wejściowych.
Upewnij się, że macierz na STDIN jest zakończona nową linią
#!/usr/bin/perl -p0
s%b%$_="$`z$'";s:|.:/
/>s#(\pL)(.{@{-}}|)(?!\1)(\pL)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg
Wypróbuj online!
Wykorzystuje 3 poziomy substytucji!
Ta 87-bajtowa wersja jest łatwiejsza do interpretacji zarówno w formacie wejściowym, jak i wyjściowym, ale nie konkuruje, ponieważ używa 3 różnych znaków w danych wyjściowych:
#!/usr/bin/perl -0p
s%b%$_="$`z$'";s:|.:/
/>s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg
Wypróbuj online!
Łatwo jest zapisać kolejny bajt ( s
modyfikator wyrażenia regularnego ) w obu wersjach, używając jakiegoś innego (nie alfanumerycznego) znaku jako terminatora wiersza (zamiast nowej linii), ale to sprawia, że dane wejściowe są ponownie nieczytelne.
Jak to działa
Rozważ zamianę
s#(\w)(.{columns}|)(?!1)(\w)#c$2c#s
Znajdują dwie litery, które są różne i znajdują się obok siebie w poziomie lub w pionie i zastępują je c
. W labiryncie, którego ścieżki składają się w całości z litery, b
nic się nie wydarzy, ponieważ litery są takie same, ale gdy tylko jedna z liter zostanie zastąpiona inną (np. z
) Ta litera i sąsiad zostaną zastąpione, c
a wielokrotne stosowanie będzie wypełnienie zalewowe podłączonego elementu z c
nasion z
.
W tym przypadku nie chcę jednak pełnego wypełnienia. Chcę wypełnić tylko jedno z sąsiadujących ramion z
, więc po pierwszym kroku chcę z
odejść. To już działa z c$2c
zamiennikiem, ale później chcę ponownie uruchomić wypełnienie zalewowe wzdłuż innego ramienia, zaczynając od tego samego punktu i nie wiem, który z nich c
był z
już pierwotnie . Zamiast tego używam
s#(\w)(.{columns}|)(?!\1)(\w)#$&|a.$2.a#se
b | a
jest c
, b | c
jest c
i z | a
jest {
. Tak więc w labiryncie z utworzonymi ścieżkami b
i ziarnem z
w pierwszym kroku b
zostanie zastąpione przez c
i z
zostanie zastąpione przez, że {
nie jest literą i nie pasuje, \w
a więc nie spowoduje dalszych wypełnień. c
Jednak będzie prowadzić dalsze przeciwpowodziowe syta dzieje i jedno ramię sąsiada nasion zostanie wypełnione. Np. Zaczynając od
b c
b c
bbzbb becomes bb{bb
b b
b b
Mogę następnie zastąpić wszystkie litery c niektórymi literami (np. -
) I zastąpić {
je z
ponownie, aby ponownie uruchomić wypełnianie zalania:
- -
- -
bbzbb becomes cc{bb
b b
b b
i powtarzajcie ten proces, aż wszyscy sąsiedzi nasienia zostaną nawróceni. Gdybym wtedy jeszcze raz zastąpić {
przez z
i powódź-fill:
- -
- -
--z-- stays --z--
- -
- -
Te z
szczątki tył na końcu, ponieważ nie ma sąsiad zrobić transformacji. To wyjaśnia, co dzieje się w następującym fragmencie kodu:
/\n/ >
Znajdź pierwszą nową linię. Początkowe przesunięcie jest teraz w@-
s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se
Wyrażenie regularne omówione powyżej z @{-}
liczbą kolumn (ponieważ zwykły @-
myli parser perla i nie zastępuje go poprawnie)
&&
/\n/
Zawsze udaje i podstawienie jest prawdą tak długo, jak możemy nadal przeciwpowodziowe wypełnienia. Tak więc część następna &&
jest wykonywana, jeśli wypełnienie jednego ramienia zostanie wykonane. Jeśli nie, lewa strona jest pusta
y/{c/z / > 0
Uruchom ponownie wypełnienie i zwróć 1, jeśli poprzednie wypełnienie zrobiło cokolwiek. W przeciwnym razie zwróć pusty ciąg. Cały kawałek kodu jest zawinięty w środku
s:|.: code :seg
Jeśli więc zostanie to wykonane na łańcuchu początkowym $_
z z
pozycją początkową, fragment kodu w środku zostanie wykonany wiele razy, w większości nie zwracając niczego, ale za 1
każdym razem, gdy ramię sąsiada zostanie wypełnione zalaniem. Skutecznie $_
zostaje zniszczony i zastąpiony przez tyle 1
s, ile jest połączonych ze sobą komponentów z
. Zauważ, że pętla musi zostać wykonana do sumy rozmiarów komponentów + liczby czasów uzbrojenia, ale jest to w porządku, ponieważ będzie to „liczba znaków łącznie z znakami nowej linii * 2 + 1”.
Labirynt zostaje rozłączony, jeśli nie ma go 1
(pusty ciąg, izolowany wierzchołek) lub jeśli jest więcej niż 1 ramię (więcej niż 2 1
s). Można to sprawdzić za pomocą wyrażenia regularnego /\B/
(daje to 0
zamiast 1
starszych wersji perla. Można argumentować, który z nich jest zły). Niestety, jeśli nie pasuje to da pusty ciąg zamiast 0
. Jednak s:|.: code :seg
został zaprojektowany, aby zawsze powrócić nieparzystą liczbę więc wykonując &
z /\B/
tego da 0
lub 1
.
Wszystko, co pozostało, to chodzenie po całej tablicy wejściowej i w każdej pozycji do przejścia na piechotę zi z
policzyć połączone ramiona. Można to łatwo zrobić za pomocą:
s%b%$_="$`z$'"; code %eg
Jedynym problemem jest to, że w pozycjach, na których nie można chodzić, stara wartość jest zachowywana. Ponieważ potrzebujemy 0
s, oznacza to, że pierwotna tablica wejściowa musi znajdować się w 0
pozycjach nie 0
pasujących \w
do przejścia i dopasowań w pierwotnym podstawieniu i wyzwalać przepełnienia. Dlatego używam \pL
zamiast tego (pasują tylko litery).