14
\$\begingroup\$

The task

Most Casio calculators featured a variable M, which has 3 operators related to it: M, M+, and M-

M, as you can expect, returns the value stored in the variable.

M+ takes the number on the left and add it to M.

M- does the same thing as M+, but subtract instead.

To make the challenge just a bit more difficult, we will add an extra operator: MR, which is short for Memory reset. As you can guess from the name, it resets the variable M back to 0.

Your task is to parse a string of Casio M expression, then print the value of M.

Here's an example:

9M+9M+

Here, we add 9 to variable M twice, so the output will be 18.

Specifications

  • M will be 0 when first initialized
  • For this challenge, you don't need to handle basic arithmetics, just those operators.
  • However, you do need to handle implicit multiplications, so 9M will become 81 for M = 9
  • If the expression given is invalid, you can return any value of your choice
  • M+ and M- must not have an operator behind them (except for M), so cases like MRM+ and 9M+M+ are invalid, but 9M+MM+ is valid.

Input/Output

The input should be a string and the output is either the variable M or an invalid value of your choice.

Testcases

Input -> Output
9M+9M+ -> 18
9MR9M+ -> 9
9M+MM+ -> 18
9M-9M-9M+ -> -9
9M+MMM+ -> 90
81M+81M+56M-35M-12M+ -> 83
9M+MRM+ -> Invalid
9M+M+  -> Invalid
9 -> 0 (Explanation: does not modify M with an operator)
9M+MM -> 9 (Same as the above test case)
2M+2M2MM+ -> 18
\$\endgroup\$
13
  • 1
    \$\begingroup\$ Could you please clarify 9M+MMM+ -> 90? \$\endgroup\$
    – Arnauld
    Nov 19, 2022 at 0:21
  • 1
    \$\begingroup\$ @WheatWizard I have also thought of relaxing the invalid output, but couldn't think of a language in the time. Edited. \$\endgroup\$
    – oeuf
    Nov 19, 2022 at 14:36
  • 1
    \$\begingroup\$ Would something like 2M+2M2MM+ be valid? If so, I assume the answer would be 18? \$\endgroup\$
    – Jonah
    Nov 19, 2022 at 17:48
  • 1
    \$\begingroup\$ @Jonah Yes, that is valid, and yes, you are right that the answer is 18 \$\endgroup\$
    – oeuf
    Nov 20, 2022 at 0:16
  • 1
    \$\begingroup\$ @oeuf You may want to add 2M+2M2MM+ to the test case, because only one of the current four answers handles it correctly.. :/ \$\endgroup\$ Nov 21, 2022 at 15:42

7 Answers 7

5
\$\begingroup\$

Python3, 287 bytes:

import re
R=re.findall
V=lambda m,x,k=1:k if[]==x else V(m,x[1:],k*(int(x[0])if x[0].isdigit()else m))
E=lambda x,M=0:M if[]==x else E(x[1:],M+[-1,1][x[0][1][-1]!='-']*V(M,R('\d+|M',x[0][0]))*(x[0][1]!='MR'))
f=lambda x:''.join(map(''.join,k:=R('([M\d]+)(M(?:\-|\+)|MR)',x)))==x and E(k)

Try it online!

\$\endgroup\$
1
4
\$\begingroup\$

Python, 172 179 174 169 164 156 153 bytes

def f(x,M=0):
 try:exec(s("M(?=\d|M)","M*",s("(\d|M)M","\\1*M",s("R=","*=0M",s("(.*?)(M[-+R])",r"\2=\1;",x))))+"\nprint(M)")
 except:0
import re
s=re.sub

Attempt This Online!

-3 bytes thanks to @The Thonnu


Python, 148 155 150 145 140 137 bytes

lambda x,M=0:exec(s("M(?=\d|M)","M*",s("(\d|M)M","\\1*M",s("R=","*=0M",s("(.*?)(M[-+R])",r"\2=\1;",x))))+"\nprint(M)")
import re
s=re.sub

Attempt This Online!

Shorter version which throws an error for invalid expressions.

+7 bytes to both versions due to bug in code.

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

05AB1E, 52 47 bytes

0U…+-RS©D¶«.:¶¡ε®'Mì„X+…Xs-‚…)\0ª'U«:'M„XP:.V}X

Try it online or verify all test cases.

Explanation:"

