11
\$\begingroup\$

I define the following operators:

Manhattan Addition a +M b, for single-digit numbers, is the result of concatenating b onto a. So, a +M b = 10a + b. Therefore, the general operator +M is defined as thus:

a +M b = 10a + b

Manhattan Subtraction a –M b, for single-digit numbers, is the result of removing the last b from a. Therefore, the operator –M is defined as thus in pseudocode:

a –M b = a remove last b

Manhattan Multiplication a ×M b is the result of replacing all instances of b in a with b instances of b. Ergo, ×M is defined in pseudocode as:

a ×M b = a -> s/b/<b copies of b>/g

Manhattan Division a ÷M b is defined in terms of ×M:

1 ÷M b = the first character of b
a ÷M b = a ×M (1 ÷M b)

With all this in mind, create an interpreter that will evaluate infix expressions that use the following operators (i.e., a + b, not a b + or + a b)

+    Addition
-    Subtraction
/    Division
*    Multiplication
*M   Manhattan Multiplication
/M   Manhattan Division
+M   Manhattan Addition
-M   Manhattan Subtraction

Each Manhattan operator has a higher order precedence than their normal counterpart.

Test cases:

> 5 +M 10 + 3
63      // 5*10 + 10 + 3 => 60 + 3
> 10 *M 2
10      // no 2s in 10
> 10 *M 1
10      // one 1 in 10 replaced once
> 23 *M 3
2333    // 23 has one 3, which is replaced with three 3s
> 23 *M 2
223     // 23 has one 2, which is replaced with two 2s
> 232 *M 2
22322   // 232 has two 2s, which are replaced with two 2s
> 232 *M 23
23...(23 times)...232   // ...
> 123 *M 2 * 3
3669    // 1223 * 3 => 3669
> 5 + 3 +M 2
37      // 5 + (3 +M 2) => 5 + 32 => 37
> 150 /M 3
150     // 150 ÷M 3 => 150 ×M 3 => 150
> 150 /M 53
1555550 // 150 ÷M 53 => 150 ×M 5 => 1555550
> 50 -M 0
5
> 500 -M 0
50
> 5234 -M 5
234
> 12 +M 633 *M 3
6333453 // = 12 +M 6333333 = 120 + 6333333 = 6333453

This is a , so the shortest program in bytes wins.

Leaderboards

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

# Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the leaderboard snippet:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

var QUESTION_ID=59299,OVERRIDE_USER=8478;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"http://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

\$\endgroup\$
24
  • 14
    \$\begingroup\$ Why are you using the Unicode symbols × and ÷ instead of ASCII * and /? \$\endgroup\$ Oct 1, 2015 at 19:47
  • 1
    \$\begingroup\$ Why does 232 ×M 23 equal 23232? Shouldn't it equal 23 copies of 23 followed by a 2? \$\endgroup\$
    – senshin
    Oct 1, 2015 at 21:25
  • 1
    \$\begingroup\$ @ASCIIThenANSI I can see why you asked that. The choice is arbitrary. Unless if there is some pressing issue with my choice, I don't think I'll change it. \$\endgroup\$ Oct 1, 2015 at 21:33
  • 4
    \$\begingroup\$ It makes it arbitrarily harder for languages without good Unicode support to participate, which is not very fun, if the challenge isn't about Unicode. \$\endgroup\$
    – Lynn
    Oct 1, 2015 at 21:48
  • 2
    \$\begingroup\$ This question has not received enough attention because is not well specified. You define addition for sngle digit numbers, then your first example have 2 digits numbers. I give up... \$\endgroup\$
    – edc65
    Oct 8, 2015 at 6:25

3 Answers 3

11
+50
\$\begingroup\$

Perl, 100 99 98 bytes

97 bytes code + 1 byte command line

s/ |.*\K(\d)(\d*)-M\1|\+M/\2/g+s/(\d+)\*M(.)/$1=~s@$2@$&x$&@erg/e+s#/(M.)\d+#*\1#&&redo,$\=eval}{

Usage example:

echo "123 *M 2 * 3 + 150 /M 53" | perl -p entry.pl
\$\endgroup\$
2
  • \$\begingroup\$ If it makes your code shorter, you only have to use *M for xM and /M for <div>M. \$\endgroup\$ Oct 1, 2015 at 21:53
  • \$\begingroup\$ Congrats on the bounty! \$\endgroup\$ Oct 13, 2015 at 15:51
7
\$\begingroup\$

Python, 644 bytes

