Unminify łańcuch Pythlike

13

Pyth jest prawdopodobnie najbardziej popularnym językiem golfa ogólnego zastosowania. Choć jest nieco w spadku , w wyniku nowych języków, od 2014 do 2016 składnia zwięzły Pyth za Constant aktualizacje, przeciążenia, oraz (dla jego epoki) wielu builtins stało się ulubionym miejscem dla większości pytań.

Kod Pyth jest często trudny do odczytania. Nawet dane wyjściowe trybu debugowania (transponowany Python) często składają się z długiej linii, czasem z nawiasami zagnieżdżonymi na dziesięciu. Jednak poprawnie sformatowany Pyth jest bardzo czytelny.

Oto fragment kodu Pyth napisany przez @isaacg w Play the Word Chain .

.MlZfqhMtTeMPT+Lzs.pMyQ

Jest o wiele bardziej czytelny jak ten.

.M                     Filter by gives-maximal-value of
   l Z                   lambda Z:length(Z) over
   f                     filter by (lambda T:
     q                     equal
       hM t T                head-map tail T
       eM P T                end-map Pop T)
     +L                    Append z to each element in
        z                        
        s .pM y Q            flattened permutations of each subset of Q

Aby sprostać temu wyzwaniu, eliminujemy aspekt Kołmogorowa polegający na kategoryzowaniu znaków Pyth i koncentrujemy się na formatowaniu. Zamiast być kodem Pyth, wejście będzie się składać ze znaków w 0123456789M. Cyfra nreprezentuje funkcję arity ni Mreprezentuje operator. Na przykład powyższy kod jest reprezentowany jako 210221M101M102M011M10. Oto kroki, aby unminify:

Podziel ciąg na tokeny.

Token pasuje [0-9]M*. 0Mnie pojawi się na wejściu.

Dodaj końcowe 0.

Gdy nie ma wystarczającej liczby argumentów, Pyth dołącza do kodu tyle ukrytych zmiennych (zmiennych lambda lub Qs), ile jest niezbędnych do wypełnienia argumentów programu; powinny być reprezentowane przez 0s.

Grupuj tokeny w linie.

Liczebność tokena to wartość jego cyfry.

  • Token arity-0 (tj. 0) kończy linię.

  • W przypadku żetonu arity-1 następny żeton powinien przejść w tym samym wierszu, oddzielony spacją.

  • W przypadku tokena arity> = 2, jego argumenty idą w osobnych wierszach, w kolejności, w jakiej występują w kodzie, a po nich każdy z własnymi podrzędnymi dokumentami i tak dalej. Argumenty do tokena są wcięte na końcu tego tokena plus jedna spacja.

Wejście

Niepusty łańcuch znaków (lub tablica znaków, tablica łańcuchów długości 1 itd., Na co pozwalają standardowe metody we / wy) składający się z 0123456789M, który nie będzie zawierał podłańcucha 0M.

Wynik

Ciąg sformatowany zgodnie z powyższymi zasadami.

Przypadki testowe

210221M101M102M011M10

2
  1 0
  2
    2
      1M 1 0
      1M 1 0
    2M
       0
       1 1M 1 0


123M4M

1 2
    3M
       4M
          0
          0
          0
          0
       0
       0
    0


2MM

2MM
    0
    0


11011100

1 1 0
1 1 1 0
0


9000000

9
  0
  0
  0
  0
  0
  0
  0
  0
  0
lirtosiast
źródło
Powiązane pytanie: codegolf.stackexchange.com/questions/47798/...
lirtosiast
Czy mogę wziąć dane wejściowe jako tablicę cyfr / ciągów? Przykładem 210221M101M102M011M10może być[2,1,0,2,2,1,'M',1,0,1,'M',1,0,2,'M',0,1,1,'M',1,0]
Luis felipe De jesus Munoz
@LuisfelipeDejesusMunoz Nie, chyba że standardowe reguły I / O wymagają, abyś miał pozwolenie na to (co nie sądzę, że tak.) IMO nieznacznie zmieniłoby wyzwanie, gdyby Mpozwolono, by były innym typem danych niż liczby całkowite.
lirtosiast
@lirtosiast Tak więc tablica znaków / ciągów jednoznakowych jest w porządku, po prostu nie używa różnych typów danych między cyframi a M?
Kamil Drakari
1
@LeakyNun Pusty ciąg znaków jest teraz niezdefiniowanym zachowaniem.
lirtosiast

Odpowiedzi:

1

JavaScript (ES8), 160 159 bajtów

f=(s,a=[d=0,p=[1]])=>s.replace(/(.)M*/g,(s,c)=>(g=_=>a[d]?s+(P=p[d]-=c--&&~s.length,c?`
`.padEnd(P):' '):g(d--))(a[d]--,a[++d]=+c,p[d]=p[d-1]))+(d?f('0',a):'')

Wypróbuj online!

