7
\$\begingroup\$

CAPTCHA Modified by Evil Mathematician

I accidentally incurred the wrath of an eccentric passive-aggressive mathematician. As part of his demented idea of payback, he modified the CAPTCHA system on my favorite website. Up until now, it would just ask a moderately challenging math question, like 3+2^4, and I would simply type the answer, 19, to verify that I am a human being. But now, thanks to my mathematical nemesis, the CAPTCHA questions are obnoxiously hard to calculate by hand and it keeps me from logging into my profile!

Math Captcha

From what I can tell, this is what he has done. The CAPTCHA images seem to still be the same, but the way it calculates the correct answer has changed. It takes the expression displayed in the image and rotates the operations. You wouldn't believe how long it took me to figure this out T__T.

Because of this fiasco, I need a program/function that takes in one of these expressions as a string, evaluates it and returns the result so that I can log onto my website! To make this a game, fewest bytes win.

Ok, you have the idea, lets walk through an example. Suppose that the CAPTCHA displayed an image with 6+5+4-3*2/1. Normally the answer would 9. Instead, we now have to rotate the operations to the right and that gives us 6/5+4+3-2*1. At this point, we evaluate it to be 6.2

Summary

Steps to evaluate the string input:

  1. Rotate the operation to the right
  2. Evaluate the result

Specifications

  • Full program or function
  • Standard I/O
  • Takes an expression
  • Prints/Returns the evaluated result
    • After the op rotation
  • Possible operations are +-/*^
    • The negatives for negative numbers stays with the number when rotating
    • Follow the normal order of operations after the rotation is completed
    • Using integer division is allowed
  • Possible numbers are positive/negative integers
    • This does not include 0
  • Parentheses could be included, but aren't rotated

Test Cases

Input     -> Output
1+3       -> 4
7+6       -> 13
1+1-2     -> 2
3*4+2     -> 11
-7^4      -> -2401
3*7+1-3   -> -1
-9+4/4    -> 1.75
(4*1)+8   -> 40
1+2-3*4/5 -> -16.5
1+-2*3    -> 1
3*4--2    -> 11
30-2/7    -> 8
120*3-4+10-> 122
(13^-12)+11 -> 1

Update

  • [16-07-28] Fixed typo in last test case. I had posted the expression after rotating it once >___> , so that rotating a second time gave an incorrect answer. It is fixed now! Thanks to @sintax!
  • [16-08-13] Removed broke test case. Thanks again to @sintax!
\$\endgroup\$
15
  • 2
    \$\begingroup\$ This question seems awfully familiar to me for some reason. It's like I saw this exact same question somewhere on PPCG some time ago...strange. \$\endgroup\$
    – R. Kap
    Jul 28, 2016 at 3:06
  • \$\begingroup\$ Integer division allowed? \$\endgroup\$
    – Leaky Nun
    Jul 28, 2016 at 3:06
  • \$\begingroup\$ How long did it take you to derive that last equation?! \$\endgroup\$
    – R. Kap
    Jul 28, 2016 at 3:14
  • 1
    \$\begingroup\$ @R.Kap That last one was a doozy, but who can say no "2 pi"? \$\endgroup\$ Jul 28, 2016 at 3:30
  • 2
    \$\begingroup\$ That overload of - as a negative number indicator and the subtraction operator makes this problem much harder/longer than it otherwise would be... \$\endgroup\$
    – sintax
    Jul 28, 2016 at 14:52

5 Answers 5

6
\$\begingroup\$

Python 3.5, 118 113 164 bytes:

from re import*
def R(U):Z='(?<!\d)-\d+|\d+|[()]';O=sub(Z,'',U);print(eval(sub(Z,'%s',U).translate(str.maketrans(O,O[::-1])).replace('^','**')%tuple(findall(Z,U))))

A named function. Can probably be golfed down more. This will take quite a while and apparently plenty of memory to compute the solution for the input:

((22^22)+2*2^2^2^2*2-2+222222+22222*-2222-2*222*2*2+2^-2+(2+2+2+2+2)+222/222+2+22*2*2)*2*2*2

I started processing this with my program about 30 minutes ago as of the time of this edit (9:52 PM on July 27, 2016) and it is still going. EDIT: Well, it eventually started to take up too much memory, so I had to stop it at around 1 hour after I started, at around 10:52 PM on July 7, 2016.

EDIT # 2: Well, even for the updated last test case it's pretty much the same thing, as it takes quite a while for my program to start finding the answer before it eventually quits out on me with error code 137.

Try It Online for the Rest of the Test Cases! (Ideone)

\$\endgroup\$
2
  • \$\begingroup\$ Try with the new last test case; the old one had errors. \$\endgroup\$
    – sintax
    Jul 29, 2016 at 14:02
  • \$\begingroup\$ @sintax Yeah, the same issue still persists. :/ \$\endgroup\$
    – R. Kap
    Jul 29, 2016 at 18:04
3
\$\begingroup\$

Dyalog APL, 30, but soon to be 16 bytes

⍎w⊣((w∊f)/w)←¯1⌽w∩f←'+-×÷'⊣w←⍞

Ungolfed, explained version:

w ← ⍞ Prompt for input (of the expression) and assign to w

f ← '+-×÷' assign the symbols to f

((w ∊ f) / w) ← ¯1 ⌽ w ∩ f using membership of f as mask, reassign those positions in w to the corresponding character in the cyclic 1-step-right rotated intersection of w and f (the symbols)

⍎w execute the modified expression

There is no special handling of minus/negative, because APL uses the distinct symbols - and ¯.

See the rotation of symbols on TryAPL!

In version 16 it will be much shorter as a function which takes the expression as argument:

⍎¯1∘⌽@(∊∘'+-×÷')

Execute the negative one step rotation ¯1∘⌽ done on @ members of the symbols set (∊∘'+-×÷').

\$\endgroup\$
3
\$\begingroup\$

Python 3, 195 bytes:

import re;I=input();x=[i for i in I if i in'+-*/^'];print(eval(''.join([i[0]+i[1]for i in[i for i in map(list,zip(*[[i for i in re.split('[+*/^-]',I)],x[-1:]+x[:-1]+['']]))]]).replace('^','**')))

