Podsumowując? To moja mocna strona!

18

Wprowadzenie

Forte to bardzo osobliwy ezoteryczny język oparty na koncepcji modyfikacji wartości liczb. W Forte liczby nie są stałymi, ale zmiennymi, możesz użyć LETinstrukcji, aby przypisać im nowe wartości.

Na przykład po wykonaniu LET 2=4-1od teraz 2przyjmuje wartość 3, co oznacza, że ​​ilekroć wartość 2pojawia się w wyrażeniu, zamiast tego jest „zastępowana” przez 3. Wyrażenie (1+1)*2będzie teraz oceniać na 9.

Ta instrukcja w Forte służy zarówno do przechowywania informacji, jak i do kontroli przepływu (linie są ponumerowane, a zmieniając wartość ich liczb można określić kolejność ich wykonywania). W tym wyzwaniu nie zajmiemy się tym drugim aspektem.

Wyzwanie

Musisz napisać interpreter dla uproszczonego podzbioru LETwyrażeń Forte .

Otrzymasz jako dane wejściowe serię wierszy następujących po tej gramatyce:

<line>::= <number>=<expression>

<expression>::= <number>|<expression>+<number>

Uwaga: ta gramatyka jest nieprawidłowa, ponieważ nie ma w niej numerów linii, LET i nawiasów (które są zawsze obowiązkowe)

Oznacza to, że będziesz musiał poradzić sobie tylko z obliczaniem sum i przypisywaniem wartości liczbom. W nawiasach wejściowych nie będzie nawiasów i każde wyrażenie będzie musiało być oceniane od lewej do prawej: strzeż się, że na częściowe wyniki wpływają redefinicje!

Liczby zawsze będą liczbami całkowitymi nieujemnymi, aż do limitu rodzimych liczb całkowitych twojego języka (lub 2 ^ 32, w zależności od tego, która wartość jest wyższa).

Dla każdego wiersza powinieneś wypisać wynik wyrażenia i przypisać ten wynik (ewentualnie ponownie przypisanej) wartości pierwszej liczby, co wpłynie na sposób interpretacji kolejnych wierszy.

To jest , wygrywa najkrótszy kod (w bajtach)!

Inne zasady

  • Format wejściowy jest elastyczny, możesz na przykład wziąć pojedynczy ciąg znaków z nowymi wierszami, listę ciągów, listę list liczb ... To samo dotyczy wyniku, o ile jest jasne, jaki jest wynik każdego wyrażenia w wejście.
  • Możesz przesłać funkcję, pełny program lub rozwiązanie do uruchomienia w środowisku REPL, wywołując je raz dla każdej linii.
  • Standardowe luki są zabronione, w szczególności nie można wywołać zewnętrznego interpretera Forte w kodzie.

Przykłady

Wszystkie są częścią tego samego wejścia. Po każdej linii wyświetlana jest oczekiwana wydajność w stosunku do tej linii, czasami z komentarzem wskazującym odpowiednie zmiany przypisania (nie jest częścią wymaganego wyniku).

5=4
4
6=5
4        # 5 -> 4
7=1+2+5
7
7=5+2+1
4        # Order of operations matters! 5+2 -> 4+2 -> 6 -> 4
18=5+6+7
12
5=3
3        # Remember: 5 -> 4
10=6+4
3        # 6 -> 4 -> 3, 3+3 = 6 -> 3
Lew
źródło
Czy 0jest poprawny numer?
orlp
@orlp 0jest poprawny („Liczby zawsze będą nieujemnymi liczbami całkowitymi”)
Leo
Czy powinniśmy akceptować jakieś operatory arytmetyczne?
bacchusbeale
@ Bacchusbeale Nie, tylko podsumowanie.
Leo
Czy istnieje jakaś konkretna maksymalna liczba, czy jest tak duża, jak rodzimy typ liczb całkowitych języka? Poza tym zwracanie listy liczb byłoby nieprawidłowym wyjściem, z których jeden jest wynikiem, prawda? (np. wydrukowanie słownika / mapy, dla której liczba idzie do której liczby)
zgrep

