Un semplice sistema numerico


19

Lascia che ti parli di un semplice sistema di numeri. (che ho inventato solo per questa sfida)

Questo sistema contiene le funzioni (), [], {}e <>.

1. ()

Quando non ()viene fornito alcun argomento, viene valutato 0.

Quando ()viene fornito uno o più argomenti, viene valutata la somma degli argomenti.

2. []

Quando non []viene fornito alcun argomento, viene valutato -1.

Quando []viene fornito uno o più argomenti, viene valutato il primo argomento meno la somma degli altri argomenti.

3. {}

Quando non {}viene fornito alcun argomento, viene valutato 1.

Quando {}viene fornito uno o più argomenti, viene valutato il prodotto di tali argomenti.

4. <>

Quando non <>viene fornito alcun argomento, viene valutato 1.

Quando <>viene fornito uno o più argomenti, viene valutato il primo argomento intero diviso per il prodotto degli altri argomenti.

Il tuo compito

Data una stringa che contiene un numero valido (ciò significa che le parentesi sono bilanciate, nessuna divisione per 0, ecc.) In questo semplice sistema di numeri, stamparne il valore.

Casi test

() -> 0
(()()) -> 0
([][]) -> -2
({}<>) -> 2
({}[]) -> 0
[] -> -1
[[][]] -> 0
[()<>] -> -1
{()} -> 0
{([]<>)} -> 0

Ricorda, questo è , quindi vince il codice con il minor numero di byte.


13
Ho un ottimo nome per questo, che ho appena inventato e non ho ottenuto da nessun'altra parte: Brain-flake!
ETHproductions

4
@ETHproductions no
Oliver Ni


2
La divisione è divisione float o divisione intera?
xnor

1
@Oliver Come dovrebbe funzionare la divisione intera quando uno o entrambi gli operandi sono negativi? Quali sono i risultati attesi per 4 5/3, 5/-3, -5/3e -5/-3?
Martin Ender,

Risposte:


2

Dyalog APL , 94 byte

o←{(⊂(1⊃⍵),⍺⍺⊃⍵),2↓⍵}⋄u←{(⊃⍵,⍺⍺1)⍺⍺⍵⍵/1↓⍵}⋄⍎⍕'+/o' '-u+o' '×/o' '÷u×o' '(⊂⍬),'[')]}>'⍳⌽⍞],'⊂⍬'

usi ⎕IO←0

sostituisce )]}>con una chiamata di funzione che prende uno stack, applica un'operazione sul suo frame superiore, lo elimina e aggiunge il risultato al frame successivo ( oper questo viene utilizzato l' operatore monadico ; l'operatore diadico ugestisce i casi più complicati di -e ÷)