Takes input on STDIN and leaves a number on STDOUT. I know that R. Kap already posted a Python answer, but the method I used is actually pretty interesting, so I thought I'll post this anyway.

The program first makes an the list: [chunks splitted by math chars, math chars rotated to the right]. It then transposes the array, flattens, converts to string, and evaluates.

\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES7), 154 bytes

f=
s=>[(s=s.replace(/(\(*-?\d+\)*)(.?)/g,(_,d,o)=>a.push(d)&&o,a=[])).slice(-1),...s.slice(0,-1)].map((o,i)=>a[i]+=o)&&eval(a.join` `.replace(/\^/g,'**'))
;
<input id=i placeholder=Input><input id=o placeholder=Output><input type=button value=Go onclick=o.value=f(i.value);>

Works by removing the values into a separate array so that the operators can be rotated.

\$\endgroup\$
3
  • \$\begingroup\$ What environment can I test this in? \$\endgroup\$
    – Jordan
    Aug 5, 2016 at 15:57
  • \$\begingroup\$ @Jordan I have converted my answer into a code snippet that can be tested in any ES7-compliant browser (not ES6 as previously inadvertently advertised). \$\endgroup\$
    – Neil
    Aug 5, 2016 at 17:22
  • \$\begingroup\$ Nice, you even got exponentiation to evaluate in the correct order (e.g., 2^3^2=512 rather than 64). \$\endgroup\$
    – kamoroso94
    Aug 13, 2016 at 22:23
2
\$\begingroup\$

Matlab, 114 chars

Okay, so the last test case evaluates to Inf (once rotated, the expression 2^222222 appears...), but otherwise, all test cases hit.

Dealing with negatives, especially non-initial negatives, gave me fits.

i=input('');d=regexp(i(2:end),'[^\d|\)|\(]');d=d(~[0 d(2:end)-d(1:end-1)==1]);i(d+1)=i(1+d([end,1:end-1]));eval(i)

Inputs should be wrapped in single quotes (e.g., '2+3/5-(12*5)'), as per Matlab standard for string inputs.

Ungolfed and commented:

i=input('');                        # Get input from stdin.
d=regexp(i(2:end),'[^\d|\)|\(]');   # Find the positions of non-digit/paren characters
                                    # in the non-initial portion of the input.
d=d(~[0 d(2:end)-d(1:end-1)==1]);    # If there are consecutive operator-type characters,
                                    # assume the second is a negativity indicator and
                                    # delete its index from our list of operator indices.
i(d+1)=i(1+d([end,1:end-1]));       # Replace each non-initial operator character of the 
                                    # input with its own right-rotated operator from our
                                    # list of operator characters
eval(i)                             # Evaluate the string expression we just built.
\$\endgroup\$
6
  • \$\begingroup\$ I thought that would be assumed, from the nature of the language. I can add that. Also, yes, I mention at the top of my answer that the last test case eval's to Inf. The portion which reads '2*222222' and gets rotated to '2^222222' is too large for Matlab to store by a LOT. \$\endgroup\$
    – sintax
    Jul 28, 2016 at 16:18
  • 1
    \$\begingroup\$ Sorry, I hadn't seen that note \$\endgroup\$
    – Luis Mendo
    Jul 28, 2016 at 16:24
  • 1
    \$\begingroup\$ I'm pretty sure the example in that one case is flawed. Evaluating the rotation by hand gives 10959 + 2^888888 * 22222 which is a much larger number than is claimed. \$\endgroup\$
    – sintax
    Jul 28, 2016 at 16:29
  • \$\begingroup\$ @sintax Good catch! I have fixed that test case. The original test case had already been rotated once, so the second rotation threw it off. \$\endgroup\$ Jul 28, 2016 at 16:40
  • 1
    \$\begingroup\$ Trying with the new last test case gives me: i = '((22^22)+2*2^2^2^2*2-2+222222+22222*-2222-2*222*2*2+2^-2+(2+2+2+2+2)+222/222+2+22*2*2)*2*2*2', eval(i) = 2.7314e+30; After rotating i = '((22*22)^2+2*2^2^2^2*2-222222+22222+-2222*2-222*2*2*2+-2^(2+2+2+2+2)+222+222/2+22+2*2)*2*2*2', eval(i) = 227160. Does that seem right to you? \$\endgroup\$
    – sintax
    Jul 28, 2016 at 21:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.