주문의 조작


13

소개

어린 시절에 더하기와 곱하기를 마스터했다고 생각하면 누군가가 와서 다음과 같이 알려줍니다.

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

이전에 배운 것만 큼 간단하거나 선형 적이 지 않았습니다. 작업 순서 라는 것이 있다는 것을 알게 됩니다 . 이것은 괄호가 모든 것을 방해하지 않고 일정 수준의 일관성과 표현을 유지하는 매우 중요한 방법입니다.

일반적인 스토리

어느 날, 당신은 거리에서 공황의 소리에 일어납니다. " 2560 " 이라는 이름의 극단주의 단체 (도덕적 인 육십이를 가진 "작전 조직에 대한 조직"의 짧은)는 그들의 사악한 방법을 사용하여 세계의 모든 핵무기를 통제했습니다. 그들은 전체 행성 인질을 보유하고 있으며 간단한 요구가 있습니다. 수용 된 순서를 바꾸거나 박멸하십시오 (괄호는 우선 순위를 유지해야 함). 새로운 시스템을 PSADME (괄호, 뺄셈 / 더하기, 나누기 / 곱하기, 지수)라고하며 식은 오른쪽에서 왼쪽으로 평가됩니다.

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

일이 지나고 전환이 진행 중입니다. 수학자와 물리학 자들이 모두 방정식을 다시 작성하는 데 바쁘지만 컴퓨터 과학자들은 컴퓨터가 수학 표현을 해석하는 방식을 바꾸는 작업에 직면하고 있습니다. 우연히하고, 당신이 무작위로 선택됩니다 - 당신은 원인의 목표는 많은 새로운 글로벌 군주에 대한 고통으로 비밀 반군 프로그램 그룹에 속한 2560 및 벤치 마크 계산 프로그램을 생산하는 임무.

당신의 임무

(숫자) 수학 표현식을 입력으로 사용하고 PSADME 를 연산 순서로 사용하여 표현식을 계산 하고 결과를 출력 하는 프로그램 (또는 함수)을 작성하십시오 . 식은 오른쪽에서 왼쪽으로 평가되므로

1+4=17=6.

간단히하기 위해 제공된 모든 숫자는 정수가되고 계산은 정수 결과를 생성합니다.

규칙과 득점

  • 프로그램은 최대 128 자 길이의 입력을 허용해야합니다. 언어 / 플랫폼의 최대 입력 길이가 낮은 경우 허용 가능한 변명입니다.
  • 표준 허점은 금지되어 있습니다.
  • 당첨 코드는 11 월 18 일 (이 게시물 날짜부터 4 주)에 선택됩니다.
  • 골프에 적합하지 않은 코드를 게시하십시오. 이것은 재미에 관한 것입니다. 이 작업을 수행하는 데 흥미로운 방법이 있지만 직접 골프를 칠 수 없거나 방법의 특성에 따라 게시 할 수 있다면 어쨌든 게시 할 수 있습니다.

평소와 같이 당첨 코드는 바이트 수가 가장 적고 엔터테인먼트 가치 보너스가있는 코드입니다.

  • 제공된 표현식에서 문자를 사용하지 않으려면 -5 : + , - , ( , ) , ^ , * , /
  • -5 계산 방법이 명확하지 않은 경우 (클럭 또는 불필요한 루프 사용) 표준 컴퓨터에서 계산하는 데 5 분 (10 분 이하)이 소요됩니다. 목표는 당신이되지 않는다는 새로운 군주를 설득하는 노력 운명의 자신의 계산을 방해 할 수 있습니다.
  • -(5 + N) 2560의 멤버에 대한 직접적인 공격 메시지 (길이 N, 선행 / 트레일 링 공백 제외)의 경우 코드 내에서 명확하게 볼 수있는 2560 멤버에 대한 이유와 함께 우스운 설명 그곳에. 코드가 제거되면 코드 올바르게 작동 하지 않아야 합니다. 예, 엔터테인먼트 가치에 대한 무료 포인트.

예와 설명