sostituisce ([{<con il codice che aggiunge un frame allo stack ( (⊂⍬),)

esegue l'espressione risultante (invertita, per abbinare l'ordine di esecuzione di APL) con uno stack iniziale di un frame vuoto ( ⊂⍬)


5

Haskell, 357 306 277 251 228 224 188 185 180 byte

Un parser basato su token con uno stack esplicito. (%)prende una pila di token e un carattere e preme (opcode, defaultnumber) o (0, numero) per({[< , oppure fa apparire i numeri più in alto e un opcode e spinge la risposta per )}]>. I codici operativi sono codificati da un hack di enumerazione ASCII.

Complimenti a @ChristianSievers per il suo grande risposta da cui ho preso in prestito alcune idee.

One-liner!

s%c|elem c"([<{",g<-div(fromEnum c)25=(g,[0,0,1,-1,1]!!g):s|(a,(o,n):b)<-span((==0).fst)s=(0,[foldr1(flip$[(+),quot,(-),(*)]!!(o-1))$snd<$>a,n]!!(0^length a)):b
snd.head.foldl(%)[]

Ora con meno gestione degli errori! Uso:

*Main> map (snd.head.foldl(%)[]) ["()","(()())","([][])","({}<>)","({}[])","[]","[[][]]","[()<>]","{()}","{([]<>)}"]
[0,0,-2,2,0,-1,0,-1,0,0]

Grazie @ChristianSievers per aver salvato 14 + 3 byte!

Grazie @Zgarb per aver salvato alcuni + 4 byte!


1
Che ne dici (0,[0,0,1,-1,1]!!o):sdella quinta riga?
Christian Sievers,

@ChristianSievers ovviamente!
Angs,

Cambia le definizioni di !, così puoi fare (s:_)!_=d scome il secondo caso. Inoltre, penso che potresti legare x<-p$d<$>init a,y<-d$last anell'ultimo caso di %.
Zgarb,

@Zgarb grazie! Ho trovato un modo per unificare ancora di più la valutazione.
Angs,

1
Sulla terza riga %puoi rilasciare parentesi _:be g c.
Zgarb,

3

Python 2, 292 265 248 235 223 206 204 byte

r=reduce
s=input()
for n in')]}>':s=s.replace(n,'),')
for a in'(*x:sum(x)','[a=-1,*x:a-sum(x)','{*x:r(int.__mul__,x,1)','<a=1,*x:r(int.__div__,x,a)':s=s.replace(a[0],'(lambda %s)('%a[1:])
print eval(s)[0]

Sostituisce tutte le parentesi con un lambda che fa quello che fa la parentesi, quindi valuta il codice Python risultante. Richiede il suo input circondato da virgolette, come '[<><>([]{})]'.

Questo programma memorizza il tipo di parentesi come primo carattere di ogni stringa in for, e tutto lambdail resto dopo la parola chiave . Quindi utilizza il primo carattere da sostituire; il resto è combinato in un lambda simile (lambda*x:sum(x))().

Provalo su Ideone!


3

PEG.js (ES6) , 132 byte

x=a:[([{<]b:x*[)\]}>]{var x='([<'.indexOf(a)
b.length^1||b.push(0)
return~~eval(b.length?b.join(('+-/'[x]||'*')+' '):~-('10'[x]||2))}

Ora dovrebbe essere risolto.

Spiegazione

Più leggibile:

x=a:[([{<]
  b:x*
  [)\]}>]
{
  var x='([<'.indexOf(a)
  b.length^1||b.push(0)
  return ~~eval(
    b.length?
      b.join(('+-/'[x]||'*')+' ')
    :~-('10'[x]||2))
  )
}

PEG.js è una versione estesa di Javascript creata appositamente per l'analisi. È MOLTO rigoroso, motivo per cui ho dovuto usare var. Inoltre, sembra esserci un bug con parentesi all'interno delle stringhe, che gonfia il codice in modo significativo.

Per iniziare, definiamo una regola xche corrisponde a qualsiasi parentesi ache può contenere o meno espressioni multiple che corrispondono alla regola x.

Per ogni partita da governare x, spingiamo uno 0 nella matrice della corrispondenza interna bse bla lunghezza è 1.

Se bla lunghezza è> 0, allora troviamo l'indice di ain ([<e otteniamo un carattere +-/dall'uso di quell'indice. Se il risultato non è definito (nel senso che aera {), quindi trasformiamo il risultato in *. Infine, puntiamo su uno spazio e ci uniamo bal risultato.

Se b's length = 0, allora troviamo l'indice di ain ([<e otteniamo un carattere 10dall'uso di quell'indice. Se il risultato non è definito (nel senso che aera {o <), allora trasformiamo il risultato in 2. Infine, semplicemente diminuiamo.

Alla fine, possiamo semplicemente valutare l'espressione e definire il risultato.


3

Perl, 113 + 2 = 115 byte

Esegui con -lp(penalità di 2 byte).

/\W/,eval"sub $`\{\$#_?(shift)$&&$'1}"for qw'a+a:1- b-a:- c*c: d/c:';y/([{</a-d/;s/\W/0),/g;s/\pL\K/(/g;$_=eval

Più leggibile (nota: questa "versione più leggibile" in realtà non verrà eseguita, perché ho inserito commenti in punti in cui non sono sintatticamente ammessi):

              # -p option: read a line of input into $_ at program start
              # -l option: remove the final newline whenever reading
do {          # for each element of a list, given later:
  /\W/;       # place an initial identifier in $`, the next character in
              # $&, and the rest of the element in $'
  eval qq{    # then evaluate the following template, with substitutions:
    sub $` {  # define a subroutine named $`, that does this:
      \$#_ ?  # if there is more than one argument                   
      (shift) # then return the first argument $&-ed with
      $& &$'  # the result of a recursive call with the tail of the arguments
              # else (the "else" is a colon taken from $', not the template)
      1       # return (the remainder of $' applied to) 1
    }
  }
} for qw'     # specify the list by splitting the following on whitespace:        
  a+a:1-      # a(head,tail) = len(tail>1) ? head+a(tail) : 1-1
  b-a:-       # b(head,tail) = len(tail>1) ? head-a(tail) : -1
  c*c:        # c(head,tail) = len(tail>1) ? head*c(tail) : 1
  d/c:        # d(head,tail) = len(tail>1) ? head/c(tail) : 1
';
y/([{</a-d/;  # replace ( [ { < with a b c d in $_
s/\W/0),/g;   # replace whitespace, punctuation in $_ with the string "0),"
s/\pL\K/(/g;  # place a ( after (\K) each letter (\pL) in $_
$_=eval       # evaluate $_ as a Perl program, storing the result back in $_
              # -p option: print $_ to the user at program end
              # -l option: output a newline whenever printing

L'idea di base è che stiamo convertendo un input simile [()<>]al programma Perl b(a(0),d(0),0),tramite l'elaborazione del testo; Perl sta bene con la virgola finale. In precedenza, abbiamo definito le funzioni a, b, c, dper avere lo stesso effetto come (), [], {}, <>costrutti del linguaggio che stiamo attuazione; entrambi ignorano il loro ultimo argomento (lo 0 alla fine), che è incluso per garantire che tutti gli input vengano analizzati correttamente, e lavorano usando l'implementazione comunemente vista nella programmazione funzionale in cui la testa e la coda vengono elaborate separatamente. Perché b(e,f,g,0)significa e-f-g, cioè tratta il suo primo argomento in particolare, mentre atratta i suoi argomenti in modo simmetrico (a(e,f,g,0) mezzi e+f+g), noi implementiamoaricorsivamente e btramite chiamata a. ce dhanno una relazione simile. Tutte e quattro queste funzioni sono molto simili, quindi le generiamo in fase di esecuzione anziché implementarle separatamente; memorizziamo un modello che si applica a tutte e quattro le funzioni in una stringa, quindi generiamo le funzioni sostituendo i caratteri nel modello.

Poiché Perl /esegue una divisione in virgola mobile, anche l'implementazione lo {}fa. Suppongo che questo non sia un problema a sé stante, oppure -Minteger(la selezione di una variante del linguaggio in cui tutte le operazioni aritmetiche sono operazioni intere) è gratuito, perché altrimenti dovrei spendere byte extra scrivendo una divisione di numeri interi in Perl, che non sembra essere il problema fondamentale. (Penso che dovresti spendere quattro byte cambiando (shift)in int+(shift); non l'ho provato.)


2

Ottava, 215 206 198 byte

S='sum(x(:))-sum(x(2:end))';Y='(@(x)isempty(x)';c=']) ';[~,~,u]=unique(['()<>[]{}',input('')]);eval([{'sum([',c,[Y,'+fix((',S,')/prod(x(2:end))))(['],c,[Y,'*-1+',S,'*2)(['],c,'prod([',c}{u(9:end)}])

provalo online


2

PHP, 315 300 285 258 250 244 byte

for($s=$argv[1];$r=!$r;)foreach(["(+)1","[-]0","{*}2","</>2]as$p)if(preg_match("#$e$p[0]([-_\d]*)$e$p[2]#",$s,$m)){if(""==$v=strtok($m[1],_))$v=$p[3]-1;while(""<$n=strtok(_))eval("\$v$p[1]=$n;");$s=strtr($s,[$m[$r=0]=>_.$v]);}echo substr($s,1);

sostituisce le sottoespressioni con underscore + valore; il ciclo si interrompe quando l'iterazione non viene sostituita.

19 anni da quando ho incontrato C per la prima volta, 17 anni lavorando con PHP;
questa è la prima volta che strtokha un senso ... aiutando a salvare 24 byte!

abbattersi

for($s=$argv[1];    // take input from argument
    $r=!$r;)        // toggle $r; loop until no replacement has taken place
    foreach(["(+)1","[-]0","{*}2","</>2]as$p) // loop through operations
        if(preg_match("#$e$p[0]([-_\d]*)$e$p[2]#",$s,$m))   // find a match
        {
            if(""==$v=strtok($m[1],_))  // init $v with first token from sub-match
                $v=$p[3]-1;             // if no token, init with default value
            while(""<$n=strtok(_))      // loop through tokens
                eval("\$v$p[1]=$n;");       // operate
            $s=strtr($s,[$m[$r=0]=>_.$v]);  // reset $r; replace match with underscore+value
        }
echo substr($s,1);  // print result

@Oliver non batte nessuno qui; ma grazie per il divertimento!
Tito

2

ES6 (Javascript), 250, 171, 154, 149, 147 byte

Una versione Javascript pura.

La "metaprogrammazione" (come la maggior parte delle altre risposte qui), converte il testo del programma di input in un corrispondente programma Javascript, applicando ad esso una serie di sostituzioni di testo diretto (cioè mantenendo la struttura del programma così com'è).

Probabilmente può essere ulteriormente giocato a golf.

AGGIORNAMENTO (v2.1)

  • Meno due byte (parentesi rimossa nell'espressione ternaria)
  • Scolpito di altri 5 byte, usando la variabile per l'estrazione dei risultati e eliminando "[]" extra

AGGIORNAMENTO (v2)

Ho appena realizzato che le virgole in sospeso nelle matrici ES sono totalmente valide, quindi è possibile rimuovere l'intero codice di normalizzazione delle virgole. Ha anche seguito un eccellente consiglio di @Titus, sull'ottimizzazione della ricerca alfabetica.

AGGIORNAMENTO (v1)

Alias ​​duplicato "sostituito" rimosso.

AGGIORNAMENTO (v1)

  • Usa un alfabeto migliore: () => 1+ [] => 0 {} => 2 * <> => 2 / (ogni carattere può essere riutilizzato direttamente come valore o operatore)

  • Sostituito riduci () con replace () (mappatura alfabetica)

  • Elaborazione della staffa di allineamento, apertura e chiusura costanti unite in un unico passaggio

Golfed (v2.1)

s=>eval("o="+s.replace(/./g,r=>"2+1-3*3/"["()[]{}<>".indexOf(r)]).replace(/\d\D?|\D/g,r=>r[1]?r[0]-2+",":r*1?'([':`].reduce((r,a)=>r${r}a)),`)+"o

Golfed (v1)

(s,A="(2)+[1]-{3}*<3>/")=>eval(s[R="replace"](/./g,r=>A[A.indexOf(r)+1])[R](/\d\D?|\D/g,r=>r[1]?r[0]-2+",":(r[0]*1?'([':`].reduce((r,a)=>r${r}a)),`))[R](/,(\])|,$/g,"$1"))    

Golfed (v0)

([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')[R](/[aceg]/g,"([")[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)[R](/,(\])|,$/g,"$1"))

Spiegato (v0)

//BEGIN 

//s - input text, A - alphabet, R - "String.replace()" alias
E=([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(

//Replace input alphabet by a more friendly one, to avoid too much escaping and quoting
// () - ab, [] -cd, {} - ef, <> - gh
s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')

//Replace no-arg invocations with a corresponding constant value
// () => 0, [] => -1, {} => 1, <> => 1      
[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')

//Replace opening brackets with "(["
[R](/[aceg]/g,"([")

//Replace closing brackets with "].reduce(...)),"
//An arithmetic operation to apply (+-*/) is chosen based on the bracket type 
//and is substituted into the template 
[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)

//Strip excessive commas
[R](/,(\])|,$/g,"$1")
);

//END: eval() the result


Example:
E("{([]<>()<>{})(<><>)}")
=> eval("([([-1,1,0,1,1].reduce((r,a)=>r+a)),([1,1].reduce((r,a)=>r+a))].reduce((r,a)=>r*a))")
=> 4

Test

E=([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')[R](/[aceg]/g,"([")[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)[R](/,(\])|,$/g,"$1"))

T=(s,a)=>{
    console.log(s,r=E(s),r==a?"OK":"NOT OK");
}

T("()",0)
T("(()())",0) 
T("([][])",-2)
T("({}<>)",2) 
T("({}[])",0) 
T("[]",-1)
T("[[][]]",0) 
T("[()<>]",-1) 
T("{()}",0) 
T("{([]<>)}",0)

Uscita di prova

() 0 OK
(()()) 0 OK
([][]) -2 OK
({}<>) 2 OK
({}[]) 0 OK
[] -1 OK
[[][]] 0 OK
[()<>] -1 OK
{()} 0 OK
{([]<>)} 0 OK

1
La tua versione v0 potrebbe andare con s.reduce((r,c)=>r+="abcdefgh"["()[]{}<>".indexOf(c)],'')(-5)? in tal caso, potresti ricordare indexOfin una variabile e prendere l'operatore da una terza stringa letterale.
Tito

2

Haskell, 184 179 172 161 160 159 151 148 145 byte

s%(c:i)|elem c")}]>"=([1?(*),sum,1?quot,(-1)?(-)]!!mod(fromEnum c)5$s,i)|(r,j)<-[]%i=(s++[r])%j
[v]%e=(v,e)
(v?_)[]=v
(_?o)s=foldl1 o s
fst.([]%)

Discesa ricorsiva, infilando l'input perché Haskell. Come al solito, l'ultima riga non è una definizione, ma indica la funzione che risolve il problema. Quindi, per testare, metti le righe tranne l'ultima in un file, caricalo e fai qualcosa del genere:

*Main> fst.([]%) $ "{([][][])([][])}"
6

Grazie a @Zgarb per l'ispirazione e molti suggerimenti dettagliati, e @Angs per l'ispirazione dalla sua soluzione e altri suggerimenti.

Non è stato specificato come la divisione dovrebbe comportarsi con numeri interi negativi. Ad ogni modo, l'uso ripetuto divsembra sbagliato, poiché non è lo stesso che usare divuna volta con il prodotto dei valori rimanenti. Ora usando quot, ottengo gli stessi risultati per <{}([][])[]>e <{}{([][])[]}>.

Per un codice piacevole, quasi leggibile, guarda la prima versione. Le versioni intermedie contengono tutti i tipi di codice simpatico e intimidatorio e aiutano a comprendere questa versione.


Penso che puoi salvare un paio di byte definendo (!)=(,)e usando al !posto di tuple esplicite.
Zgarb,

Se si definisce m xe d xcome 1#xe 0#x, è possibile unire i casi m[x]e d[x]in uno, che credo di risparmiare alcuni byte troppo.
Zgarb,

@Zgarb Grazie! Ho quasi perso l'ultima coppia, senza la quale il !trucco non paga. Il tuo secondo suggerimento è malvagio, ecco il mio codice quasi leggibile ... Intelligente!
Christian Sievers,

Heh, ho appena capito che la definizione s%(c:i)=(s?c,i)e s?')'=sum scosì via saranno molto più brevi, dato che puoi sbarazzarti delle ripetute i. ..Non aspettare, probabilmente non funzionerà a causa del s%(_:i)caso.
Zgarb,

1
Perdere i backtick su eleme div, questo dovrebbe salvare qualche altro byte.
Zgarb,

1

JavaScript (ES6), no eval, 156 byte

f=s=>s==(s=s.replace(/(.) ?([- \d]*)[\]})>]/,(_,c,s)=>` `+(s?s.split` `.reduce((l,r)=>c<`<`?l- -r:c<`[`?l/r|0:c<`{`?l-r:l*r):c==`[`?-1:c==`(`?0:1)))?+s:f(s)

Spiegazione: regexp trova la prima parentesi quadra di chiusura non elaborata e corrisponde alla parentesi di apertura (presumibilmente) corrispondente e agli argomenti in mezzo. Gli argomenti vengono suddivisi e ridotti in base all'operazione (purtroppo '(' e '[' non sono la coppia ottimale per +e -), oppure se non ci sono argomenti viene calcolato il valore appropriato (anche in questo caso la corrispondenza dei caratteri con i valori è non ottimale dal mio punto di vista). Il risultato viene quindi sostituito con uno spazio iniziale in modo da separarlo da altri risultati. La funzione quindi si chiama ricorsivamente fino a quando non ci sono più modifiche da apportare, nel qual caso restituisce il valore risultante. Esempio:

[()<>]
[ 0<>]
[ 0 1]
 -1

f ("([] [])") => 0 (invece di 2)
zeppelin

Alcuni altri test falliscono anche per me (puoi provare il codice di test nella mia risposta ), probabilmente a causa di: f ("[]") => 0, poiché "[]" fa parte di ogni test fallito.
zeppelin,

@zeppelin Oops, a causa del cattivo golf. Sono tornato a una versione precedente, ma purtroppo mi costa un paio di byte.
Neil,
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.