Gira la calculadora

16

Introducción:

Echemos un vistazo a una calculadora estándar en Windows: para este desafío, solo veremos los siguientes botones e ignoraremos todo lo demás:
ingrese la descripción de la imagen aquí

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

Desafío:

Entrada:
Recibirá dos entradas:

  • Uno es algo para indicar la rotación en incrementos de 90 grados
  • La otra es una lista de coordenadas que representan los botones presionados en la calculadora girada.

Según la primera entrada, giramos el diseño mencionado anteriormente en el sentido de las agujas del reloj en incrementos de 90 grados. Entonces, si la entrada es 0 degrees, permanece como está; pero si la entrada es 270 degrees, se rotará tres veces en sentido horario (o una vez en sentido antihorario). Aquí están los cuatro diseños posibles:

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

La segunda entrada es una lista de coordenadas en cualquier formato razonable . Por ejemplo (0-index 2D integer-array):

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

Salida:
sacamos tanto la suma como el resultado (y un signo igual =).

Ejemplo:
Entonces, si la entrada es 270 degreesy [[1,2],[2,3],[0,3],[1,0],[1,1]], la salida se convertirá en:

517*6=3102

Reglas de desafío:

  • Las entradas pueden estar en cualquier formato razonable. La primera entrada puede ser 0-3, 1-4, A-D, 0,90,180,270, etc. La segunda entrada puede ser una matriz de 0 indexados 2D, array 1 indexadas-2D, una cadena, lista de Point-objetos, etc. Su llamada. Incluso es posible intercambiar las coordenadas x e y en comparación con las entradas de ejemplo proporcionadas. ¡Indique qué formatos de entrada ha utilizado en su respuesta!
  • Se le permite agregar espacios (es decir 517 * 6 = 3102) si lo desea.
  • Se le permite agregar ceros finales después de la coma, hasta un máximo de tres (es decir, 3102.0/ 3102.00/ en 3102.000lugar de 3102o en 0.430lugar de 0.43).
  • No está permitido agregar paréntesis en la salida, por (((0.6+4)-0)/2)/4=0.575lo que no es una salida válida.
  • Puede utilizar otros símbolos de operando para su idioma. Entonces ×o en ·lugar de *; o en ÷lugar de /; etc.
  • Dado que una calculadora calcula automáticamente al ingresar un operando, ¡debe ignorar la precedencia del operador! Entonces 10+5*3dará como resultado 45( (10+5)*3=45), no 25( 10+(5*3)=25)
    (es decir, 10+5*(ahora muestra 15 en la pantalla) → 3=(ahora muestra la respuesta 45)). Tenga esto en cuenta cuando use evalfunciones similares en la suma resultante.
  • No habrá casos de prueba para la división por 0.
  • No habrá casos de prueba con más de tres dígitos decimales como resultado, por lo que no es necesario redondear el resultado.
  • No habrá ningún caso de prueba en el que varios operandos se sigan, o donde dos puntos se sigan.
  • No habrá casos de prueba para números negativos. El signo menos ( -) solo se usará como operando, no como negativo.
  • No habrá ningún caso de prueba .##sin un número inicial antes de la coma (es decir 2+.7, no será un caso de prueba válido, pero 2+0.7podría serlo).

Reglas generales:

  • Este es el , por lo que la respuesta más corta en bytes gana.
    No permita que los lenguajes de code-golf lo desanimen a publicar respuestas con lenguajes que no sean codegolf. Trate de encontrar una respuesta lo más breve posible para 'cualquier' lenguaje de programación.
  • Se aplican reglas estándar para su respuesta, por lo que puede usar STDIN / STDOUT, funciones / método con los parámetros adecuados, programas completos. Tu llamada.
  • Las lagunas predeterminadas están prohibidas.
  • Si es posible, agregue un enlace con una prueba para su código.
  • Además, agregue una explicación si es necesario.

Casos de prueba:

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
Kevin Cruijssen
fuente
1
Los casos de prueba tienen muchos errores (por ejemplo, el 3 ° y el 4 ° tienen X e Y intercambiados (el 1 ° no) y ni siquiera sé qué pasó con el 2 °)
dzaima
2
¿Debería el programa manejar extrañas pulsaciones de botones? 1+-*/+-*/2will da 0.5en la calculadora de Windows (10).
user202729
1
segundo caso de prueba debe comenzar con[1,3],
Uriel
1
¿Tenemos que asa décimas menos que 1 sin 0s principales, como en 2+.7?
Tutleman
44
La prioridad del operador es la razón por la que nunca uso la Calculadora de Windows en modo estándar.
Neil

Respuestas:

3

Dyalog APL, 94 88 86 85 bytes

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

Pruébalo en línea!

Toma las rotaciones como argumento izquierdo 0-3, y los índices basados ​​en 1 como argumento derecho, como una lista de y xcoordenadas, como (1 1)(2 3)(4 5)etc.

Esto se volvió bastante complicado debido a la evaluación diestra de las expresiones en APL.

Uriel
fuente
3

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

Todas las optimizaciones deben desactivarse y solo funcionan en GCC de 32 bits.

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 gracias a @Orion!

Pruébalo en línea!

Prototipo de la función:

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

Formato de entrada (como en 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>

Versión sin golf con comentarios:

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);
}

El código puede manejar casos como 1+.7o -8*4.

Muy triste C no tiene un eval😭.

Keyu Gan
fuente
De hecho, puede considerar casos como 3*-5inválidos. He especificado esto en las reglas.
Kevin Cruijssen
Teniendo en cuenta la precisión requerida en las bases es de sólo 3 lugares, se puede sustituir doublecon floatun byte libre. Además, ¿no es putc()idéntico a putchar()? Sin embargo, podría estar equivocado.
Orion
@Orion ¿Recuerdo que putcnecesita un segundo argumento para especificar en qué transmisión está escribiendo?
Keyu Gan
292 bytes
ceilingcat
2

JavaScript (ES6), 162 160 157 bytes

Toma la entrada como orientación oy matriz de coordenadas (y, x)a en la sintaxis de curry (o)(a).

La orientación es un número entero en [0..3] :

  • 0 = 0 °
  • 1 = 90 ° en sentido horario
  • 2 = 180 ° en sentido horario
  • 3 = 270 ° en sentido horario
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`)`)

Casos de prueba

Arnauld
fuente
2

Rubí , 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}"}

Pruébalo en línea!

Orientación como entero: 0 para 0 °, 1 para 90 ° y así sucesivamente.

GB
fuente
1

Python 3, 235 234 230 bytes

Un poco feo, pero funciona para todos los casos de prueba, excepto el primero, que no parece coincidir con la calculadora de ejemplo. Tomo la rotación como 0-3 (0-270) y multiplico por 16 para compensar.

eval() es una función integrada que intenta compilar cadenas como código y maneja la conversión de los símbolos de texto a operadores.

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])

Método alternativo, resultó un poco más largo, pero realmente me gusta este consejo SO para rotar la matriz.

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])
nocturama
fuente
1

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;}

Decidí responder mi propia pregunta también. Estoy seguro de que se puede jugar un poco más utilizando un enfoque diferente.
Ingrese como int( 0-3) y int[][](0-indexado / igual que en la descripción del desafío). Salida como floatcon el interlineado .0si el resultado es un número entero en lugar de un número decimal.

Explicación:

Pruébalo aquí

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
Kevin Cruijssen
fuente