Hoạt động của trật tự


13

Giới thiệu

Có một điểm trong thời thơ ấu khi bạn nghĩ rằng bạn đã thành thạo việc thêm và nhân, sau đó ai đó sẽ đến và thông báo cho bạn rằng:

a * b + c = (a * b) + c! = a * (b + c),

và đó không phải là một quá trình đơn giản hay tuyến tính như bạn đã được dạy trước đó. Bạn học được rằng tồn tại một cái gì đó gọi là thứ tự của các hoạt động . Đây là một cách rất quan trọng để giữ một số mức độ nhất quán và trong các biểu thức, mà không có dấu ngoặc đơn cản trở mọi thứ.

Cốt truyện chung

Một ngày nọ, bạn thức dậy với âm thanh hoảng loạn trên đường phố. Một nhóm cực đoan dưới cái tên " The 2560 " (viết tắt của "Tổ chức chống lại trật tự hoạt động", với một vòng xoắn hex-ish) đã sử dụng các phương pháp xấu xa của chúng để kiểm soát tất cả các vũ khí hạt nhân trên thế giới. Họ đang giữ toàn bộ con tin hành tinh và họ có một yêu cầu đơn giản: đảo ngược trật tự hoạt động được chấp nhận hoặc đối mặt với việc xóa sổ (dấu ngoặc đơn là để duy trì ưu tiên của họ). Hệ thống mới được gọi là PSADME (dấu ngoặc đơn, phép trừ / phép cộng, phép chia / phép nhân, số mũ) và các biểu thức đánh giá từ phải sang trái:

a - b - c = a - (b - c) = a + c - b

Ngày trôi qua, và quá trình chuyển đổi đang diễn ra. Trong khi các nhà toán học và vật lý học đang bận rộn viết lại phương trình của họ, các nhà khoa học máy tính phải đối mặt với nhiệm vụ thay đổi thời trang trong đó các biểu thức toán học được giải thích bằng máy tính. Bạn thuộc nhóm lập trình phiến quân bí mật nhằm gây ra nhiều đau khổ cho các lớp phủ toàn cầu mới - và, tình cờ, bạn được The 2560 chọn ngẫu nhiên và được giao nhiệm vụ sản xuất chương trình tính toán điểm chuẩn.

Nhiệm vụ của bạn

Viết chương trình (hoặc hàm) lấy biểu thức toán học (số) làm đầu vào, tính toán biểu thức bằng PSADME làm thứ tự các thao tác và đưa ra kết quả. Biểu thức nên đánh giá từ phải sang trái, vì vậy

1-3+4= =1-7= =-6.

Để đơn giản, tất cả các số được cung cấp sẽ là số nguyên và các phép tính sẽ tạo ra kết quả số nguyên.

Quy tắc và tính điểm

  • Chương trình nên chấp nhận độ dài đầu vào tối đa 128 ký tự - nếu ngôn ngữ / nền tảng của bạn có độ dài đầu vào tối đa thấp hơn, đó là một lý do có thể chấp nhận được.
  • Sơ hở tiêu chuẩn bị cấm.
  • Mã chiến thắng sẽ được chọn vào ngày 18 tháng 11 (4 tuần kể từ ngày đăng bài này).
  • Vui lòng gửi mã không được coi là xứng đáng chơi gôn. Đây là về niềm vui. Nếu bạn có một cách thú vị để làm điều này nhưng không thể tự đánh golf nó (hoặc theo bản chất của phương pháp của bạn), bạn vẫn có thể đăng nó.

Như thường lệ, mã chiến thắng là mã có số byte ít nhất, với một số phần thưởng giá trị giải trí:

  • -5 để tránh sử dụng các ký tự trong biểu thức được cung cấp: + , - , ( , ) , ^ , * , /
  • -5 để thực hiện các phép tính mất hơn 5 phút (nhưng không quá 10 phút) để tính toán trên một máy tính tiêu chuẩn, mà không có phương pháp rõ ràng (sử dụng đồng hồ hoặc các vòng lặp không cần thiết); Mục đích là để thuyết phục các lớp phủ mới mà bạn không cố gắng phá vỡ tính toán của họ.
  • - (5 + N) cho một tin nhắn tấn công trực tiếp (có độ dài N, không bao gồm khoảng trắng hàng đầu / dấu) về các thành viên của The 2560 được viết trong tầm nhìn rõ ràng trong mã của bạn, với một số giải thích nực cười về lý do tại sao nó cần phải được ở đó Nếu nó được gỡ bỏ, mã phải không hoạt động chính xác. Có, điểm miễn phí cho giá trị giải trí.

Ví dụ và giải thích

[program] 2 - 2 - 2
2

2 - (2 - 2) = 2

[program] (2 + 2 * 3 + 3) / 3 + 3
4

(4 * 6) / (3 + 3) = 4

[program] 3 + 2 + 1 ^ 3
216

(3 + 2 + 1) ^ 3 = 216