[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? 오른쪽에서 왼쪽으로 제안 할 수 있지만 PSADME과는 반대로 뺄셈보다 먼저 덧셈을하고 있습니다.
LLlAMnYP

1
@LLlAMnYP 덧셈과 뺄셈은 PEMDAS에서와 같이 동일한 "그룹"에 있으므로 오른쪽에서 왼쪽으로 발생합니다. 곱하기 / 나누기와 같습니다. 더 비슷 P(SA)(DM)E합니다.
Geobits

2
이 문장은 오른쪽에서 왼쪽으로 처리하기위한 것이 아니라 우선 순위가 동일한 작업이 우선적으로 평가됩니다. 따라서 4/2 = 2, 2-1 = 1이지만 일반적인 (a / b) * c가 아닌 a / b c = a / (b c)입니다. 이것이 문제를 해결하기를 바랍니다.
Jake

아마도 가장 쉬운 방법은 flex / bison 또는 lex / yacc 문법을 작성하는 것입니다.

5
그러한 사악한 조직의 구성원은 원본보다 새로운 Star Wars 3 부작을 가장 좋아할 것이기 때문에 약어를 PADME로 변경해야합니다 . 기억하기도 쉽습니다.
mbomb007

답변:


9

하스켈, 134 바이트

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

새로운 연산자와 우선 순위를 사용하여 수학 연산자를 재정의합니다. 지금:

*Main> 32 / 8 * 3 - 1
2

1
와. 와우 다른 언어에서도 가능합니까? +1
ETHproductions

나는 Mathematica 또는 적어도 비슷한 접근법에서 가능하다는 것을 확신했지만, 그것을 만들 지식이 부족하다는 것을 빨리 깨달았습니다.
LLlAMnYP

1
이 포럼에서 다음 제안이 일반적으로 수용 가능한지 여부를 확신 할 수있을만큼 충분히 새롭습니다. 전적으로 코드를 기반으로하지만 Perl을 사용하여 Haskell 파일을 생성하고 GHCi에 전달하는 bash 스크립트입니다. 이렇게함으로써 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 불행히도 오타로 인해 생성 된 코드에 숫자와 기호 사이에 공백이 없지만 여전히 잘 작동합니다. 이것은 코드가 5 바이트를 잃을 수 있고 내 '개선'을 능가한다는 것을 의미합니다.
Jake

@JArkinstall 그 가치에 대한 대답은 sed쉘 코드를 생성하고 평가하는 데 효과적으로 사용 됩니다. 아마도 좋은 메타 질문입니다.
Digital Trauma

그것은 사실이며, 나는 당신의 접근법을 정말로 좋아합니다. 그러나 도구 (perl 또는 sed)를 사용하여 언어로 파일을 생성 한 다음 다른 언어로 읽는 것이 한 단계 더 나아간 것 같습니다. 다른 생성기를 통해 위의 코드를 생성하는 방법이 있지만 (방법이 나에게 분명하지는 않지만) 우리는 파싱 인식에 빠질 것입니다. 이것이 가능하다면,이 접근법을 코드에 적용 할 수도 있습니다 (그리고이 보드의 일부 문제에 대한 더 읽기 쉬운 언어로 된 답변에서 몇 가지 예를 보았습니다).
Jake

2

exec 확장자를 가진 GNU sed -r, 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

특히 짧지는 않지만 작업을 완료합니다.

sed는 우선 순위를 파싱해도 괜찮지 만 산술을하지 않습니다. 따라서 우리는 s명령에 GNU sed exec 확장을 사용하여 필요한 산술을 쉘에 아웃소싱합니다.

^앞뒤에 정확히 하나의 공백이 있는 것을 제외하고 모든 연산자를 가정합니다 .

테스트 출력 :

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

좋은 프로필 사진. xD
Oliver Ni

1

자바 스크립트 (ES6) 287 (300)

편집 코드 조각의 끝 부분에 대한 자세한 설명을 추가 - 버그 수정 (단지 오타는 6 4 있었어야)

편집 2 다른 도전에 대한 개선 사항을 발견했습니다

그러나 약간의 차이가 있지만 동일한 파서의 또 다른 포팅. (비교 )

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>

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.