Szaleństwo magicznego lustra

22

Wprowadzenie

Mam pokój pełen magicznych luster . Są to tajemnicze artefakty, które mogą powielić dowolny przedmiot, z wyjątkiem innego magicznego lustra. Mówiąc dokładniej, duplikat wersji elementu pojawi się po drugiej stronie lustra, w tej samej odległości. Jeśli jednak po obu stronach znajduje się inne magiczne lustro, między lustrem do duplikowania a dowolnym przedmiotem (oryginalnym lub duplikatem), duplikat nie jest tworzony. Oryginalny element może znajdować się po lewej lub prawej stronie lustra, a duplikat pojawi się po drugiej stronie. Ponadto zduplikowany element może sam zostać powielony przez inne dublowanie. Przedmioty nigdy nie blokują powielania innych przedmiotów (z wyjątkiem tego, że znajdują się bezpośrednio na pozycji potencjalnego duplikatu).

Wkład

Twój wkład to ciąg znaków składający się z znaków .#|reprezentujących puste miejsce, przedmioty i magiczne zwierciadła. Na wejściu zawsze będzie przynajmniej jedno magiczne lustro.

Wydajność

Twój wynik będzie kolejnym ciągiem, w którym każde magiczne lustro powieli każdy możliwy przedmiot, zgodnie z powyższymi zasadami. Możesz założyć, że w miejscu, w którym pojawi się zduplikowany przedmiot, zawsze będzie puste miejsce (więc nie będą przekraczać granic).

Przykłady

Rozważ ciąg wejściowy

.#.|.....|......#
 A B     C      D

gdzie zaznaczyliśmy niektóre pozycje dla jasności. Lustro Bduplikuje element A, który kończy się po jego prawej stronie:

.#.|.#...|......#
 A B     C      D

Mirror Cnastępnie powiela nowy element:

.#.|.#...|...#..#
 A B     C      D

Lustro Cnie może powielić elementu A, ponieważ przeszkadza mu lustro B. Nie może również powielać przedmiotu D, ponieważ lustro przeszkadza Bpo drugiej stronie. Podobnie, lustro Bnie może powielić elementu Dlub duplikatu obok niego, ponieważ lustro przeszkadza C, więc jest to prawidłowe wyjście.

W innym przykładzie rozważmy dane wejściowe

.##..#...|#..##...|..##....#.
 AB  C   DE  FG   H  IJ    K

Lustro Dmoże powielać Ai Bna prawo, a Ei Gw lewo. Ci Fsą już duplikatami. Ciąg staje się

.##.##..#|#..##.##|..##....#.
 AB  C   DE  FG   H  IJ    K

Lustro Hmoże powielać E, Foraz duplikaty Ai Bna prawo i Ina lewo. Gi Jsą już duplikatami, a lustro Djest na drodze K. Teraz mamy

.##.##..#|#..#####|#####..##.
 AB  C   DE  FG   H  IJ    K

Wreszcie lustro Dmoże powielić duplikat Ipo lewej stronie. Kończymy z

.#####..#|#..#####|#####..##.
 AB  C   DE  FG   H  IJ    K

Zasady i punktacja

Możesz napisać pełny program lub funkcję. Wygrywa najniższa liczba bajtów. Zgłoszenia, które nie używają silników wyrażeń regularnych, konkurują osobno z tymi, które to robią i mogą być oznaczone symbolem (bez wyrażeń regularnych) .

Przypadki testowe