[program] -5^2
25

(-5) ^ 2 = 25

[program] 32 / 8 * 3 - 1
2

32 / (8 * (3 - 1)) = 32/16 = 2


1 - 3 + 4 = 1 - 7? Phải sang trái sẽ đề xuất như vậy, nhưng đó là sự bổ sung đi trước phép trừ, trái với PSADME, phải không?
LLlAMnYP

1
@LLlAMnYP Phép cộng và phép trừ nằm trong cùng một "nhóm", giống như trong PEMDAS, vì vậy chúng xảy ra từ phải sang trái. Tương tự với phép nhân / chia. Nó giống như hơn P(SA)(DM)E.
Geobits

2
Tuyên bố không có nghĩa là được xử lý từ phải sang trái - thay vào đó, các hoạt động có mức độ ưu tiên như nhau được đánh giá từ phải sang trước. Vậy 4/2 = 2, 2-1 = 1, nhưng a / b c = a / (b c) chứ không phải thông thường (a / b) * c. Tôi hy vọng điều này sẽ làm mọi thứ rõ ràng.
Jake

Có lẽ cách dễ nhất để làm điều này là viết lên một ngữ pháp flex / bison hoặc lex / yacc.

5
Bạn nên thay đổi từ viết tắt thành PADME , vì các thành viên của một tổ chức xấu xa như vậy chắc chắn sẽ thích bộ ba Star Wars mới hơn là bản gốc. Nó cũng dễ nhớ hơn.
mbomb007

Câu trả lời:


9

Haskell, 134 byte

import qualified Prelude as P
infixl 6 ^
(^)=(P.^)
infixr 8 + 
(+)=(P.+)
infixr 8 - 
(-)=(P.-)
infixr 7 /
(/)=P.div
infixr 7 *
(*)=(P.*)

Xác định lại các toán tử toán học với các ưu tiên và ưu tiên mới. Hiện nay:

*Main> 32 / 8 * 3 - 1
2

1
Ồ Chỉ là, wow. Điều này thậm chí có thể trong bất kỳ ngôn ngữ khác? +1
Sản phẩm điện tử

Tôi khá chắc chắn, điều đó có thể xảy ra trong Mathematica, hoặc ít nhất là một cách tiếp cận tương tự, nhưng nhanh chóng nhận ra, tôi thiếu kiến ​​thức để thực hiện nó.
LLlAMnYP

1
Tôi mới đủ ở đây để không chắc chắn về việc liệu đề xuất sau đây thường được chấp nhận trên diễn đàn này. Nó hoàn toàn dựa trên mã của bạn, nhưng là một tập lệnh bash sử dụng Perl để tạo tệp Haskell và chuyển nó đến GHCi. Bằng cách làm như vậy, tôi tiết kiệm được một WHOLE BYTE. perl -e'$_="import qualified Prelude as Pl 6^r 8+r 8-r 7*r 7/";s/(. \d(.))/\ninfix\1\n(\2)=(P.\2)/g;s~\./~.div~;print'>a.hs;ghci a.hs Thật không may, một lỗi đánh máy làm cho mã được tạo ra thiếu khoảng cách giữa chữ số và ký hiệu, nhưng vẫn chạy tốt. Điều này có nghĩa là mã của bạn có thể mất 5 byte và đánh bại 'sự cải thiện' của tôi.
Jake

@JArkinstall Với giá trị của nó, câu trả lời của tôi là sử dụng hiệu quả sedđể tạo và đánh giá mã shell. Có lẽ là một câu hỏi meta tốt.
Chấn thương kỹ thuật số

Đó là sự thật và tôi thực sự thích cách tiếp cận của bạn - tuy nhiên, sử dụng một công cụ (perl hoặc sed) để tạo một tệp bằng ngôn ngữ mà sau đó đọc sang ngôn ngữ khác dường như tiến thêm một bước. Tôi sẽ không quá ngạc nhiên nếu có một cách sản xuất mã trên thông qua một trình tạo khác (mặc dù phương thức này không rõ ràng đối với tôi!), Và chúng tôi sẽ thấy mình bị lừa dối. Nếu điều này được cho phép, người ta thậm chí có thể áp dụng cách tiếp cận này cho mã của bạn (và một vài ví dụ tôi đã thấy trong một số câu trả lời bằng ngôn ngữ dễ đọc hơn cho một số thách thức trên bảng này).
Jake

2

GNU sed -r với phần mở rộng exec, 398

s@ *\^ *@ ** @
:
s@\((-?[0-9]+)\)@\1@
t
s@(-?[0-9]+ - )+(-?[0-9]+ - -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ [-+] -?[0-9]+)(.*)@echo '\1'$((\3))'\4'@e
t
s@(-?[0-9]+ / )+(-?[0-9]+ / -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ [*/] -?[0-9]+)(.*)@echo '\1'$((\3))'\4'@e
t
s@(-?[0-9]+ \*\* )+(-?[0-9]+ \*\* -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ \*\* -?[0-9]+)(.*)@bash -c 'echo \1$[\3]\4'@e
t

