Riassumendo? Questo è il mio forte!


18

introduzione

Forte è un linguaggio esoterico molto peculiare basato sul concetto di modifica dei valori dei numeri. In Forte i numeri non sono costanti ma variabili, è possibile utilizzare l' LETistruzione per assegnare loro nuovi valori.

Ad esempio, dopo l'esecuzione LET 2=4-1da ora in poi 2assume il valore di 3, il che significa che ogni volta che il valore 2compare in un'espressione viene invece "sostituito" da 3. L'espressione (1+1)*2ora valuterebbe 9.

Questa istruzione in Forte viene utilizzata sia per la memorizzazione delle informazioni che per il controllo del flusso (le linee sono numerate e modificando il valore dei loro numeri è possibile determinare l'ordine della loro esecuzione). In questa sfida non affronteremo questo secondo aspetto.

La sfida

È necessario scrivere un interprete per un sottoinsieme semplificato delle LETespressioni di Forte .

Riceverai come input una serie di righe seguendo questa grammatica:

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

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

Nota: questa grammatica non è valida in quanto manca di numeri di riga, LET e parentesi (che sono sempre obbligatori)

Cioè, dovrai solo occuparti delle somme di calcolo e dell'assegnazione dei valori ai numeri. Le parentesi non saranno presenti nell'input e ogni espressione dovrà essere valutata da sinistra a destra: attenzione che i risultati parziali sono influenzati dalle ridefinizioni!

I numeri saranno sempre numeri interi non negativi, fino al limite del tipo intero nativo della tua lingua (o 2 ^ 32, a seconda di quale sia il valore più alto).

Per ogni riga dovresti produrre il risultato dell'espressione e assegnare questo risultato al valore (possibilmente riassegnato) del primo numero, che influenzerà il modo in cui verranno interpretate le seguenti righe.

Questo è , vince il codice più breve (in byte)!

Altre regole

  • Il formato di input è flessibile, ad esempio puoi prendere una singola stringa con newline, un elenco di stringhe, un elenco di elenchi di numeri ... Lo stesso vale per l'output, purché sia ​​chiaro quale sia il risultato di ogni espressione in l'ingresso.
  • È possibile inviare una funzione, un programma completo o una soluzione da eseguire in un ambiente REPL chiamandolo una volta per ogni linea.
  • Sono vietate le scappatoie standard , in particolare non è possibile chiamare un interprete Forte esterno nel proprio codice.

Esempi

Questi fanno tutti parte dello stesso input. Dopo ogni riga viene mostrato l'output previsto relativo a quella riga, a volte con un commento che indica le riassegnazioni pertinenti (non parte dell'output richiesto).

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

È 0un numero valido?
orlp

@orlp 0è valido ("I numeri saranno sempre numeri interi non negativi")
Leo

Dovremmo accettare eventuali operatori aritmetici?
bacchusbeale,

@bacchusbeale No, solo sommatoria.
Leo,

Esiste un numero massimo particolare o è grande quanto il tipo intero nativo della lingua? Inoltre, sarebbe un output non valido per restituire un elenco di numeri, uno dei quali è il risultato, giusto? (ad esempio la stampa del dizionario / mappa per il quale numero va a quale numero)
zgrep

Risposte:


4

Gelatina , 28 byte

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

Provalo online!

Questo è uno dei pochi programmi Jelly in cui sembra più difficile prendere input da input standard. È un programma completo (la scrittura di una funzione sarebbe stata più breve ma è vietata dalle regole PPCG, perché non verrà eseguita correttamente la seconda volta). Il formato di input è simile al seguente:

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

Spiegazione

Funzione helper 1Ŀ (traduce un numero intero nel suo valore)

®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.}

Piuttosto convenientemente, questa funzione di supporto funzionerà correttamente su un singolo valore o su un elenco di valori, a causa del modo in cui yè definito. Se viene fornito più di un mapping per un singolo valore, prendiamo il primo mapping dalla tabella. La tabella di mappatura è memorizzata nel registro (che è fondamentalmente solo una variabile; Jelly ha solo una variabile).

Funzione di supporto 2Ŀ (valutare un'istruzione 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}.

Non vogliamo davvero un valore di ritorno qui; stiamo solo eseguendo questo per i suoi effetti collaterali (aggiornamento del registro e emissione del valore assegnato). Tuttavia, le funzioni Jelly restituiscono sempre un valore, quindi lasciamo semplicemente restituire la tabella di mapping, poiché è più testata.

Programma principale

⁸©ḷƓÇ€¤
 ©       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}

Normalmente, ci darebbe il primo argomento della riga di comando quando eseguito in questo contesto, ma non ce n'è uno (stiamo prendendo input da input standard), quindi viene eseguito in una modalità alternativa che ci fornisce la stringa nulla. La necessità di inizializzare il registro (dal suo valore predefinito di 0, che si arresta in ymodo anomalo ) significa che non possiamo menzionare implicitamente l'input dell'utente, il che significa che è economico prenderlo dall'input standard ( Ɠ) come lo sarebbe prendere da un argomento della riga di comando ( ³o ) e poter accedere all'uso alternativo di significa che l'insolita (per Jelly) forma di input è in realtà un byte più breve.

È possibile che questo sia migliorabile. Non ho ancora capito perché la seconda riga debba dire ⁸Ǥ;piuttosto che solo ;@Ç- i due dovrebbero essere equivalenti, per quanto ho capito Jelly, data la mancanza di uso di µ/ ð/ ø- ma quest'ultimo si blocca per qualche motivo. Allo stesso modo, ci sono molti altri modi per riorganizzare il programma senza perdere byte, quindi è possibile che mi sia perso un modo per rendere le cose un po 'più brevi.

