Một hệ thống số đơn giản


19

Hãy để tôi nói với bạn về một hệ thống số đơn giản. (mà tôi đã tạo nên chỉ cho thử thách này)

Hệ thống này bao gồm các chức năng (), [], {}, và <>.

1. ()

Khi ()được đưa ra không có đối số, nó đánh giá 0.

Khi ()được đưa ra một hoặc nhiều đối số, nó ước tính tổng của các đối số.

2. []

Khi []được đưa ra không có đối số, nó đánh giá -1.

Khi []được đưa ra một hoặc nhiều đối số, nó ước tính cho đối số đầu tiên trừ đi tổng của các đối số khác.

3. {}

Khi {}được đưa ra không có đối số, nó đánh giá 1.

Khi {}được đưa ra một hoặc nhiều đối số, nó sẽ đánh giá sản phẩm của các đối số đó.

4. <>

Khi <>được đưa ra không có đối số, nó đánh giá 1.

Khi <>được đưa ra một hoặc nhiều đối số, nó ước tính cho số nguyên đối số đầu tiên chia cho tích của các đối số khác.

Nhiệm vụ của bạn

Cho một chuỗi chứa một số hợp lệ (có nghĩa là dấu ngoặc được cân bằng, không chia cho 0, v.v.) trong hệ thống số đơn giản này, hãy in giá trị của nó.

Các trường hợp thử nghiệm

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

Hãy nhớ rằng, đây là , vì vậy mã có ít byte nhất sẽ thắng.


13
Tôi có một cái tên tuyệt vời cho điều này, thứ mà tôi hoàn toàn tạo ra và không nhận được từ bất cứ nơi nào khác: Brain-flake!
Sản xuất ETH

4
@ETHproductions no
Oliver Ni


2
Là phân chia float hay chia số nguyên?
xnor

1
@Oliver Làm thế nào để phân chia số nguyên hoạt động khi một hoặc cả hai toán hạng âm? 4 kết quả mong đợi cho là gì 5/3, 5/-3, -5/3-5/-3?
Martin Ender

Câu trả lời:


2

APL Dyalog , 94 byte

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

sử dụng ⎕IO←0

thay thế )]}>bằng một lệnh gọi hàm lấy một ngăn xếp, áp dụng một thao tác trên khung trên cùng của nó, xóa nó và nối kết quả vào khung tiếp theo của nó (toán tử đơn âm ođược sử dụng cho điều đó; toán tử dyadic uxử lý các trường hợp phức tạp hơn -÷)

thay thế ([{<bằng mã thêm khung vào ngăn xếp ( (⊂⍬),)

thực hiện biểu thức kết quả (đảo ngược, để khớp với thứ tự thực hiện của APL) với một ngăn xếp ban đầu của một khung trống ( ⊂⍬)


5

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

Trình phân tích cú pháp dựa trên mã thông báo với ngăn xếp rõ ràng. (%)lấy một ngăn xếp mã thông báo và một ký tự và đẩy (opcode, defaultnumber) hoặc (0, số) cho ({[<, hoặc bật các số trên cùng và một opcode và đẩy câu trả lời cho )}]>. Các mã được mã hóa bởi một hack liệt kê ascii.

Kudos gửi tới @ChristianSievers vì câu trả lời tuyệt vời của anh ấy mà tôi đã mượn một số ý tưởng từ đó.

Lót!

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

Bây giờ với ít xử lý lỗi! Sử dụng:

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

Cảm ơn @ChristianSievers đã lưu 14 + 3 byte!

Cảm ơn @Zgarb đã lưu một số + 4 byte!


1
Làm thế nào về (0,[0,0,1,-1,1]!!o):sdòng thứ năm?
Christian Sievers

@ChristianSievers tất nhiên!
Angs

Chuyển các định nghĩa về !, vì vậy bạn có thể làm (s:_)!_=d snhư trường hợp thứ hai. Ngoài ra, tôi nghĩ rằng bạn có thể ràng buộc x<-p$d<$>init a,y<-d$last atrong trường hợp cuối cùng của %.
Zgarb

@Zgarb cảm ơn! Tôi tìm thấy một cách để thống nhất đánh giá hơn nữa.
Angs

1
Trên dòng thứ ba của %bạn có thể thả parens xung quanh _:bg 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]

Thay thế tất cả các dấu ngoặc bằng lambda thực hiện những gì dấu ngoặc làm, sau đó đánh giá mã Python kết quả. Yêu cầu đầu vào của nó được bao quanh bởi dấu ngoặc kép, như '[<><>([]{})]'.

Chương trình này lưu trữ loại dấu ngoặc là ký tự đầu tiên trong mỗi chuỗi trong forvà mọi thứ sau từ khóa lambdalà phần còn lại. Sau đó, nó sử dụng ký tự đầu tiên để thay thế; phần còn lại của nó được kết hợp thành một lambda như thế nào (lambda*x:sum(x))().

Hãy thử nó trên 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))}

Nên sửa ngay.

Giải trình

