Ein einfaches Zahlensystem


19

Lassen Sie sich von einem einfachen Zahlensystem erzählen. (was ich nur für diese Herausforderung erfunden habe)

Dieses System enthält die Funktionen (), [], {}, und <>.

1. ()

Wenn ()keine Argumente angegeben werden, wird dies zu ausgewertet 0.

Wenn ()ein oder mehrere Argumente angegeben werden, ergibt dies die Summe der Argumente.

2. []

Wenn []keine Argumente angegeben werden, wird dies zu ausgewertet -1.

Wenn []ein oder mehrere Argumente angegeben werden, ergibt dies das erste Argument abzüglich der Summe der anderen Argumente.

3. {}

Wenn {}keine Argumente angegeben werden, wird dies zu ausgewertet 1.

Wenn {}ein oder mehrere Argumente angegeben werden, wird das Produkt dieser Argumente ausgewertet.

4. <>

Wenn <>keine Argumente angegeben werden, wird dies zu ausgewertet 1.

Wenn <>ein oder mehrere Argumente angegeben werden, wird das erste Argument als Ganzzahl dividiert durch das Produkt der anderen Argumente ausgewertet.

Deine Aufgabe

Wenn ein String eine gültige Zahl enthält (dh Klammern sind ausgeglichen, keine Division durch 0 usw.), wird sein Wert in diesem einfachen Zahlensystem ausgegeben.

Testfälle

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

Denken Sie daran, das ist , also gewinnt der Code mit den wenigsten Bytes.


13
Ich habe dafür einen tollen Namen, den ich mir total ausgedacht habe und von nirgendwo anders bekommen habe: Brain-Flake!
ETHproductions

4
@ETHproductions no
Oliver Ni


2
Ist Division Float Division oder Integer Division?
xnor

1
@Oliver Wie soll die Ganzzahldivision funktionieren, wenn einer oder beide Operanden negativ sind? Was sind die 4 erwarteten Ergebnisse für 5/3, 5/-3, -5/3und -5/-3?
Martin Ender

Antworten:


2

Dyalog APL , 94 Bytes

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

Verwendet ⎕IO←0

wird )]}>durch einen Funktionsaufruf ersetzt , der einen Stapel annimmt, eine Operation auf sein oberes Bild anwendet, es löscht und das Ergebnis an sein nächstes Bild anfügt (dafür wird der monadische Operator overwendet; der dyadische Operator ubehandelt die komplizierteren Fälle von -und ÷)