"|" -> "|"
"..|.." -> "..|.."
".#.|..." -> ".#.|.#."
"..#|.#." -> ".##|##."
".#..|....|.." -> ".#..|..#.|.#"
".|..|.#....." -> "#|#.|.#....."
"...|.#...|....#" -> ".##|##...|...##"
"......#|......." -> "......#|#......"
".#.|.....|......#" -> ".#.|.#...|...#..#"
".......|...#.##|...." -> "##.#...|...#.##|##.#"
"...#..||.......#..#...#" -> "...#..||.......#..#...#"
".##|.#....||#||......#|.#" -> ".##|##....||#||.....##|##"
".##..#...|#..##...|..##....#." -> ".#####..#|#..#####|#####..##."
".#|...||...|#...|..##...|#...." -> ".#|#..||.##|##..|..##..#|#..##"
"....#.|...#.|..|.|.....|..#......" -> "..#.#.|.#.#.|.#|#|#.#..|..#.#...."
"..|....|.....#.|.....|...|.#.|..|.|...#......" -> ".#|#...|...#.#.|.#.#.|.#.|.#.|.#|#|#..#......"
Zgarb
źródło
Czy możemy wziąć tablicę znaków jako dane wejściowe i / lub wyjściowe?
Conor O'Brien
@ ConorO'Brien Nie, chyba że jest to naturalna reprezentacja łańcucha w twoim języku.
Zgarb

Odpowiedzi:

10

Siatkówka , 50 bajtów