Per inciso, cambiando il nell'ultima riga per ;darti uno sguardo interessante sul funzionamento interno del programma, in quanto emetterà quindi la "storia del registro" che è implicitamente prodotta dai valori di ritorno di 2Ḷ.


5

Perl 5 , 92 byte

90 byte di codice + -plflag.

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

Provalo online!

Uso l'hashtable %hper memorizzare la mappatura tra numeri.
La funzione ( sub) frestituisce il numero a cui la sua mappa di input (o il suo input se non è mappato su nessun numero): $h{$a=pop}recupera il numero a cui la mappa di input. Se non è nessuno, grazie a //$a, il valore di ($b=$h{$a=pop}//$a)è input ( $a). Ci assicuriamo che questo valore non sia l'input stesso per non eseguire il loop all'infinito ( !=$a). Quindi, chiamiamo in modo ricorsivo fo restituiamo l'input.
Il programma principale prevede due passaggi:
- s%(\d+)\+(\d+)%f($1)+f$2%e&&redovaluta la prima aggiunta sul lato destro, mentre è ancora presente un'aggiunta: sostituisce x+ycon il risultato della valutazione di f(x)+f(y).
- /=/;$_=$h{f$`}=f$'fa l'incarico:/=/consente di accedere al lato sinistro con $`e al lato destro con $', quindi $h{f$`}=f$'esegue il compito. E lo assegniamo anche a $_quello che è implicitamente stampato dopo ogni riga.


5

JavaScript (Node.js) , 81 byte

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)

Provalo online!

Riceve input chiamando f con il valore a cui assegnare, quindi chiamando il risultato di quello con una matrice di valori da sommare. (es. f(5)([4])) Ripeti per più righe.

vviene utilizzato come funzione per calcolare il valore corrente effettivo di un numero e anche come oggetto per memorizzare i valori effettivi. Innanzitutto v[x]=v[x]||xassicura che v[x]sia definito. v[x]-xesegue un confronto per determinare se questo è il numero effettivo o meno. Se il numero non viene mappato su se stesso, v(v[x])riprova in modo ricorsivo, altrimenti ritorna x.

f esegue il calcolo e l'assegnazione, cercando di salvare un byte, in cui la seconda chiamata restituisce il valore calcolato.


3

Haskell , 116 113 108 106 byte

(#)=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?)

Provalo online! Ogni equazione 4=3+1+5è indicata come tupla (4,[3,1,5]). La funzione anonima (id?)prende un elenco di tali tuple e restituisce un elenco di tutti i risultati intermedi.

#è una funzione per trovare un punto fisso di una determinata funzione ee un valore iniziale x.

La funzione ?assume una funzione di valutazione ee risolve ricorsivamente ogni equazione. foldl1(\a b->e#(e#a+e#b))svaluta il lato destro di un'equazione e salva il risultato m, ad es. per il 4=3+1+5calcolo eval(eval(eval 3 + eval 1) + eval 5), in cui ciascuna evalè un'applicazione del punto fisso di e. Quindi la funzione eval viene modificata per tenere conto della nuova assegnazione di n: (\x->last$m:[e#x|x/=e#n])che è la stessa di \x -> if x == eval n then m else eval x.

La funzione di valutazione iniziale è idche mappa ogni intero su se stesso.


Grazie a Ørjan Johansen per una funzione di fixpoint più breve, risparmiando 2 byte!


Bel lavoro! A proposito, ti viene richiesto di restituire tutti i risultati intermedi, in modo da poter eliminarelast.
Leo

2
(#)e=until((==)=<<e)eo (#)=until=<<((==)=<<)è più corto.
Ørjan Johansen,

@ ØrjanJohansen Grazie mille!
Laikoni,

3

ok, 48 byte

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

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

Provalo online!


Se non vi occupate avente un limite superiore al numero è possibile utilizzare, ad esempio utilizzando solo numeri 0attraverso 998, quindi le seguenti suffissi ( 41 byte ± alcune seconda del massimo):

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

Spiegazione:

; separa tre definizioni.

aè un dizionario / mappa di numeri. Nel primo caso, è un dizionario reale, vuoto [], nel secondo caso è un elenco dei numeri 0a 998.

sè una funzione che trova il numero "risultante" quando viene assegnato un numero. L' /estremità della funzione indica che si applicherà al proprio output finché l'uscita non smetterà di cambiare.

L'ultimo bit f, significa che:

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

3

Python 3, 146 132 130 byte

14 byte salvati grazie a @Dada
2 byte salvati grazie a @ 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)

Provalo online!

Riceve input come tuple di equazioni [ x = y + z + was (x, (y, z, w))], output tramite generatore.


Puoi mostrare un esempio di invocazione in modo che possa essere testato?
Leo,

1
@Leo ha aggiunto TIO.
Uriel,

1
gprobabilmente potrebbe essere scritto g=lambda x:d.get(x)and d[x]!=x and g(d[x])or x. E penso che puoi usare 1 spazio per rientrare invece di 2. Questo dovrebbe portarti a [132 byte] ( Provalo online! ).
Dada,

1
@Dada grazie! peccato che non abbiano un rientro a metà spazio: P
Uriel

1
Nessun rientro di mezzo spazio, ma un altro trucco accurato sta usando una singola scheda anziché due spazi. Fintanto che le rientranze sono diverse, Python è contento (potresti ad esempio usare spazio-tab e tab-space come rientri su livelli nidificati aggiuntivi). Questo può farti risparmiare due byte :)
Leo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.