import operator as o,re
x,q,t,r,w='*/+-M';mm,md,ma,ms='*M /M +M -M'.split()
n=lambda x:x
a=lambda a,b:str(10*int(a)+int(b))
v=lambda a,b:a[::-1].replace(b,'',1)[::-1]
m=lambda a,b:a.replace(b,b*int(b))
d=lambda a,b:m(a,b[0])if a>0 else b[0]
def p(s):s=s.group();ss=s.split();l=s.split(ss[1]);h={mm:m,md:d,ma:a,ms:v,x:o.mul,q:o.div,t:o.add,r:o.sub}.get(ss[1],n);return str(h(*map(int if h in[o.mul,o.div,o.add,o.sub]else n,map(u,map(str.strip,l)))))
def u(s):z=r'\d+ (?:\{0}{2}|\{1}{2}) \d+';return re.sub(z.format(t,r,''),p,re.sub(z.format(t,r,w),p,re.sub(z.format(x,q,''),p,re.sub(z.format(x,q,w),p,re.sub(r'\((.*)\)',u,s)))))
print u(input())

Accepts input on STDIN (wrapped in quotes). Uses regex to match and parse operations. All work is done on strings, and casting to and from ints is only used when doing normal mathematical operations.

I'm pretty sure this could be golfed further, so I'll be working on that over the next few days.

\$\endgroup\$
1
  • \$\begingroup\$ I don't see a c or f. \$\endgroup\$
    – RK.
    Jun 29, 2016 at 16:17
4
\$\begingroup\$

Dyalog APL, 104 81 79 93 75 bytes

Edit: Now handles 4342343 -M 3443423 correctly.

M←{⍎(5|⌊⍺⍺2)⊃'⍺×M⍣(⍺≠1)⍎⊃b'(b⎕R(⍵⍴'&')⊢a)'10⊥⍺⍵'(('(.*)',b←⍕⍵)⎕R'\1'⊢a←⍕⍺)}

Background

This extends APL to include the Manhattan operator. An operator in APL terminology is a modifier of functions (e.g. ÷). An example of an operator is which modifies functions to swap their arguments so 3 = 2 ÷⍨ 6. So too, M modifies the basic arithmetic functions to be their Manhattan relatives. Note that since the resulting language is an extension of APL, APL's strict right-to-left precedence remains.

Explanation

The overarching structure is M←{⍎(5|⌊⍺⍺2)⊃} which applies the function (+ or - or × or ÷) to 2 and uses the result to chose which string to evaluate. The strings are:

3 for -M: (('(.*)',b←⍕⍵)⎕R'\1'⊢a←⍕⍺)
 regex remove the last occurrence of b (string rep. of right arg.) in a (string rep. of left arg.)

2 for +M: '10⊥⍺⍵'
 evaluate the arguments as base-10 digits

1 for ×M: (b⎕R(⍵⍴'&')⊢a)
 replace occurrences of b with b ampersands (i.e. regex for the

0 for ÷M: '⍺×M⍣(⍺≠1)⍎⊃b'
⍎⊃b first digit of b
⍺×M⍣(⍺≠1) apply ⍺ ×M if ⍺ ≠ 1

out of of the above four strings, pick number:

(5|⌊⍺⍺2) mod-5 of the floor of the function applied to 2, namely:
 3 = 5 | ⌊-2
 2 = 5 | ⌊+2
 1 = 5 | ⌊×2 because ×2 ⇔ sgn(2) ⇔ 1
 0 = 5 | ⌊÷2 because ÷2 ⇔ 1 ÷ 2 ⇔ 0.5

Lots of thanks to my dear friend ngn for amazing shavings.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ This is fine. It fits what I had desired. \$\endgroup\$ Oct 12, 2015 at 21:03
  • \$\begingroup\$ Great, I'll edit the post then. \$\endgroup\$
    – Adám
    Oct 12, 2015 at 21:15
  • \$\begingroup\$ @CᴏɴᴏʀO'Bʀɪᴇɴ I might have lost out on the bonus, but it sure is the shortest now. \$\endgroup\$
    – Adám
    Jun 29, 2016 at 9:47
  • \$\begingroup\$ oops, forgot about this one. \$\endgroup\$ Jun 29, 2016 at 17:23
  • \$\begingroup\$ @CᴏɴᴏʀO'Bʀɪᴇɴ Forgot? I just edited today, making it shorter than the accepted one. \$\endgroup\$
    – Adám
    Jun 29, 2016 at 20:02

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.