0U            # Set variable `X` to 0 (it's 1 by default)
…+-RSD¶«.:¶¡  # Split the (implicit) input after each "+"/"-"/"R":
…+-RS         #  Push triplet ["+","-","R"]
     ©        #  Store it in variable `®` (without popping)
      D       #  Duplicate it
       ¶«     #  Append a newline to the values in the pair
         .:   #  Replace all "+"/"-"/"R" with "+\n"/"-\n"/"R\n" respectively in the
              #  (implicit) input
           ¶¡ #  Then split on newlines
ε             # Map over each substring:
              # (used as a foreach, where all will have their own separated stack):
 ®            #  Push triplet ["+","-","R"] from variable `®`
  'Mì        '#  Prepend an "M" in front of each
 „X+          #  Push string "X+"
     ‚        #  Pair it with
 …Xs-         #  String "Xs-"
     ª        #  And also append
 …)\0         #  String ")\0"
      'U«    '#  Append an "U" after all three: ["X+U","Xs-U",")\0U"]
 :            #  Replace all "M+"/"M-"/"MR" with "X+U"/"Xs-U"/")\0U" respectively
 'M„XP:      '#  Then replace all remaining "M" with "XP"
 .V           #  Execute it as 05AB1E code (see below)
}X            # After the map: push value `X`
              # (which is output implicitly as result)
)\0U          # MR:
)             #  Wrap the entire stack into a list
 \            #  Discard it
  0U          #  Reset `X` to 0

X+U           # M+:
X+            #  Add `X` to the top value
  U           #  Pop and store it as new value `X`

Xs-U          # M-:
X             #  Push `X`
 s            #  Wrap the top two values on the stack
  -           #  Subtract the value from `X`
   U          #  Pop and store it as new value `X`

XP            # Remaining M:
X             #  Push value `X`
 P            #  Get the product of all values on the stack (for the current group)
\$\endgroup\$
3
\$\begingroup\$

Vyxal D, 40 bytes