+`([#.])(([#.])*\|(?>(?<-3>[#.])*))(?!\1)[#.]
#$2#

Wypróbuj online! (Pierwszy wiersz włącza pakiet testowy oddzielony od linii).

Wydaje mi się, że jest to przeciwieństwo przedłożenia (bez wyrażenia regularnego).

Wyjaśnienie

Jest to po prostu podstawienie wyrażenia regularnego, które jest stosowane wielokrotnie ( +), aż łańcuch przestanie się zmieniać. Używam grup równoważących, aby upewnić się, że dwie pozycje lustrzane znajdują się w tej samej odległości od danego lustra (odwołania wsteczne nie zrobią, ponieważ dokładny ciąg po obu stronach |może być inny).

([#.])            # Match and capture a non-mirror cell.
(                 # This will match and capture everything up to its corresponding
                  # cell so that we can write it back in the substitution.
  ([#.])*         #   Match zero or more non-mirror cells and push each one onto
                  #   group 3. This counts the distance from our first match to
                  #   the mirror.
  \|              #   Match the mirror.
  (?>             #   Atomic group to prevent backtracking.
    (?<-3>[#.])*  #     Match non-mirror while popping from group 3.
  )               #   There are three reasons why the previous repetition
                  #   might stop:
                  #   - Group 3 was exhausted. That's good, the next position
                  #     corresponds to the first character we matched.
                  #   - We've reached the end of the string. That's fine,
                  #     the last part of the regex will cause the match to fail.
                  #   - We've hit another mirror. That's also fine, because
                  #     the last part of the regex will still fail.
)
(?!\1)            # Make sure that the next character isn't the same as the first
                  # one. We're looking for .|# or #|., not for #|# or .|.
[#.]              # Match the last non-mirror character.

Zastępuje się to, #$2#co po prostu zamienia zarówno pierwszy, jak i ostatni znak meczu na #.

Martin Ender
źródło
9

Perl, 49 bajtów

Pełne uznanie dla @Martin Ender dla tego, który zasugerował to wyrażenie o 15 bajtów krótsze niż moje.

47 bajtów kodu + -plflagi

s/([.#])(\||[^|](?2)[^|])(?!\1)[^|]/#$2#/&&redo

Aby uruchomić:

perl -plE 's/([.#])(\||[^|](?2)[^|])(?!\1)[^|]/#$2#/&&redo' <<< ".##..#...|#..##...|..##....#."

Pierwsza ( ([.#])) i ostatnia ( (?!\1)[^|]) część są takie same jak w odpowiedzi Retina (patrz objaśnienie tam).
Środkowa część ( (\||[^|](?2)[^|])) używa perl recursion ( (?2)), aby dopasować albo mirror ( \|) albo ( |) dwa znaki inne niż mirrors ( [^|]) oddzielone tym samym wzorcem ( (?2)).


Moja starsza (i brzydsza) wersja: s/([.#])(([^|]*)\|(??{$3=~s%.%[^|]%gr}))(?!\1)[^|]/#$2#/&&redo

Dada
źródło
4

Haskell (bez wyrażenia regularnego), 117 bajtów

r=reverse
s=span(<'|')
m=zipWith min
g a|(b,l:c)<-s a,(d,e)<-s c=b++l:g(m(r b++[l,l..])d++e)|0<1=a
f x=m(g x)$r.g.r$x
Dianne
źródło
2

PHP, 123 117 100 bajtów

for($t=$argv[1];$t!=$s;)$t=preg_replace("%([.#])(\||[.#](?2)[.#])(?!\g1)[.#]%","#$2#",$s=$t);echo$t;

program pobiera argument wiersza poleceń, wyrażenie regularne wzięte z @Martin Ender / Dada. Uruchom z -r.

Tytus
źródło
@Zgarb naprawiono, dziękuję
Tytus
2

C, 176 bajtów

void t(char*a){int x=0;for(int i=0;a[i];i++)if(a[i]=='|'){for(int j=x;a[j]&&j<=i*2-x;j++){if((a[j]==35)&&(a[2*i-j]==46)){a[2*i-j]=35;i=-1;}if((i-j)&&(a[j]=='|'))break;}x=i+1;}}

Nie golfił

void t(char*a)
{
    int x=0;
    for(int i=0;a[i];i++)
        if(a[i]=='|')
        {
            for(int j=x;a[j]&&j<=i*2-x;j++)
            {
                if((a[j]=='#')&&(a[2*i-j]=='.'))
                {
                    a[2*i-j]='#';
                    i=-1;
                    break;
                }
                if((i!=j)&&(a[j]=='|'))
                    break;
            }
            x=i+1;
        }
}
Eyal Lev
źródło
1
Myślę, że można zaoszczędzić kilka bajtów poprzez zastąpienie '#'i '.'z 35i 46odpowiednio.
sztuczny
Ten kod może być golfem… dużo.
Mukul Kumar
dzięki sztucznej wartości Null, która uratowała 3 bajty. „|” wynosi 124, więc to niczego nie oszczędza (ale może powinienem to zmienić, aby było spójne; jeszcze nie jestem pewien). i @Mulul, tak naprawdę nie widzę, jak to zrobić, bez wielkiej zmiany jego logiki.
Eyal Lev
sprawdź, czy kod działa poprawnie x,i,j;void t(char*a){while(a[i]++)if(a[i]=='|'){for(j=x;a[j++]&&j<=i*2-x;j++){if((a[j]==35)&&(a[2*i-j]==46)){a[2*i-j]=35;i=-1;break;}if((i-j)&&(a[j]=='|'))break;}x=i+1;}}- 170 bajtów
Mukul Kumar
1
1 więcej bajtów zamień (i! = J) na (ij), a jeśli zamierzasz pozostać przy c ++, to przynajmniej zdefiniuj wszystkie int w jednym miejscu ...
Mukul Kumar,
1

JavaScript (ES6), 170 bajtów

s=>s.replace(/#/g,(c,i)=>(g(i,-1),g(i,1)),g=(i,d,j=h(i,d))=>j-h(j=j+j-i,-d)|s[j]!='.'||(s=s.slice(0,j)+'#'+s.slice(j+1),g(j,d)),h=(i,d)=>s[i+=d]=='|'?i:s[i]?h(i,d):-1)&&s

Nie golfowany:

function mirror(s) {
    for (var i = 0; i < s.length; i++) {
        // Reflect each # in both directions
        if (s[i] == '#') s = reflect(reflect(s, i, true), i, false);
    }
    return s;
}
function reflect(s, i, d) {
    // Find a mirror
    var j = d ? s.indexOf('|', i) : s.lastIndexOf('|', i);
    if (j < 0) return s;
    // Check that the destination is empty
    var k = j + (j - i);
    if (s[k] != '.') return s;
    // Check for an intervening mirror
    var l = d ? s.lastIndexOf('|', k) : s.indexOf('|', k);
    if (l != j) return s;
    // Magically duplicate the #
    s = s.slice(0, k) + '#' + s.slice(k + 1);
    // Recursively apply to the new #
    return reflect(s, k, d);
}
Neil
źródło