Odpowiedzi:

4

Galaretka , 28 bajtów

®y$ÐL
ṪÇ+Ç¥/Ṅ;®⁸Ǥ;©
⁸©ḷƓÇ€¤

Wypróbuj online!

Jest to jeden z niewielu programów Jelly, w których bardziej efektywne jest pobieranie danych ze standardowego wejścia. Jest to pełny program (pisanie funkcji byłoby krótsze, ale jest zabronione przez reguły PPCG, ponieważ nie działałoby poprawnie za drugim razem). Format wejściowy wygląda następująco:

[[5,[4]],[6,[5]],[7,[1,2,5]],[7,[5,2,1]],[18,[5,6,7]],[5,[3]],[10,[6,4]]]

Wyjaśnienie

Funkcja pomocnicza 1Ŀ (przetłumacz liczbę całkowitą na jej wartość)

®y$ÐL
   ÐL   Repeatedly, until there are no further changes,
  $       apply the following unary function to {the input}:
 y          replace values using the mapping table
®             stored in the register.
        {Then return the eventual result.}

Raczej wygodnie, ta funkcja pomocnicza będzie działać poprawnie albo na pojedynczej wartości, albo na liście wartości, zależnie od sposobu y zdefiniowania. Jeśli dla jednej wartości podano więcej niż jedno mapowanie, pierwsze mapowanie pobieramy z tabeli. Tabela mapowania jest przechowywana w rejestrze (który jest w zasadzie tylko zmienną; Galaretka ma tylko jedną zmienną).

Funkcja pomocnicza 2Ŀ (oceń jedną instrukcję LET)

ṪÇ+Ç¥/Ṅ;®⁸Ǥ;©
Ṫ               On the last element of {the input},
 Ç              Run 1Ŀ,
     /          left fold it via
    ¥             the following binary function:
  +                 add {the two arguments}
   Ç                and run 1Ŀ on {the result},
      Ṅ         write {the result} (and a newline) to standard output,
       ;®       append the value of the register,
            ;   prepend
           ¤      the following value:
         ⁸          {the input, without its last element}
          Ç         with 1Ŀ run on it
             ©  and store that value in the register {and return it}.

Tak naprawdę nie chcemy tutaj wartości zwrotnej; po prostu uruchamiamy to ze względu na jego skutki uboczne (aktualizacja rejestru i wysyłanie przypisanej wartości). Funkcje galaretki zawsze zwracają jednak wartość, więc po prostu pozwalamy na zwrócenie tabeli mapowania, ponieważ jest to najkrótsza.

Główny program

⁸©ḷƓÇ€¤
 ©       Initialize the mapping table
⁸        with the empty string (which is also the empty list)
  ḷ      then evaluate and discard
      ¤  the following value:
   Ɠ       a line from standard input, parsed into a data structure
    Ç€     with each element transformed via 2Ŀ
         {and leave the empty string to be printed implicitly}

Zwykle dałby nam pierwszy argument wiersza poleceń, gdy jest uruchomiony w tym kontekście, ale nie ma go (pobieramy dane ze standardowego wejścia), więc działa w trybie alternatywnym, który daje nam ciąg zerowy. Konieczność zainicjowania rejestru (z domyślnej wartości 0, która ulega awarii y) oznacza, że ​​nie możemy domyślnie wspomnieć o danych wejściowych użytkownika, co oznacza, że ​​tak tanie jest pobranie go ze standardowego wejścia ( Ɠ), jak byłoby pobranie go z argument wiersza poleceń ( ³lub ) i możliwość dostępu do alternatywnego użycia oznacza, że ​​nietypowa (jak na galaretkę) forma wprowadzania danych jest w rzeczywistości o bajt krótsza.

