Perl 5 , -p0 105 101 96 93 90 89 bajtów
Używa bzamiast 1w 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 ( smodyfikator 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, bnic 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, ca wielokrotne stosowanie będzie wypełnienie zalewowe podłączonego elementu z cnasion 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ę zodejść. To już działa z c$2czamiennikiem, 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 cbył zjuż pierwotnie . Zamiast tego używam
s#(\w)(.{columns}|)(?!\1)(\w)#$&|a.$2.a#se
b | ajest c, b | cjest ci z | ajest {. Tak więc w labiryncie z utworzonymi ścieżkami bi ziarnem zw pierwszym kroku bzostanie zastąpione przez ci zzostanie zastąpione przez, że {nie jest literą i nie pasuje, \wa więc nie spowoduje dalszych wypełnień. cJednak 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 zponownie, 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 zi powódź-fill:
- -
- -
--z-- stays --z--
- -
- -
Te zszczą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 zpozycją początkową, fragment kodu w środku zostanie wykonany wiele razy, w większości nie zwracając niczego, ale za 1każdym razem, gdy ramię sąsiada zostanie wypełnione zalaniem. Skutecznie $_zostaje zniszczony i zastąpiony przez tyle 1s, 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 1s). Można to sprawdzić za pomocą wyrażenia regularnego /\B/(daje to 0zamiast 1starszych 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 :segzostał zaprojektowany, aby zawsze powrócić nieparzystą liczbę więc wykonując &z /\B/tego da 0lub 1.
Wszystko, co pozostało, to chodzenie po całej tablicy wejściowej i w każdej pozycji do przejścia na piechotę zi zpoliczyć 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 0s, oznacza to, że pierwotna tablica wejściowa musi znajdować się w 0pozycjach nie 0pasujących \wdo przejścia i dopasowań w pierwotnym podstawieniu i wyzwalać przepełnienia. Dlatego używam \pLzamiast tego (pasują tylko litery).