⁽±ḊƛǍ[f;f(nw‛MR‛¥⁼½dĿ÷Ė‟n±ß¥£!3=ß*)¥D⌊=*

Test suite. Returns blank in the case of an invalid expression.

Explanation:

⁽±Ḋ                                      # group digits and non-digits together, preserving order
   ƛǍ[f;                                 # split into list of chars for non-digit items
        f                                # flattened
         (                        )      # for each item:
          nw                             #  item, wrapped in a single list
            ‛MR                          #  literal "MR"
               ‛¥⁼½d                     #  list ["¥¥","⁼⁼"] (D flag: do not decompress string)
                    Ŀ                    #  transliterate
                     ÷Ė                  #  unwrap and execute the item:
                                         #    M: push register twice
                                         #    R: always 0, also makes stack length to 1
                                         #    + & -: add and subtract respectively
                                         #      concatenates with input if stack is insufficient
                                         #    <number>: push <number> as int
                       ‟                 #  rotate the item to the back of stack
                        n±ß¥             #  if the current item is numeric, push register
                                         #    (preventing the number from being stored)
                            £            #  store to register
                             !3=ß*       #  if stack length == 3, multiply
                                   ¥     # push register
                                    D⌊=* # multiply depending on being an integer
                                         # implicit output
\$\endgroup\$
3
\$\begingroup\$

Retina, 248 bytes

\d+|M
¶$&
\d+
*
{`^(.*)¶(_*¶)?MR|^.*¶M[-+](¶.*)*

+`^(.*)(¶-?_*¶?)M(?!.)
$1$2$1
^(.*¶-?)(_*)¶(-?)(_*)(?!.)
$1$3$.2*$4
--

^(.*)¶(.*)¶M([-+])
$1$3$2
\+-
-
--
+
^(_*)\+|^(-_*)-|^-(_*)\+\3|^(-_*?)(_*)\+\5
$1$2$4
)`(_+)-\1(\B)?
$#2*-
L$`^(-?)(_*)
$1$.2

Try it online! Link includes test cases. Explanation:

\d+|M
¶$&

Insert newlines before each number or memory operation. The newline before the very first operation serves to set the initial memory to zero.

\d+
*

Convert all the numbers to unary.

{`
)`

Repeat until all of the numbers and memory operations have been processed.

^(.*)¶(_*¶)?MR|^.*¶M[-+](¶.*)*

MR will reset just the memory and M- or M+ in an invalid place will clear everything resulting in an output of zero.

+`^(.*)(¶-?_*¶?)M(?!.)
$1$2$1

M either immediately after an MR, M- or M+, or with a number in between, will read the memory.

^(.*¶-?)(_*)¶(-?)(_*)(?!.)
$1$3$.2*$4
--

Two values (at least one of which will have been the result of a memory read) will multiply together.

^(.*)¶(.*)¶M([-+])
$1$3$2
\+-
-
--
+
^(_*)\+|^(-_*)-|^-(_*)\+\3|^(-_*?)(_*)\+\5
$1$2$4
(_+)-\1(\B)?
$#2*-

M+ and M- after the value will add it to or subtract it from the memory.

L$`^(-?)(_*)
$1$.2

Convert the final memory to decimal, ignoring any pending value.

\$\endgroup\$
2
  • \$\begingroup\$ Seems to fail for 2M+2M2MM+ -> 18 \$\endgroup\$ Nov 21, 2022 at 15:43
  • \$\begingroup\$ @KevinCruijssen At the time it wasn't obvious that numbers after M needed to be supported, but I guess I'll look at it at some point. \$\endgroup\$
    – Neil
    Nov 21, 2022 at 17:05
3
\$\begingroup\$

Charcoal, 78 72 bytes

≔¹ηF⪪⁺RθM«¿⊙ι№-+Rκ«≡§ι⁰-¿υ≧⁻Πυζ≔⁰η+¿υ≧⁺Πυζ≔⁰η≔⁰ζ≔⟦⟧υ≔Φιλι»⊞υζ¿ι⊞υIι»¿ηIζ

Try it online! Link is to verbose version of code. Explanation:

≔¹η

Start by assuming the expression is valid.

F⪪⁺RθM«

Split the input on M and loop over the parts, however prefix an R to the first part to get a free memory reset.

¿⊙ι№-+Rκ«

If this part contains a -, + or R, then:

≡§ι⁰

Switch over the first character in the part.

-¿υ≧⁻Πυζ≔⁰η

If it's a - then subtract the product of the stack from the memory, but if the stack is empty then mark the expression as invalid.

+¿υ≧⁺Πυζ≔⁰η

Similarly for +.

≔⁰ζ

Otherwise, this is an R, so clear the memory.

≔⟦⟧υ

Clear the stack.

≔Φιλι

Remove the leading character from the part.

»⊞υζ

Otherwise, push the memory to the stack.

¿ι⊞υIι

If the part isn't empty then push its value to the stack.

»¿ηIζ

If the expression was valid then output the memory.

\$\endgroup\$
3
  • \$\begingroup\$ Seems to fail for 2M+2M2MM+ -> 18 \$\endgroup\$ Nov 21, 2022 at 15:43
  • \$\begingroup\$ @KevinCruijssen At the time it wasn't obvious that numbers after M needed to be supported, but I guess I'll look at it at some point. \$\endgroup\$
    – Neil
    Nov 21, 2022 at 17:04
  • 1
    \$\begingroup\$ @KevinCruijssen I took the opportunity to change my approach and as a bonus it's now 10% shorter! \$\endgroup\$
    – Neil
    Nov 27, 2022 at 9:53
2
\$\begingroup\$

JavaScript (Node.js), 146 bytes

s=>eval(s.replace(/\d+|M[-+R]?/g,b=>`_${c?"*":""}=${b<":"?(d=c++,b):d&&b[1]?"m=``//":`m${(d=b[1])||";a"}=_;${c=!d,b>"M-"&&"m=0"}`};`,m=c=d=0)+"m")

Try it online!

Creates a program based on the input and then evaluates it. Returns the empty string for invalid inputs. My favorite aspect of this solution is using b<":" to separate numeric strings from the other kinds of strings that can appear here.


JavaScript (Node.js), 138 bytes

s=>eval(s.replace(/\d+|M[-+R]?/g,b=>`_${c?"*":""}=${b<":"?(d=c++,b):d&&b[1]||`m${(d=b[1])||";a"}=_;${c=!d,b>"M-"&&"m=0"}`};`,m=c=d=0)+"m")

Try it online!

Similar to @Mukundan314's reasoning, this version throws an error instead of returning a specific value.

\$\endgroup\$

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.