wird ([{<durch Code ersetzt , der dem Stack einen Frame hinzufügt ( (⊂⍬),)

führt den resultierenden Ausdruck (umgekehrt, um der Ausführungsreihenfolge von APL zu entsprechen) mit einem Anfangsstapel von einem leeren Frame aus (⊂⍬ )


5

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

Ein Token-basierter Parser mit einem expliziten Stack. (%)Nimmt einen Token-Stack und ein Zeichen und drückt entweder (Opcode, Standardnummer) oder (0, Nummer) für({[< , oder gibt die obersten Zahlen und einen opcode ein und drückt die Antwort für )}]>. Opcodes werden von einem ASCII-Aufzählungs-Hack codiert.

Ein großes Lob an @ChristianSievers für seine großartige Leistung Antwort , von der ich einige Ideen ausgeliehen habe.

Einzeiler!

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(%)[]

Jetzt mit weniger Fehlerbehandlung! Verwendung:

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

Vielen Dank an @ChristianSievers für das Speichern von 14 + 3 Bytes!

Vielen Dank an @Zgarb für das Speichern von einigen + 4 Bytes!


1
Wie wäre es (0,[0,0,1,-1,1]!!o):sin der fünften Zeile?
Christian Sievers

@ ChristianSievers natürlich!
Angs

Ändern Sie die Definitionen von !, damit Sie (s:_)!_=d sden zweiten Fall durchführen können. Auch ich denke, Sie könnten x<-p$d<$>init a,y<-d$last aim letzten Fall von binden %.
Zgarb

@ Zgarb danke! Ich habe einen Weg gefunden, die Bewertung noch mehr zu vereinheitlichen.
Angs

1
In der dritten Zeile %können Sie Parens um _:bund ablegen g c.
Zgarb

3

Python 2, 292 265 248 235 223 206 204 Bytes

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]

Ersetzt alle Klammern durch ein Lambda, das die gleiche Funktion wie die Klammer hat, und wertet dann den resultierenden Python-Code aus. Benötigt seine Eingabe in Anführungszeichen, wie '[<><>([]{})]'.

Dieses Programm speichert den Klammertyp als erstes Zeichen in jeder Zeichenfolge im forund alles nach dem Schlüsselwortlambda als Rest. Dann wird das erste Zeichen zum Ersetzen verwendet. Der Rest wird zu einem Lambda-ähnlichen Wert kombiniert (lambda*x:sum(x))().

Probieren Sie es auf Ideone!


3

PEG.js (ES6) , 132 Bytes

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

Sollte jetzt behoben sein.

Erläuterung

Besser lesbar:

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 ist eine erweiterte Version von Javascript, die speziell für das Parsen entwickelt wurde. Es ist sehr streng, weshalb ich verwenden musstevar . Außerdem scheint es einen Fehler mit eckigen Klammern innerhalb von Strings zu geben, der den Code erheblich aufblähte.

Zunächst definieren wir eine Regel x, die mit einer beliebigen Klammer übereinstimmt a, die mehrere Ausdrücke enthalten kann oder nicht, die mit der Regel übereinstimmen x.

Für jede zu regelnde Übereinstimmung geben xwir eine 0 in das Array der inneren Übereinstimmung ein, bwenn bdie Länge 1 ist.

Wenn bdie Länge> 0 ist, finden wir den Index von ain ([<und erhalten ein Zeichen aus +-/diesem Index. Wenn das Ergebnis undefiniert ist (das heißt das awar {), machen wir das Ergebnis zu *. Schließlich wenden wir uns einem Leerzeichen zu und schließen uns bdem Ergebnis an.

Wenn bdie Länge = 0 ist, finden wir den Index von ain ([<und erhalten ein Zeichen aus 10diesem Index. Wenn das Ergebnis undefiniert ist (dh das awar {oder <), machen wir das Ergebnis zu 2. Schließlich dekrementieren wir einfach.

Am Ende können wir nur den Ausdruck bewerten und das Ergebnis begrenzen.


3

Perl, 113 + 2 = 115 Bytes

Laufen Sie mit -lp(2-Byte-Strafe).

/\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

Besser lesbar (Hinweis: Diese "besser lesbare Version" wird nicht ausgeführt, da ich Kommentare an Stellen platziere, an denen sie syntaktisch nicht zulässig sind.):

              # -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

Die Grundidee ist, dass wir eine Eingabe wie [()<>]in das Perl-Programm b(a(0),d(0),0),per Textverarbeitung konvertieren . Perl ist mit dem nachgestellten Komma einverstanden. Früher haben wir die Funktionen definiert a, b, c, ddie gleiche Wirkung wie das haben (), [], {}, <>sind die Umsetzung Konstrukte aus der Sprache , die wir; Sie ignorieren jeweils ihr letztes Argument (die 0 am Ende), das enthalten ist, um sicherzustellen, dass alle Eingaben korrekt analysiert werden, und verwenden die in der funktionalen Programmierung übliche Implementierung, bei der Kopf und Schwanz getrennt verarbeitet werden. Weil b(e,f,g,0)means e-f-g, dh sein erstes Argument speziell abehandelt , während a(e,f,g,0)means seine Argumente symmetrisch behandelt e+f+g, implementieren wirarekursiv und bper Aufruf a. cund dhaben eine ähnliche Beziehung. Alle vier Funktionen sind sich sehr ähnlich, daher generieren wir sie zur Laufzeit, anstatt sie separat zu implementieren. Wir speichern eine Vorlage, die für alle vier Funktionen in einer Zeichenfolge gilt, und generieren dann die Funktionen, indem wir Zeichen in die Vorlage einsetzen.

Da Perl eine /Gleitkommadivision durchführt, ist {}dies auch bei der Implementierung der Fall. Ich gehe davon aus, dass dies entweder kein eigenständiges Problem ist oder dass die -MintegerAuswahl einer Sprachvariante (bei der alle arithmetischen Operationen Ganzzahloperationen sind) kostenlos ist, da ich sonst zusätzliche Bytes für das Schreiben einer Ganzzahldivision in Perl aufwenden müsste. Das scheint nicht das zu sein, worum es im Grunde geht. (Ich glaube , man müßte vier Bytes verbringt Wechsel (shift)zu int+(shift);. Ich kann das nicht getestet)


2

Oktave, 215 206 198 Bytes

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)}])

versuche es online


2

PHP, 315 300 285 258 250 244 Bytes

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);

Ersetzt Unterausdrücke durch Unterstrich + Wert. Die Schleife bricht ab, wenn die Iteration nicht ersetzt wurde.

19 Jahre, seit ich C das erste Mal getroffen habe, 17 Jahre Arbeit mit PHP;
Dies ist das erste Mal, dass strtokes Sinn macht, 24 Bytes einzusparen!

Nervenzusammenbruch

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 schlägt hier niemanden; aber danke für den spaß!
Titus

2

ES6 (Javascript), 250, 171, 154, 149147 Bytes

Eine reine Javascript-Version.

"Metaprogramming" (wie die meisten anderen Antworten hier) konvertiert den eingegebenen Programmtext in ein entsprechendes Javascript-Programm, indem eine Reihe direkter Textsubstitutionen daran vorgenommen werden (dh die Programmstruktur bleibt unverändert).

Kann wahrscheinlich weiter golfen werden.

UPDATE (v2.1)

  • Minus zwei Bytes (entfernte Klammer im ternären Ausdruck)
  • 5 Bytes mehr Zeit gespart, indem eine Variable für die Ergebnisextraktion verwendet und zusätzliches "[]" entfernt wurde

UPDATE (v2)

Nur erkannt, dass ausstehende Kommas in ES-Arrays vollständig gültig sind, sodass der gesamte Kommanormalisierungscode entfernt werden kann. Es folgte auch ein ausgezeichneter Rat von @Titus zur Optimierung der Alphabet-Suche.

UPDATE (v1)

Doppelter "Ersetzen" -Alias ​​wurde entfernt.

UPDATE (v1)

  • Verwenden Sie ein besseres Alphabet: () => 1+ [] => 0 {} => 2 * <> => 2 / (jedes Zeichen kann direkt als Wert oder Operator wiederverwendet werden)

  • Redu () durch replace () ersetzt (Alphabetische Zuordnung)

  • Konstante Inlining-, Open- und Closing-Bracket-Verarbeitung in einem Schritt zusammengeführt

Golf (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

Golf (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"))    

Golf (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"))

Erklärt (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

Prüfung

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)

Ausgang testen

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

1
Könnte Ihre v0-Version mit s.reduce((r,c)=>r+="abcdefgh"["()[]{}<>".indexOf(c)],'')(-5) gehen? In diesem Fall können Sie sich an indexOfeine Variable erinnern und den Operator aus einem dritten Zeichenfolgenliteral übernehmen.
Titus

2

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

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.([]%)

Rekursiver Abstieg, Threading der Eingabe wegen Haskell. Wie üblich ist die letzte Zeile keine Definition, sondern gibt die Funktion an, die das Problem löst. Um dies zu testen, setzen Sie die Zeilen mit Ausnahme der letzten in eine Datei, laden Sie sie und führen Sie so etwas aus:

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

Vielen Dank an @Zgarb für die Inspiration und viele detaillierte Hinweise und an @Angs für die Inspiration von seiner Lösung und weiteren Hinweisen.

Es wurde nicht festgelegt, wie sich die Division bei negativen Ganzzahlen verhalten soll. Wie auch immer, die wiederholte Verwendung divscheint falsch, da sie nicht mit der diveinmaligen Verwendung des Produkts der verbleibenden Werte identisch ist . Wenn quotich jetzt benutze , erhalte ich die gleichen Ergebnisse für <{}([][])[]>und <{}{([][])[]}>.

Für schönen, fast lesbaren Code schauen Sie sich die erste Version an. Die Zwischenversionen enthalten alle Arten von nettem und einschüchterndem Code und helfen, diese Version zu verstehen.


Ich denke, Sie können ein paar Bytes sparen, (!)=(,)indem Sie !statt expliziter Tupel definieren und verwenden .
Zgarb

Wenn Sie m xund d xals 1#xund definieren 0#x, können Sie die Fälle m[x]und d[x]in einen zusammenführen, was meiner Meinung nach auch einige Bytes einspart.
Zgarb

@ Zgarb Danke! Ich habe fast das letzte Paar verpasst, ohne das sich der !Trick nicht auszahlt. Dein zweiter Vorschlag ist böse, da geht mein fast lesbarer Code ... Clever!
Christian Sievers

Heh, das habe ich gerade gemerkt s%(c:i)=(s?c,i) und s?')'=sum susw. viel kürzer sein werden, da Sie die wiederholten is loswerden können . ..Keine Wartezeit, das wird wahrscheinlich wegen des s%(_:i)Falls nicht funktionieren .
Zgarb

1
Lose die Backticks auf elem und div, das sollte ein paar Bytes mehr sparen.
Zgarb

1

JavaScript (ES6), nein 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)

Erläuterung: Der reguläre Ausdruck findet die erste nicht verarbeitete schließende Klammer und stimmt mit der (vermutlich) entsprechenden öffnenden Klammer und allen dazwischen liegenden Argumenten überein. Die Argumente werden entsprechend der Operation aufgeteilt und reduziert (leider sind '(' und '[' nicht das optimale Paar für +und -), oder wenn es keine Argumente gibt, wird der entsprechende Wert berechnet (wiederum ist die Übereinstimmung von Zeichen mit Werten suboptimal) aus meiner Sicht) .Das Ergebnis wird dann durch ein vorangestelltes Leerzeichen ersetzt, um es von anderen Ergebnissen zu trennen.Die Funktion ruft sich dann rekursiv auf, bis keine Änderungen mehr vorgenommen werden müssen, und gibt in diesem Fall den resultierenden Wert zurück. Beispiel:

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

f ("([] [])") => 0 (anstelle von 2)
Zeppelin

Einige andere Tests schlagen für mich ebenfalls fehl (Sie können den Testcode in meiner Antwort ausprobieren), wahrscheinlich aufgrund von: f ("[]") => 0, da "[]" ein Teil jedes fehlgeschlagenen Tests ist.
Zeppelin

@zeppelin Hoppla, das war auf schlechtes Golfen zurückzuführen. Ich habe auf eine frühere Version zurückgegriffen, aber das kostet mich leider ein paar Bytes.
Neil
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.