Sistem bilangan sederhana

19

Biarkan saya memberi tahu Anda tentang sistem bilangan sederhana. (yang saya buat hanya untuk tantangan ini)

Sistem ini berisi fungsi (), [], {}, dan <>.

1. ()

Ketika ()tidak diberikan argumen, itu dievaluasi untuk 0.

Ketika ()diberikan satu atau lebih argumen, itu mengevaluasi jumlah argumen.

2. []

Ketika []tidak diberikan argumen, itu dievaluasi untuk -1.

Ketika []diberikan satu atau lebih argumen, ia mengevaluasi argumen pertama dikurangi jumlah argumen lainnya.

3. {}

Ketika {}tidak diberikan argumen, itu dievaluasi untuk 1.

Ketika {}diberikan satu atau lebih argumen, ia mengevaluasi produk dari argumen tersebut.

4. <>

Ketika <>tidak diberikan argumen, itu dievaluasi untuk 1.

Ketika <>diberikan satu atau lebih argumen, itu mengevaluasi ke integer argumen pertama dibagi dengan produk dari argumen lain.

Tugas Anda

Diberikan string yang berisi angka yang valid (itu berarti tanda kurung seimbang, tidak ada pembagian dengan 0s, dll.) Dalam sistem angka sederhana ini, cetak nilainya.

Uji kasus

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

Ingat, ini adalah , jadi kode dengan byte paling sedikit menang.

Oliver Ni
sumber
13
Saya memiliki nama yang bagus untuk ini, yang saya benar-benar hanya membuat dan tidak mendapatkan dari tempat lain: Brain-flake!
ETHproduk
4
@ETHProduk no
Oliver Ni
Semacam terkait
DJMcMayhem
2
Apakah divisi float Division atau Integer Division?
xnor
1
@Liver Bagaimana seharusnya pembagian integer bekerja ketika satu atau kedua operan negatif? Apa 4 hasil yang diharapkan untuk 5/3, 5/-3, -5/3dan -5/-3?
Martin Ender

Jawaban:

2

Dyalog APL , 94 byte

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

menggunakan ⎕IO←0

menggantikan )]}>dengan pemanggilan fungsi yang mengambil tumpukan, menerapkan operasi pada frame atasnya, menghapusnya, dan menambahkan hasilnya ke frame berikutnya (operator monadik odigunakan untuk itu; operator dyadic umenangani kasus yang lebih rumit dari -dan ÷)

diganti ([{<dengan kode yang menambahkan bingkai ke tumpukan ( (⊂⍬),)

mengeksekusi ekspresi yang dihasilkan (terbalik, agar sesuai dengan urutan eksekusi APL) dengan tumpukan awal dari satu frame kosong ( ⊂⍬)

ngn
sumber
5

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

Parser berbasis token dengan tumpukan eksplisit. (%)mengambil token stack dan karakter dan mendorong (opcode, defaultnumber) atau (0, number) untuk ({[<, atau muncul nomor paling atas dan satu opcode dan mendorong jawaban untuk )}]>. Opcode dikodekan oleh peretas enumerasi ascii.

Salam kepada @ChristianSievers atas jawaban besarnya yang saya pinjam dari beberapa ide.

Satu garis!

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

Sekarang dengan lebih sedikit penanganan kesalahan! Pemakaian:

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

Terima kasih @ChristianSievers untuk menghemat 14 + 3 byte!

Terima kasih @Zgarb untuk menghemat +4 byte!

Angs
sumber
1
Bagaimana dengan (0,[0,0,1,-1,1]!!o):sdi baris kelima?
Christian Sievers
@ChristianSievers tentu saja!
Angs
Ganti definisi !, sehingga Anda dapat melakukan (s:_)!_=d ssebagai kasus kedua. Juga, saya pikir Anda bisa mengikat x<-p$d<$>init a,y<-d$last adalam kasus terakhir %.
Zgarb
@ Zgarb terima kasih! Saya menemukan cara untuk menyatukan evaluasi lebih lanjut.
Angs
1
Di baris ketiga %Anda bisa meletakkan parens di sekitar _:bdan 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]

Mengganti semua tanda kurung dengan lambda yang melakukan apa yang dilakukan braket, kemudian mengevaluasi kode Python yang dihasilkan. Membutuhkan inputnya dikelilingi oleh tanda kutip, seperti '[<><>([]{})]'.

Program ini menyimpan jenis braket sebagai karakter pertama di setiap string di for, dan semuanya setelah kata kunci lambdasebagai sisanya. Kemudian menggunakan karakter pertama untuk menggantikan; sisanya digabung menjadi seperti lambda (lambda*x:sum(x))().

Cobalah di Ideone!

Tembaga
sumber
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))}

Harus diperbaiki sekarang.

Penjelasan

