16
\$\begingroup\$

Introduction:

Let's take a look at a standard Calculator in Windows:
enter image description here
For this challenge, we'll only look at the following buttons, and ignore everything else:

7 8 9 /
4 5 6 *
1 2 3 -
0 0 . +

Challenge:

Input:
You will receive two inputs:

  • One is something to indicate the rotation in increments of 90 degrees
  • The other is a list of coordinates representing the buttons pressed on the rotated calculator.

Based on the first input, we rotate the layout mentioned above clockwise in increments of 90 degrees. So if the input is 0 degrees, it remains as is; but if the input is 270 degrees, it will be rotated three times clockwise (or once counterclockwise). Here are the four possible lay-outs:

Default / 0 degrees:
7 8 9 /
4 5 6 *
1 2 3 -
0 0 . +

90 degrees clockwise:
0 1 4 7
0 2 5 8
. 3 6 9
+ - * /

180 degrees:
+ . 0 0
- 3 2 1
* 6 5 4
/ 9 8 7

270 degrees clockwise / 90 degrees counterclockwise:
/ * - +
9 6 3 .
8 5 2 0
7 4 1 0

The second input is a list of coordinates in any reasonable format . For example (0-index 2D integer-array):

[[1,2],[2,3],[0,3],[1,0],[1,1]]

Output:
We output both the sum, as well as the result (and an equal sign =).

Example:
So if the input is 270 degrees and [[1,2],[2,3],[0,3],[1,0],[1,1]], the output will become:

517*6=3102

Challenge rules:

  • The inputs can be in any reasonable format. The first input can be 0-3, 1-4, A-D, 0,90,180,270, etc. The second input can be a 0-indexed 2D array, 1-indexed 2D array, a String, list of Point-objects, etc. Your call. It's even possible to swap the x and y coordinates compared to the example inputs given. Please state which input formats you've used in your answer!
  • You are allowed to add spaces (i.e. 517 * 6 = 3102) if you want to.
  • You are allowed to add trailing zeros after the comma, to a max of three (i.e. 3102.0/3102.00/3102.000 instead of 3102 or 0.430 instead of 0.43).
  • You are not allowed to add parenthesis in the output, so (((0.6+4)-0)/2)/4=0.575 is not a valid output.
  • You are allowed to use other operand-symbols for your language. So × or · instead of *; or ÷ instead of /; etc.
  • Since a calculator automatically calculates when inputting an operand, you should ignore operator precedence! So 10+5*3 will result in 45 ((10+5)*3=45), not 25 (10+(5*3)=25)
    (i.e. 10+5* (it now displays 15 in the display) → 3= (it now displays the answer 45)). Keep this in mind when using eval and similar functions on the resulting sum.
  • There won't be any test cases for division by 0.
  • There won't be any test cases with more than three decimal digits as result, so no need for rounding the result.
  • There won't be any test cases where multiple operands follow each other, or where two dots follow each other.
  • There won't be any test cases for negative numbers. The minus-sign (-) will only be used as operand, not as negative.
  • There won't be any test cases for .## without a leading number before the comma (i.e. 2+.7 will not be a valid test case, but 2+0.7 could be).

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code.
  • Also, please add an explanation if necessary.

Test cases:

Input:   270 degrees & [[1,2],[2,3],[0,3],[1,0],[1,1]]
Output:  517*6=3102

Input:   90 degrees & [[3,1],[0,0],[0,1],[3,3],[2,0],[0,3],[0,0],[0,2],[3,0],[2,1]]
Output:  800/4+0.75=200.75

Input:   0 degrees & [[0,0],[1,0],[2,0],[3,0],[1,2],[2,1],[2,2]]
Output:  789/263=3