Skomentował

f = (                          // f = recursive function taking:
  s,                           //   s   = input string
  a = [                        //   a[] = array holding the number of expected arguments
    d = 0,                     //   d   = current depth, initialized to 0
    p = [1]                    //   p[] = array holding the padding values
  ]                            //
) =>                           //
  s.replace(                   // search in s all substrings
    RegExp('(.)M*', 'g'),      // consisting of a digit followed by 0 to N 'M' characters
    (s, c) =>                  // for each substring s beginning with the digit c:
      ( g = _ =>               //   g = recursive function
          a[d] ?               //     if we're still expecting at least one argument at
                               //     this depth:
            s + (              //       append s
              P = p[d] -=      //       update the padding value P = p[d] for this depth:
                c-- &&         //         decrement c; unless c was equal to 0,
                ~s.length,     //         add the length of s + 1 to p[d]
              c ?              //       if c is not equal to 0 (i.e. was not equal to 1):
                `\n`.padEnd(P) //         append a linefeed followed by P - 1 spaces
              :                //       else:
                ' '            //         append a single space
            )                  //
          :                    //     else (all arguments have been processed):
            g(d--)             //       decrement the depth and call g again
      )(                       //   before the initial call to g:
        a[d]--,                //     decrement the number of arguments at depth d
        a[++d] = +c,           //     set the number of arguments for the next depth
        p[d] = p[d - 1]        //     set the padding value for the next depth,
      )                        //     using a copy of the previous depth
  ) + (                        // end of replace()
    d ?                        // if we're not back at depth 0:
      f('0', a)                //   do a recursive call to f with an extra '0'
    :                          // else:
      ''                       //   stop recursion
  )                            //
Arnauld
źródło
1

Haskell , 192 190 187 bajtów

unlines.snd.f
f(n:r)|(m,t)<-span(>'9')r,(s,l)<-n#t=(s,n?((n:m):map((' '<$(n:n:m))++)l))
f e=(e,["0"])
'1'?(a:b:r)=(a++drop(length a)b):r
_?s=s
'0'#s=(s,[])
n#s|(r,l)<-f s=(l++)<$>pred n#r

Wypróbuj online!

Musi istnieć lepszy sposób obsługi przypadku arity-1, który obecnie zajmuje 45 bajtów.

Edycje:

  • -2 bajty, przełączając się na inną metodę obsługi 1, chociaż poprzednia metoda ma prawdopodobnie większy potencjał optymalizacji.
  • -3 bajty, nie konwertując cyfr znaków na liczby i używając predzamiast nich n-1.
unlines.snd.f
f(n:r)|(m,t)<-span(>'9')r,(s,l)<-read[n]#t,w<-map((' '<$(n:n:m))++)=(s,last$((n:m):w l):[(n:m++' ':h):w t|n<'2',h:t<-[l]])
f e=(e,["0"])
0#s=(s,[])
n#s|(r,l)<-f s=(l++)<$>(n-1)#r

Wypróbuj online!

Laikoni
źródło
1

Węgiel drzewny , 75 bajtów

FS⊞υ⎇⁼ιM⁺⊟υιι≔⮌υυ≔⟦⟧θ≔⟦⟧ηW∨υη«≔⎇υ⊟υ0ιι¿⊖Σι↘→⊞θι⊞ηΣιW∧η¬§η±¹«⊟ηM⊕L⊟θ←¿η⊞η⊖⊟η

Wypróbuj online! Link jest do pełnej wersji kodu. Wyjaśnienie:

FS⊞υ⎇⁼ιM⁺⊟υιι

Zapętl znaki wejściowe i zamień je w listę cyfr z opcjonalnymi Mprzyrostkami.

≔⮌υυ

Odwróć tę listę, abyśmy mogli ją wykorzystać Pop.

≔⟦⟧θ

Ta zmienna jest stosem żetonów, których arity nie zostały jeszcze spełnione.

≔⟦⟧η

Ta zmienna jest stosem pozostałej arii niespełnionych tokenów.

W∨υη«

Powtarzaj, aż zużyjemy wszystkie żetony i opróżnimy stos.

     ≔⎇υ⊟υ0ι

Zdobądź następny token lub 0jeśli nie.

     ι¿⊖Σι↘→

Wydrukuj token, a następnie przesuń kursor w poziomie, jeśli zaczyna się 1inaczej po przekątnej.

     ⊞θι⊞ηΣι

Dodaj token i jego arity do odpowiednich zmiennych.

     W∧η¬§η±¹«

Powtarzaj, gdy stos arity jest niepusty, ale najwyższy arity ma wartość zero.

              ⊟η

Odrzuć arity zero.

              M⊕L⊟θ←

Usuń jego żeton i przenieś tyle znaków, które pozostały.

              ¿η⊞η⊖⊟η

Jeśli pozostały jakieś arie, zmniejsz arseum górne.

Neil
źródło