Lebih mudah dibaca:

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 adalah versi Javascript tambahan yang dibuat khusus untuk parsing. Ini SANGAT ketat, itulah sebabnya saya harus menggunakan var. Selain itu, tampaknya ada bug dengan tanda kurung di dalam string, yang membengkak kode secara signifikan.

Untuk memulai, kami menetapkan aturan xyang cocok dengan braket apa pun ayang mungkin atau mungkin tidak mengandung banyak ekspresi yang cocok dengan aturan x.

Agar setiap kecocokan berkuasa x, kami mendorong 0 ke deretan kecocokan dalam bjika bpanjangnya adalah 1.

Jika bpanjang> 0, maka kita menemukan indeks adalam ([<dan mendapatkan karakter dari +-/menggunakan indeks itu. Jika hasilnya tidak terdefinisi (artinya adulu {), maka kami mengubah hasilnya menjadi *. Akhirnya, kami memasang spasi dan bergabung bdengan hasilnya.

Jika bpanjang = 0, maka kami menemukan indeks amasuk ([<dan mendapatkan karakter dari 10menggunakan indeks itu. Jika hasilnya tidak terdefinisi (artinya aitu {atau <), maka kami mengubah hasilnya menjadi 2. Akhirnya, kami hanya mengurangi.

Pada akhirnya, kita bisa mengevaluasi ekspresi dan mengukur hasilnya.

Mama Fun Roll
sumber
3

Perl, 113 + 2 = 115 byte

Jalankan dengan -lp(penalti 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

Lebih mudah dibaca (catatan: "versi yang lebih mudah dibaca" ini tidak akan benar-benar berjalan, karena saya memberikan komentar di tempat yang tidak diizinkan secara sintaksis):

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

Ide dasarnya adalah bahwa kita mengubah input seperti [()<>]ke program Perl b(a(0),d(0),0),melalui pemrosesan teks; Perl baik-baik saja dengan koma yang tertinggal. Sebelumnya, kita mendefinisikan fungsi a, b, c, dmemiliki efek yang sama seperti (), [], {}, <>konstruksi dari bahasa kita menerapkan; mereka masing-masing mengabaikan argumen terakhir mereka (0 di akhir), yang disertakan untuk memastikan bahwa semua input diurai dengan benar, dan bekerja menggunakan implementasi yang biasa terlihat dalam pemrograman fungsional di mana kepala dan ekor diproses secara terpisah. Karena b(e,f,g,0)cara e-f-g, yaitu memperlakukan argumen pertamanya secara khusus, sedangkan amemperlakukan argumennya secara simetris ( a(e,f,g,0)berarti e+f+g), kami terapkanasecara rekursif dan bmelalui panggilan a. cdan dmemiliki hubungan yang serupa. Keempat fungsi ini sangat mirip, jadi kami membuatnya pada saat runtime daripada mengimplementasikannya secara terpisah; kami menyimpan templat yang berlaku untuk keempat fungsi dalam sebuah string, lalu menghasilkan fungsi dengan mengganti karakter ke dalam templat.

Karena Perl /melakukan pembagian floating-point, yang diterapkan {}juga. Saya berasumsi bahwa ini bukan masalah dalam dirinya sendiri, atau -Minteger(memilih varian bahasa di mana semua operasi aritmatika adalah operasi integer) adalah gratis, karena kalau tidak saya harus menghabiskan byte ekstra menulis divisi integer di Perl, yang tampaknya tidak menjadi masalah pada dasarnya. (Saya pikir Anda harus menghabiskan empat byte (shift)untuk mengganti int+(shift); Saya belum menguji ini.)


sumber
2

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

coba online

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

menggantikan sub-ekspresi dengan nilai garis bawah +; loop terputus ketika iterasi tidak membuat penggantian.

19 tahun sejak saya pertama kali bertemu C, 17 tahun bekerja dengan PHP;
ini adalah pertama kalinya strtokmasuk akal ... membantu menyelamatkan 24 byte!

kerusakan

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
Titus
sumber
@Liver tidak mengalahkan siapa pun di sini; tapi terima kasih untuk kesenangannya!
Titus
2

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

Versi Javascript murni.

"Metaprogramming" (seperti kebanyakan jawaban lain di sini), mengubah teks program input menjadi program Javascript yang sesuai, dengan menerapkan sejumlah substitusi teks langsung padanya (yaitu menjaga struktur program seperti apa adanya).

Mungkin bisa bermain golf lebih lanjut.

PEMBARUAN (v2.1)

  • Kurang dua byte (tanda kurung dihapus dalam ekspresi ternary)
  • Memotong 5 byte lebih banyak, dengan menggunakan variabel untuk ekstraksi hasil, dan menyingkirkan tambahan "[]"

PEMBARUAN (v2)

Baru menyadari bahwa koma yang tertunda dalam array ES benar-benar valid, sehingga seluruh kode normalisasi koma dapat dihapus. Juga mengikuti saran yang sangat baik dari @Titus, tentang mengoptimalkan pencarian alfabet.

PEMBARUAN (v1)

Duplikat "ganti" alias dihapus.

PEMBARUAN (v1)

  • Gunakan alfabet yang lebih baik: () => 1+ [] => 0 {} => 2 * <> => 2 / (masing-masing karakter dapat langsung digunakan kembali sebagai nilai atau operator)

  • Diganti reduksi () dengan replace () (pemetaan alfabet)

  • Penggabungan braket inline, buka dan tutup yang konstan menjadi satu langkah

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

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

Uji

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)

Output Uji

() 0 OK
(()()) 0 OK
([][]) -2 OK
({}<>) 2 OK
({}[]) 0 OK
[] -1 OK
[[][]] 0 OK
[()<>] -1 OK
{()} 0 OK
{([]<>)} 0 OK
zeppelin
sumber
1
Bisakah versi v0 Anda berjalan dengan s.reduce((r,c)=>r+="abcdefgh"["()[]{}<>".indexOf(c)],'')(-5)? jika demikian, Anda bisa mengingat indexOfdalam variabel dan mengambil operator dari string literal ketiga.
Titus
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.([]%)

Turunnya rekursif, memasukkan input karena Haskell. Seperti biasa, baris terakhir bukan definisi, tetapi menyatakan fungsi yang memecahkan masalah. Jadi untuk menguji, letakkan baris kecuali yang terakhir dalam file, muat dan lakukan sesuatu seperti ini:

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

Terima kasih kepada @Zgarb untuk inspirasi dan banyak petunjuk terperinci, dan untuk @Angs atas inspirasi dari solusi dan petunjuk selanjutnya.

Tidak ditentukan bagaimana pembagian harus berperilaku dengan bilangan bulat negatif. Lagi pula, berulang kali menggunakan divtampaknya salah, karena tidak sama dengan menggunakan divsatu kali dengan produk dari nilai yang tersisa. Sekarang menggunakan quot, saya mendapatkan hasil yang sama untuk <{}([][])[]>dan <{}{([][])[]}>.

Untuk kode yang bagus dan mudah dibaca lihatlah pada versi pertama. Versi perantara berisi semua jenis kode yang bagus dan mengintimidasi dan membantu memahami versi ini.

Sievers Kristen
sumber
Saya pikir Anda dapat menyimpan beberapa byte dengan mendefinisikan (!)=(,)dan menggunakan !alih-alih tuple eksplisit.
Zgarb
Jika Anda mendefinisikan m xdan d xsebagai 1#xdan 0#x, Anda dapat menggabungkan kasus m[x]dan d[x]menjadi satu, yang saya pikir menyimpan beberapa byte juga.
Zgarb
@ Zgarb Terima kasih! Saya hampir melewatkan pasangan terakhir, yang tanpanya !trik itu tidak membuahkan hasil. Saran kedua Anda adalah jahat, hilang kode saya yang hampir dapat dibaca ... Pintar!
Christian Sievers
Heh, saya baru menyadari bahwa mendefinisikan s%(c:i)=(s?c,i)dan s?')'=sum slain - lain akan jauh lebih pendek, karena Anda dapat menyingkirkan is berulang . ..Tidak Tunggu, itu mungkin tidak akan berhasil karena s%(_:i)kasus ini.
Zgarb
1
Kurangi backticks elemdan div, yang seharusnya menghemat lebih banyak byte.
Zgarb
1

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

Penjelasan: Regexp menemukan braket penutup yang belum diproses pertama, dan cocok dengan (mungkin) braket pembuka yang sesuai dan argumen di antaranya. Argumen dibagi dan dikurangi sesuai dengan operasi (sayangnya '(' dan '[' bukan pasangan yang optimal untuk +dan -), atau jika tidak ada argumen maka nilai yang sesuai dihitung (lagi-lagi pencocokan karakter dengan nilai-nilai adalah suboptimal dari sudut pandang saya). Hasilnya kemudian diganti dengan ruang terdepan untuk memisahkannya dari hasil lainnya. Fungsi ini kemudian memanggil dirinya secara rekursif sampai tidak ada lagi perubahan untuk dibuat, dalam hal ini mengembalikan nilai yang dihasilkan. Contoh:

[()<>]
[ 0<>]
[ 0 1]
 -1
Neil
sumber
f ("([] [])") => 0 (bukan 2)
zeppelin
Beberapa tes lain juga gagal untuk saya (Anda dapat mencoba kode tes dalam jawaban saya ), mungkin karena: f ("[]") => 0, karena "[]" adalah bagian dari setiap tes yang gagal.
zeppelin
@zeppelin Ups, itu karena beberapa golf yang buruk. Saya telah kembali ke versi sebelumnya, tetapi sayangnya hal itu menghabiskan beberapa byte.
Neil