Input:   180 degrees & [[3,0],[1,0],[1,2],[0,0],[3,2],[0,1],[2,0],[0,3],[2,1],[0,3],[3,2]]
Output:  0.6+4-0/2/4=0.575
\$\endgroup\$
  • 1
    \$\begingroup\$ The test cases have many errors (e.g. the 3rd and 4th has X and Y swapped (1st doesn't) and I don't even know what happened to the 2nd) \$\endgroup\$ – dzaima Jun 22 '17 at 15:14
  • 2
    \$\begingroup\$ Should the program handle weird button presses? 1+-*/+-*/2 will gives 0.5 on Windows (10) calculator. \$\endgroup\$ – user202729 Jun 22 '17 at 15:21
  • 1
    \$\begingroup\$ second test case should start with [1,3], \$\endgroup\$ – Uriel Jun 22 '17 at 15:37
  • 1
    \$\begingroup\$ Do we have to handle decimals less than 1 without leading 0s, like in 2+.7? \$\endgroup\$ – Tutleman Jun 22 '17 at 15:37
  • 4
    \$\begingroup\$ Operator precedence is why I never use Windows Calculator in standard mode. \$\endgroup\$ – Neil Jun 22 '17 at 17:03
4
\$\begingroup\$

SOGL V0.12, 70 69 67 bytes

i⅛⁸Νο;⌡░▼Y6γj±²‘1n4n.⌡Iø,→{_≤whwιh:"/*-+”;W? )Κ; (Κ;}+}:Ƨ)(čøŗoļ=→p

Try it Here, or try a version which takes inputs as given in the test-cases

uses SOGLs I operator, which rotates the array. Then reads a string as a JavaScript array, and where an operation is used, encase previous result in parentheses, evaluates as JavaScript and then removes the parentheses.

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

Dyalog APL, 94 88 86 85 bytes

{o,'=',⍎('('\⍨+/'+-×÷'∊⍨o),'[×÷+-]'⎕R')&'⊢o←(((⌽∘⍉⍣⍺)4 4⍴'789÷456×123-00.+')⊃⍨⊂∘⊢)¨⍵}

Try it online!

Takes the rotations as left argument, 0-3, and the 1-based indices as right argument, as a list of y x coordinates, like (1 1)(2 3)(4 5) etc.

This got quite messy because of the right-handed evaluation of expressions in APL.

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

C (gcc), 282 294 295 296 300 304 306 310 bytes

All optimizations need to be turned off and only work on 32-bit GCC.

float r,s;k,p,l,i;g(d,x,y){int w[]={y,x,3-y,3-x,y};d=w[d+1]*4+w[d];}f(x,y,z)int**z;{for(i=0;i<=y;i++)putchar(k=i-y?"789/456*123-00.+"[g(x,z[i][0],z[i][1])]:61),57/k*k/48?p?r+=(k-48)*pow(10,p--):(r=10*r+k-48):k-46?s=l?l%2?l%5?l&4?s/r:s+r:s-r:s*r:r,r=p=0,l=k:(p=-1);printf("%.3f",s);}

1 byte thanks to @Orion!

Try it online!

Function prototype:

f(<Direction 0-3>, <Number of entries>, <a int** typed array in [N][2]>)

Input format (as on TIO):

<Direction 0~3> <Number of entries>
<Entries 0 Row> <Entries 0 Column>
<Entries 1 Row> <Entries 1 Column>
....
<Entries N Row> <Entries N Column>

Ungolfed version with comments:

float r, s;
k, p, l, i;
g(d, x, y) {
  int w[] = {
    y,
    x,
    3 - y,
    3 - x,
    y
  };
  d = w[d + 1] * 4 + w[d];
}
f(x, y, z) int **z; {
  for (i = 0; i <= y; i++)
  {
      putchar(k = i - y ? 
      "789/456*123-00.+"[g(x, z[i][0], z[i][1])] : 61),     // Print character, otherwise, '='
      57 / k * k / 48 ?                                     // If the character is from '0'~'9'
        p ?                                                 // If it is after or before a dot
            r += (k - 48) * pow(10., p--)                   // +k*10^-p
        :
            (r = 10 * r + k - 48)                           // *10+k
      :
          k - 46 ?                                          // If the character is not '.', that is, an operator, + - * / =
            s = l ?                                         // Calculate the result of previous step (if exist)
                    l % 2 ?                                 // If + - /
                        l % 5 ?                             // If + /
                            l & 4 ?
                                s / r
                            :
                                s + r
                        :
                            s - r
                    :
                        s * r
                 :
                    r,
                    r = p = 0, l = k                        // Reset all bits
          :
            (p = -1);                                       // Reverse the dot bit
  }
  printf("%.3f", s);
}

The code can handle cases such as 1+.7 or -8*4.

Very sad C doesn't have an eval 😭.

\$\endgroup\$
  • \$\begingroup\$ You can indeed deem cases like 3*-5 invalid. I've specified this in the rules. \$\endgroup\$ – Kevin Cruijssen Jun 22 '17 at 17:31
  • \$\begingroup\$ Considering the required precision in the rules is only 3 places, you could replace double with float for a free byte. Also, isn't putc() identical to putchar()? I could be wrong, though. \$\endgroup\$ – Orion Jun 23 '17 at 0:10
  • \$\begingroup\$ @Orion I remember putc needs a second argument to specify which stream you are writing to? \$\endgroup\$ – Keyu Gan Jun 23 '17 at 5:20
  • \$\begingroup\$ 292 bytes \$\endgroup\$ – ceilingcat Sep 30 at 15:59
2
\$\begingroup\$

JavaScript (ES6), 162 160 157 bytes

Takes input as orientation o and array of (y,x) coordinates a in currying syntax (o)(a).

The orientation is an integer in [0..3]:

  • 0 = 0°
  • 1 = 90° clockwise
  • 2 = 180° clockwise
  • 3 = 270° clockwise
o=>a=>(s=a.map(([y,x])=>'789/456*123-00.+'[[p=y*4+x,12+(y-=x*4),15-p,3-y][o]]).join``)+'='+eval([...x=`0)+${s}`.split(/(.[\d.]+)/)].fill`(`.join``+x.join`)`)

Test cases

let f =

o=>a=>(s=a.map(([y,x])=>'789/456*123-00.+'[[p=y*4+x,12+(y-=x*4),15-p,3-y][o]]).join``)+'='+eval([...x=`0)+${s}`.split(/(.[\d.]+)/)].fill`(`.join``+x.join`)`)

console.log(f(3)([[2,1],[3,2],[3,0],[0,1],[1,1]])) // 517*6=3102
console.log(f(1)([[1,3],[0,0],[1,0],[3,3],[0,2],[3,0],[0,0],[2,0],[0,3],[1,2]])) // 800/4+0.75=200.75
console.log(f(0)([[0,0],[0,1],[0,2],[0,3],[2,1],[1,2],[2,2]])) // 789/263=3
console.log(f(2)([[0,3],[0,1],[2,1],[0,0],[2,3],[1,0],[0,2],[3,0],[1,2],[3,0],[2,3]])) // 0.6+4-0/2/4=0.575

\$\endgroup\$
2
\$\begingroup\$

Ruby, 135 133 132 bytes

->r,c{a="";c.map{|x,y|a=((w="789/456*123-00.+"[[y*4+x,12-x*4+y,15-y*4-x,x*4+3-y][r]])=~/[0-9.]/?a:"#{eval a}")+w;w}*""+"=#{eval a}"}

Try it online!

Orientation as integer: 0 for 0°, 1 for 90° and so on.

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

Python 3, 235 234 230 bytes

Bit ugly but it works for all the test cases except the first, which doesn't seem to match the example calculator. I take the rotation as 0-3 (0-270) and multiply by 16 to offset.

eval() is a built-in which attempts to compile strings as code and handles converting the text symbols to operators.

import re
def f(r,c,J=''.join):
 b='789/456*123-00.+01470258.369+-*/+.00-321*654/987/*-+963.85207410'
 s=t=J([b[r*16+x*4+y]for y,x in c]);t=re.split('([\+\-\/\*])',s)
 while len(t)>2:t=[str(eval(J(t[0:3])))]+t[3:]
 print(s+'='+t[0])

Alternate method, it turned out a little bit longer but I really like this SO tip for rotating the array.

import re
def f(r,c):
 L=list;b=L(map(L,['789/','456*','123-','00.+']))
 while r:b=L(zip(*b[::-1]));r-=1
 s=''.join([b[x][y]for y,x in c]);t=re.split('([\+\-\/\*])',s)
 while len(t)>2:t=[str(eval(''.join(t[0:3])))]+t[3:]
 print(s+'='+t[0])
\$\endgroup\$
1
\$\begingroup\$

Java 10, 418 380 bytes

d->a->{String r="",g=d>2?"/*-+963.85207410":d>1?"+.00-321*654/987":d>0?"01470258.369+-*/":"789/456*123-00.+",n[],o[];for(var i:a)r+=g.charAt(i[1]*4+i[0]);n=r.split("[-/\\+\\*]");o=r.split("[[0-9]\\.]");float s=new Float(n[0]),t;for(int i=1,O,j=0;++j<o.length;O=o[j].isEmpty()?99:o[j].charAt(0),s=O<43?s*t:O<44?s+t:O<46?s-t:O<48?s/t:s,i+=O>98?0:1)t=new Float(n[i]);return r+"="+s;}

Decided to answer my own question as well. I'm sure it can be golfed some more by using a different approach.
Input as int (0-3) and int[][] (0-indexed / the same as in the challenge description). Output as float with leading .0 if the result is an integer instead of decimal number.

Explanation:

Try it here.

d->a->{                       // Method with int & 2D int-array parameters and String return
  String r="",                //  Result-String, starting empty
    g=d>2?                    //  If the input is 3:
       "/*-+963.85207410"     //   Use 270 degree rotated String
      :d>1?                   //  Else if it's 2:
       "+.00-321*654/987"     //   Use 180 degree rotated String
      :d>0?                   //  Else if it's 1:
       "01470258.369+-*/"     //   Use 90 degree rotated String
      :                       //  Else (it's 0):
       "789/456*123-00.+",    //   Use default String
    n[],o[];                  //  Two temp String-arrays
  for(var i:a)                //  Loop over the coordinates:
    r+=g.charAt(i[1]*4+i[0]); //   Append the result-String with the next char
  n=r.split("[-/\\+\\*]");    //  String-array of all numbers
  o=r.split("[[0-9]\\.]");    //  String-array of all operands (including empty values unfortunately)
  float s=new Float(n[0]),    //  Start the sum at the first number
        t;                    //  A temp decimal
  for(int i=0,                //  Index-integer `i`, starting at 0
      O,                      //  A temp integer
      j=0;++j<o.length        //  Loop `j` over the operands
      ;                       //    After every iteration:
       O=o[j].isEmpty()?      //     If the current operand is an empty String
          99                  //      Set `O` to 99
         :                    //     Else:
          o[j].charAt(0),     //      Set it to the current operand character
       s=O<43?                //     If the operand is '*':
          s*t                 //      Multiply the sum with the next number
         :O<44?               //     Else-if the operand is '+':
          s+t                 //      Add the next number to the sum
         :O<46?               //     Else-if the operand is '-':
          s-t                 //      Subtract the next number from the sum 
         :O<48?               //     Else-if the operand is '/':
          s/t                 //      Divide the sum by the next number
         :                    //     Else (the operand is empty):
          s,                  //      Leave the sum the same
       i+=O>98?0:1)           //     Increase `i` if we've encountered a non-empty operand
    t=new Float(n[i]);        //   Set `t`  to the next number in line
  return r+"="+s;}            //  Return the sum + sum-result
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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