Dễ đọc hơn:

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 là phiên bản mở rộng của Javascript được tạo riêng để phân tích cú pháp. Nó rất nghiêm ngặt, đó là lý do tại sao tôi phải sử dụng var. Ngoài ra, dường như có một lỗi với dấu ngoặc trong chuỗi, làm tăng mã đáng kể.

Để bắt đầu, chúng tôi xác định quy tắc xkhớp với bất kỳ dấu ngoặc anào có thể có hoặc không chứa nhiều biểu thức khớp với quy tắc x.

Để mỗi quy tắc khớp x, chúng tôi đẩy 0 vào mảng của kết quả khớp bên trong bnếu bđộ dài của nó là 1.

Nếu bđộ dài> 0, thì chúng ta sẽ tìm thấy chỉ mục atrong ([<và nhận một ký tự từ +-/việc sử dụng chỉ mục đó. Nếu kết quả không được xác định (có nghĩa a{), thì chúng ta biến kết quả thành *. Cuối cùng, chúng tôi giải quyết một không gian và tham gia bvới kết quả.

Nếu bchiều dài = 0, thì chúng ta sẽ tìm thấy chỉ mục atrong ([<và nhận một ký tự từ 10việc sử dụng chỉ mục đó. Nếu kết quả không xác định (có nghĩa a{hoặc <), thì chúng ta biến kết quả thành 2. Cuối cùng, chúng ta chỉ đơn giản là giảm.

Cuối cùng, chúng ta chỉ có thể đánh giá biểu thức và kết quả sàn.


3

Perl, 113 + 2 = 115 byte

Chạy với -lp(hình phạt 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

Dễ đọc hơn (lưu ý: "phiên bản dễ đọc hơn" này sẽ không thực sự chạy, vì tôi đặt nhận xét ở những nơi chúng không được phép về mặt cú pháp):

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

Ý tưởng cơ bản là chúng tôi đang chuyển đổi một đầu vào như [()<>]chương trình Perl b(a(0),d(0),0),thông qua xử lý văn bản; Perl chỉ tốt với dấu phẩy. Trước đó, chúng tôi đã xác định chức năng a, b, c, dcó tác dụng tương tự như (), [], {}, <>cấu trúc từ ngôn ngữ chúng ta đang thực hiện; mỗi cái đều bỏ qua đối số cuối cùng của chúng (0 ở cuối), được bao gồm để đảm bảo rằng tất cả các phân tích cú pháp đầu vào chính xác và hoạt động bằng cách sử dụng triển khai thường thấy trong lập trình chức năng nơi đầu và đuôi được xử lý riêng. Bởi vì b(e,f,g,0)có nghĩa là e-f-g, nghĩa là đối xử đặc biệt với đối số đầu tiên của nó, trong khi ađối xử với các đối số của nó đối xứng ( a(e,f,g,0)phương tiện e+f+g), chúng tôi thực hiệnađệ quy và bthông qua cuộc gọi a. cdcó mối quan hệ tương tự. Tất cả bốn chức năng này rất giống nhau, vì vậy chúng tôi tạo ra chúng trong thời gian chạy thay vì thực hiện chúng một cách riêng biệt; chúng tôi lưu trữ một mẫu áp dụng cho cả bốn hàm trong một chuỗi, sau đó tạo các hàm bằng cách thay thế các ký tự vào mẫu.

Bởi vì Perl /không phân chia dấu phẩy động, nên việc thực hiện {}cũng vậy. Tôi cho rằng đây không phải là vấn đề theo đúng nghĩa của nó, hoặc -Minteger(chọn một biến thể ngôn ngữ trong đó tất cả các phép toán số học là các phép toán số nguyên) là miễn phí, vì nếu không, tôi phải dành thêm byte để viết một số nguyên trong Perl, mà dường như không phải là vấn đề cơ bản. (Tôi nghĩ rằng bạn phải dành bốn byte (shift)để thay đổi int+(shift); Tôi chưa thử nghiệm điều này.)


2

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

thử trực tuyến


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

thay thế các biểu thức con bằng dấu gạch dưới + giá trị; vòng lặp bị phá vỡ khi lặp không thực hiện thay thế.

19 năm kể từ lần đầu tiên tôi gặp C, 17 năm làm việc với PHP;
đây là lần đầu tiên có strtoký nghĩa ... giúp tiết kiệm 24 byte!

phá vỡ

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 không đánh ai ở đây; nhưng cảm ơn vì niềm vui!
Tít

2

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

Một phiên bản Javascript thuần túy.

"Siêu lập trình" (giống như hầu hết các câu trả lời khác ở đây), chuyển đổi văn bản chương trình đầu vào thành chương trình Javascript tương ứng, bằng cách áp dụng một số thay thế văn bản trực tiếp cho nó (nghĩa là giữ nguyên cấu trúc chương trình).

Có lẽ có thể được chơi golf hơn nữa.

CẬP NHẬT (v2.1)

  • Trừ hai byte (loại bỏ dấu ngoặc đơn trong biểu thức ternary)
  • Đã giảm thêm 5 byte, bằng cách sử dụng biến để trích xuất kết quả và loại bỏ thêm "[]"

CẬP NHẬT (v2)

Chỉ cần nhận ra rằng dấu phẩy đang chờ xử lý trong mảng ES là hoàn toàn hợp lệ, vì vậy toàn bộ mã chuẩn hóa dấu phẩy có thể được xóa. Cũng theo một lời khuyên tuyệt vời của @Titus, về việc tối ưu hóa việc tra cứu bảng chữ cái.

CẬP NHẬT (v1)

Loại bỏ bí danh "thay thế" trùng lặp.

CẬP NHẬT (v1)

  • Sử dụng bảng chữ cái tốt hơn: () => 1+ [] => 0 {} => 2 * <> => 2 / (mỗi char có thể được sử dụng lại trực tiếp dưới dạng giá trị hoặc toán tử)

  • Đã thay thế less () bằng thay thế () (ánh xạ bảng chữ cái)

  • Sáp nhập liên tục nội tuyến, mở và đóng khung xử lý thành một bước

Chơi gôn (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

Chơi gôn (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"))    

Chơi gôn (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"))

Giải thích (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

Kiểm tra

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)

Đầu ra thử nghiệm

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

1
Phiên bản v0 của bạn có thể đi với s.reduce((r,c)=>r+="abcdefgh"["()[]{}<>".indexOf(c)],'')(-5) không? nếu vậy, bạn có thể nhớ indexOftrong một biến và lấy toán tử từ một chuỗi thứ ba.
Tít

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

Đệ quy đệ quy, xâu chuỗi đầu vào vì Haskell. Như thường lệ, dòng cuối cùng không phải là một định nghĩa, nhưng nêu rõ chức năng giải quyết vấn đề. Vì vậy, để kiểm tra, hãy đặt các dòng ngoại trừ dòng cuối cùng trong một tệp, tải nó và làm một cái gì đó như thế này:

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

Cảm ơn @Zgarb đã truyền cảm hứng và rất nhiều gợi ý chi tiết và @Angs đã truyền cảm hứng từ giải pháp của anh ấy và những gợi ý khác.

Nó không được chỉ định cách phân chia nên hành xử với các số nguyên âm. Dù sao, việc sử dụng nhiều lần divcó vẻ sai, vì nó không giống như sử dụng divmột lần với sản phẩm của các giá trị còn lại. Bây giờ sử dụng quot, tôi nhận được kết quả tương tự cho <{}([][])[]><{}{([][])[]}>.

Đối với mã đẹp, hầu như có thể đọc được ở phiên bản đầu tiên. Các phiên bản trung gian chứa tất cả các loại mã đẹp và đáng sợ và giúp hiểu phiên bản này.


Tôi nghĩ rằng bạn có thể lưu một vài byte bằng cách xác định (!)=(,)và sử dụng !thay vì các bộ dữ liệu rõ ràng.
Zgarb

Nếu bạn xác định m xd xnhư 1#x0#x, bạn có thể hợp nhất các trường hợp m[x]d[x]thành một, mà tôi nghĩ cũng tiết kiệm một số byte.
Zgarb

@Zgarb Cảm ơn! Tôi gần như đã bỏ lỡ cặp cuối cùng, mà không có !mẹo nào không trả tiền. Đề nghị thứ hai của bạn là xấu xa, có mã gần như dễ đọc của tôi ... Thông minh!
Christian Sievers

Heh, tôi chỉ nhận ra rằng việc xác định s%(c:i)=(s?c,i)s?')'=sum svv sẽ ngắn hơn nhiều, vì bạn có thể thoát khỏi các is lặp đi lặp lại . .. Không chờ đợi, có lẽ sẽ không hoạt động vì s%(_:i)vụ án.
Zgarb

1
Mất các backticks trên elemdiv, điều đó sẽ tiết kiệm thêm một số byte.
Zgarb

1

JavaScript (ES6), không 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)

Giải thích: regrec tìm thấy khung đóng chưa được xử lý đầu tiên và khớp với khung mở tương ứng (có lẽ là) và bất kỳ đối số nào ở giữa. Các đối số được phân chia và giảm theo thao tác (đáng buồn là '(' và '[' không phải là cặp tối ưu cho +-) hoặc nếu không có đối số thì giá trị phù hợp được tính (một lần nữa, việc khớp các ký tự với các giá trị là tối ưu theo quan điểm của tôi). Kết quả sau đó được thay thế bằng một khoảng trắng ở đầu để tách nó ra khỏi các kết quả khác. Hàm sau đó tự gọi đệ quy cho đến khi không còn thay đổi nào nữa, trong trường hợp đó nó trả về giá trị kết quả. Thí dụ:

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

f ("([] [])") => 0 (thay vì 2)
zeppelin

Một số thử nghiệm khác cũng không thành công đối với tôi (bạn có thể thử mã thử trong câu trả lời của tôi ), có thể là do: f ("[]") => 0, vì "[]" là một phần của mọi thử nghiệm thất bại.
zeppelin

@zeppelin Rất tiếc, đó là do chơi golf không tốt. Tôi đã trở lại phiên bản trước, nhưng thật đáng buồn là tôi phải trả một vài byte.
Neil
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.