Không đặc biệt ngắn, nhưng hoàn thành công việc.

sed là OK để phân tích ưu tiên nhưng không làm số học. Vì vậy, chúng tôi sử dụng phần mở rộng GNU sed exec cho slệnh để thuê ngoài số học cần thiết cho trình bao.

Bây giờ giả định tất cả các nhà khai thác, ngoại trừ ^có chính xác một không gian ở phía trước và phía sau.

Đầu ra thử nghiệm:

$ cat psadme.txt 
2 - 2 - 2
(2 + 2 * 3 + 3) / 3 + 3
3 + 2 + 1 ^ 3
-5^2
32 / 8 * 3 - 1
$ sed -rf psadme.sed psadme.txt 
2
4
216
25
2
$ 

Hình đại diện đẹp. xD
Oliver Ni

1

JavaScript (ES6) 287 300

Sửa lỗi sửa lỗi (chỉ là một lỗi đánh máy, 6 nên là 4) - Đã thêm một lời giải thích hoàn chỉnh ở cuối đoạn trích

Chỉnh sửa 2 Tìm thấy một số cải tiến làm việc trên một thách thức khác

Một cổng khác của cùng một trình phân tích cú pháp chỉ với một số khác biệt tối thiểu. (so sánh với điều này )

f=(x,W=[],Q=['('],z=1,h=p=>'+-*/^^))('.indexOf(p)>>1,C=n=>{for(;h(q=Q.pop())<h(n);W.push(q=='^'?Math.pow(a,b):eval(`a${q}b`)))a=W.pop(b=W.pop());z&&Q.push(q,n)})=>((x+')').replace(/\d+|\S/g,t=>t>'('?t>'('?~h(t)?z&&t=='-'?z=-z:C(t,z=1):(W.push(z*t),z=0):C(t,z=0):(Q.push(t),z=1)),W.pop())

// More readable
U=(x,W=[],Q=['('],z=1,
  h=p=>'+-*/^^))('.indexOf(p)>>1,
  C=n=>{
    for(;h(q=Q.pop())<h(n);
        W.push(q=='^'?Math.pow(a,b):eval(`a${q}b`)))
      a=W.pop(b=W.pop());
    z&&Q.push(q,n)
  }
)=>(
  (x+')')
  .replace(/\d+|\S/g,t=> 
       t>'('
       ?t>'('
       ?~h(t)
       ?z&&t=='-'?z=-z:C(t,z=1)
       :(W.push(z*t),z=0)
       :C(t,z=0)
       :(Q.push(t),z=1)
  ),
  W.pop()
)

// TEST
console.log=(...x)=>O.innerHTML+=x.join` `+'\n'

console.log(f('1 - 3 + 4')) // -6
console.log(f('2-2-2')) // 2
console.log(f('(2 + 2 * 3 + 3) / 3 + 3')) // 4
console.log(f('3 + 2 + 1 ^ 3')) // 216
console.log(f('-5^2')) // 25
console.log(f('32 / 8 * 3 - 1')) // 2

// Explained
X=(x,W=[],Q=['('],z=1,
  h=p=> // operator priority '+-:1, */:3, ^:5, ):7, (:9. If an operand then -1
     '+-*/^^))('.indexOf(p)>>1,
  C=n=>{ // Evaluate operators present on stack if they have upper priority, then push new operator on stack
    //console.log('Operand '+n)
    while( h(q = Q.pop()) < h(n) ) // pop operator from op stack and compare priority with current
    {
      // Pop operands from stack and push result
      b = W.pop();
      a = W.pop();
      r = q=='^' ? Math.pow(a,b) : eval('a'+q+'b')
      // console.log('Evaluate '+a+q+b+'='+r)
      W.push(r);
    }
    // if z == 0 do nothing, because the current operands are '(' and ')' that must be discarded
    // else Push again the last operator popped and the current one
    z && Q.push(q, n) // 
  }
)=>(
  (x+')')
  .replace(/[\d.]+|\S/g,t=> {
    //console.log('Q:'+Q,'W:'+W,'T:'+t,'U:'+h(t),'Z:'+z), // display status
    if (t == '(') 
    { // open parenthesis
      z = 1
      Q.push(t) // push a operator, its the highest priority
    }
    else if (t == ')')
    { //close parenthesis
      z = 0
      C(t) 
    }
    else if (h(t) < 0)
    { // operand
      W.push(z*t) // push operand with right sign
      z = 0 // set z to 0 to mark that we just pushed an operand, so next '-' (if present) is a binary operator 
    }
    else
    { // operator
      if (z && t=='-') // the minus is an unary operator (the only unary operator allowed is '-', '+' will not work)
        z =-z // change the sign
      else
        z = 1, // no unary minus
        C(t)
    }    
  }),
  W.pop() // return the value at top of operand stack
)
<pre id=O></pre>

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.