Możliwe, że można to poprawić. Nadal nie zorientowałem się, dlaczego druga linia powinna powiedzieć, ⁸Ǥ;a nie tylko ;@Ç- obie powinny być równoważne, o ile rozumiem Jelly, biorąc pod uwagę brak użycia µ/ ð/ ø- ale ta ostatnia z jakiegoś powodu ulega awarii. Podobnie, istnieje wiele innych sposobów przestawienia programu bez utraty bajtów, więc możliwe, że przegapiłem sposób na skrócenie rzeczy.

Nawiasem mówiąc, zmiana w ostatnim wierszu ;daje interesujące spojrzenie na wewnętrzne działanie programu, ponieważ wyświetli on „historię rejestru”, która domyślnie jest generowana przez zwracane wartości 2Ḷ.


źródło
5

Perl 5 , 92 bajtów

90 bajtów kodu + -plflagi.

sub f{($b=$h{$a=pop}//$a)!=$a?f($b):$a}s%(\d+)\+(\d+)%f($1)+f$2%e&&redo;/=/;$_=$h{f$`}=f$'

Wypróbuj online!

Używam hashtable %hdo przechowywania mapowania między liczbami.
Funkcja ( sub) fzwraca liczbę, do której odwzorowuje dane wejściowe (lub dane wejściowe, jeśli nie jest odwzorowana): $h{$a=pop}pobiera liczbę, do której odwzorowują dane wejściowe. Jeśli nie, dzięki temu //$awartością ($b=$h{$a=pop}//$a)jest input ( $a). Upewniamy się, że te wartości nie są danymi wejściowymi, aby nie zapętlały się nieskończenie ( !=$a). Następnie rekurencyjnie wywołujemy flub zwracamy dane wejściowe.
Główny program składa się z dwóch etapów:
- s%(\d+)\+(\d+)%f($1)+f$2%e&&redoocenia pierwszy dodatek po prawej stronie, podczas gdy nadal istnieje dodatek: zastępuje x+ygo wynik oceny f(x)+f(y).
- /=/;$_=$h{f$`}=f$'czy zadanie:/=/umożliwia dostęp do lewej $`i prawej strony $', a następnie $h{f$`}=f$'wykonuje przypisanie. I przypisujemy to również do $_tego, że jest domyślnie drukowane po każdej linii.

Dada
źródło
5

JavaScript (Node.js) , 81 bajtów

v=x=>(v[x]=v[x]||x,v[x]-x?v(v[x]):x)
f=x=>l=>v[v(x)]=l.reduce((p,x)=>v(v(x)+p),0)

Wypróbuj online!

Odbiera dane wejściowe, wywołując f z wartością do przypisania, a następnie wywołując wynik z tablicą wartości do dodania razem. (tj. f(5)([4])) Powtórz dla wielu linii.

vjest używany jako funkcja do obliczania rzeczywistej bieżącej wartości liczby, a także jako obiekt do przechowywania rzeczywistych wartości. Najpierw v[x]=v[x]||xzapewnia, że v[x]jest zdefiniowany. v[x]-xprzeprowadza porównanie w celu ustalenia, czy jest to rzeczywista liczba, czy nie. Jeśli liczba nie odwzorowuje się sama, v(v[x])rekurencyjnie próbuje ponownie, w przeciwnym razie powróć x.

f wykonuje obliczenia i przypisanie, curry, aby zapisać jeden bajt, gdzie drugie wywołanie zwraca obliczoną wartość.

OinkIguana
źródło
3

Haskell , 116 113 108 106 bajtów

(#)=until=<<((==)=<<)
e?((n,s):r)|m<-foldl1(\a b->e#(e#a+e#b))s=m:(\x->last$m:[e#x|x/=e#n])?r
e?r=[]
(id?)

Wypróbuj online! Każde równanie 4=3+1+5jest zapisywane jako krotka (4,[3,1,5]). Anonimowa funkcja (id?)pobiera listę takich krotek i zwraca listę wszystkich wyników pośrednich.

#to funkcja znajdująca punkt stały danej funkcji ei wartość początkową x.

Funkcja ?przyjmuje funkcję oceny ei rekurencyjnie rozwiązuje każde równanie. foldl1(\a b->e#(e#a+e#b))socenia prawą stronę równania i zapisuje wynik m, np. dla 4=3+1+5obliczeń eval(eval(eval 3 + eval 1) + eval 5), gdzie każda evaljest zastosowaniem punktu stałego e. Następnie funkcja eval jest modyfikowana w celu uwzględnienia nowego przypisania n: (\x->last$m:[e#x|x/=e#n])które jest takie samo jak \x -> if x == eval n then m else eval x.

Funkcja oceny wstępnej idodwzorowuje każdą liczbę całkowitą na siebie.


Dzięki Ørjan Johansen za krótszą funkcję punktu stałego, oszczędzającą 2 bajty!

Laikoni
źródło
Dobra robota! Nawiasem mówiąc, musisz zwrócić wszystkie wyniki pośrednie, abyś mógł upuścićlast.
Leo
2
(#)e=until((==)=<<e)elub (#)=until=<<((==)=<<)jest krótszy.
Ørjan Johansen
@ ØrjanJohansen Dzięki bardzo!
Laikoni,
3

ok, 48 bajtów

a:[];s:{*(a@x;x)^0N}/;f:{a[s@x]:y:{s@x+y}/s'y;y}

Stosowanie: f[5;1 2 3] / 5=1+2+3

Wypróbuj online!


Jeśli nie przeszkadza ci górny limit liczb, których możesz użyć, na przykład tylko przy użyciu liczb 0przez 998, to wystarczą następujące ( 41 bajtów ± kilka w zależności od maksimum):

a:!999;s:(a@)/;f:{a[s@x]:y:{s@x+y}/s'y;y}

Wyjaśnienie:

; oddziela trzy definicje.

ajest słownikiem / mapą liczb. W pierwszym przypadku jest to rzeczywisty, pusty słownik [], w drugim przypadku jest to lista liczb 0do 998.

sjest funkcją, która wyszukuje „wynikowy” numer, gdy otrzyma liczbę. /Na koniec pomocą funkcji, które będzie stosować się do jego własnej produkcji, aż wyjście przestaje się zmieniać.

Ostatni bit foznacza, że:

f:{                      } /function called f, input number x, list y
                    s'y    /apply s to every number in the list
                   /       /fold through the list
            {s@x+y}        /    sum the two numbers, apply s
   a[s@x]:                 /set the s(x) to map to the final sum
          y:           ;y  /redefine y to be the final sum, then return it
zgrep
źródło
3

Python 3, 146 132 130 bajtów

14 bajtów zapisanych dzięki @Dada
2 bajty zapisane dzięki @ mbomb007

d={}
g=lambda x:d.get(x)and x!=d[x]and g(d[x])or x
def f(t):
 for n,(s,*r)in t:
  for b in r:s=g(g(s)+g(b))
  d[g(n)]=s;yield g(n)

Wypróbuj online!

Odbiera dane wejściowe w postaci krotek równań [ x = y + z + was (x, (y, z, w))], dane wyjściowe przez generator.

Uriel
źródło
Czy możesz pokazać przykład wywołania, aby można go było przetestować?
Lew
1
@Leo dodał TIO.
Uriel
1
gprawdopodobnie można by napisać g=lambda x:d.get(x)and d[x]!=x and g(d[x])or x. I myślę, że możesz użyć 1 spacji do wcięcia zamiast 2. To powinno doprowadzić cię do [132 bajtów] ( Wypróbuj online! ).
Dada,
1
@Dada dzięki! szkoda, że ​​nie mają wcięcia półprzestrzeni: P
Uriel
1
Brak wcięcia na pół spacji, ale kolejną ciekawą sztuczką jest użycie jednej tabulacji zamiast dwóch spacji. Dopóki wcięcia są różne, Python jest zadowolony (możesz na przykład użyć spacji i tabulacji jako wcięć na dodatkowych zagnieżdżonych poziomach). Dzięki temu możesz zaoszczędzić dwa bajty :)
Leo