Gire a calculadora

16

Introdução:

Vamos dar uma olhada em uma calculadora padrão no Windows: para esse desafio, veremos apenas os seguintes botões e ignoraremos todo o resto:
insira a descrição da imagem aqui

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

Desafio:

Entrada:
você receberá duas entradas:

  • Um é algo para indicar a rotação em incrementos de 90 graus
  • A outra é uma lista de coordenadas que representam os botões pressionados na calculadora girada.

Com base na primeira entrada, giramos o layout mencionado acima no sentido horário em incrementos de 90 graus. Portanto, se a entrada é 0 degrees, permanece como é; mas se a entrada for 270 degrees, ela será girada três vezes no sentido horário (ou uma vez no sentido anti-horário). Aqui estão os quatro layouts possíveis:

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

A segunda entrada é uma lista de coordenadas em qualquer formato razoável . Por exemplo (matriz de números inteiros 2D com 0 índices):

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

Saída:
Nós produzimos tanto a soma quanto o resultado (e um sinal de igual =).

Exemplo:
Portanto, se a entrada for 270 degreese [[1,2],[2,3],[0,3],[1,0],[1,1]], a saída se tornará:

517*6=3102

Regras do desafio:

  • As entradas podem estar em qualquer formato razoável. A primeira entrada pode ser 0-3, 1-4, A-D, 0,90,180,270, etc. A segunda entrada pode ser uma matriz 2D 0-indexados, array 1-indexados 2D, uma String, lista de Point-objetos, etc. Sua chamada. É até possível trocar as coordenadas x e y em comparação com as entradas de exemplo fornecidas. Indique quais formatos de entrada você usou em sua resposta!
  • Você tem permissão para adicionar espaços (ou seja 517 * 6 = 3102), se desejar.
  • Você tem permissão para adicionar zeros à direita após a vírgula, até um máximo de três (ou seja, 3102.0/ 3102.00/ em 3102.000vez de 3102ou em 0.430vez de 0.43).
  • Você não tem permissão para adicionar parênteses na saída, portanto, (((0.6+4)-0)/2)/4=0.575não é uma saída válida.
  • Você tem permissão para usar outros símbolos de operando no seu idioma. Então ×ou em ·vez de *; ou em ÷vez de /; etc.
  • Como uma calculadora calcula automaticamente ao inserir um operando, você deve ignorar a precedência do operador! Portanto 10+5*3, resultará em 45( (10+5)*3=45), não 25( 10+(5*3)=25)
    (ou seja, 10+5*(agora exibe 15 no visor) → 3=(agora exibe a resposta 45)). Lembre-se disso ao usar evalfunções semelhantes na soma resultante.
  • Não haverá casos de teste para divisão por 0.
  • Não haverá casos de teste com mais de três dígitos decimais como resultado, portanto, não há necessidade de arredondar o resultado.
  • Não haverá casos de teste em que vários operandos se sigam ou em que dois pontos se sigam.
  • Não haverá casos de teste para números negativos. O sinal de menos ( -) será usado apenas como operando, não como negativo.
  • Não haverá casos de teste .##sem um número inicial antes da vírgula (ou seja 2+.7, não será um caso de teste válido, mas 2+0.7poderia ser).

Regras gerais:

  • Isso é , então a resposta mais curta em bytes vence.
    Não permita que idiomas com código de golfe o desencorajem a postar respostas com idiomas que não sejam codegolf. Tente encontrar uma resposta o mais curta possível para 'qualquer' linguagem de programação.
  • As regras padrão se aplicam à sua resposta, para que você possa usar STDIN / STDOUT, funções / método com os parâmetros adequados, programas completos. Sua chamada.
  • As brechas padrão são proibidas.
  • Se possível, adicione um link com um teste para o seu código.
  • Além disso, adicione uma explicação, se necessário.

Casos de teste:

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
fonte
1
Os casos de teste têm muitos erros (por exemplo, a 3ª e 4ª tem X e Y trocadas (1º não) e eu não sei mesmo o que aconteceu com o 2º)
dzaima
2
O programa deve lidar com pressionamentos de botão estranhos? 1+-*/+-*/2vontade dá 0.5na calculadora Windows (10).
user202729
1
segundo caso de teste deve começar com[1,3],
Uriel
1
Temos que lidar com decimais menores que 1 sem zeros à esquerda, como em 2+.7?
Tutleman
4
A precedência do operador é o motivo pelo qual nunca uso a Calculadora do Windows no modo padrão.
22417 Neil

Respostas:

3

Dyalog APL, 94 88 86 85 bytes

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

Experimente online!

Toma as rotações como argumento à esquerda 0-3, e os índices baseados em 1 como argumento à direita, como uma lista de y xcoordenadas, como (1 1)(2 3)(4 5)etc.

Isso ficou bastante confuso por causa da avaliação destra de expressões no APL.

Uriel
fonte
3

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

Todas as otimizações precisam ser desativadas e funcionam apenas no 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 graças a @Orion!

Experimente online!

Função protótipo:

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

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

Versão ungolfed com comentários:

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

O código pode lidar com casos como 1+.7ou -8*4.

C muito triste não tem eval😭.

Keyu Gan
fonte
Você pode realmente considerar casos como 3*-5inválidos. Eu especifiquei isso nas regras.
Kevin Cruijssen
Considerando a precisão exigida nas regras é de apenas 3 lugares, você poderia substituir doublecom floatum byte livre. Além disso, não é putc()idêntico a putchar()? Eu poderia estar errado, no entanto.
Orion
@ Orion Lembro que putcpreciso de um segundo argumento para especificar em qual stream você está escrevendo?
Keyu Gan
292 bytes
tetocat 30/09/19
2

JavaScript (ES6), 162 160 157 bytes

Recebe a entrada como orientação oe matriz de coordenadas (y, x)a na sintaxe de currying (o)(a).

A orientação é um número inteiro em [0..3] :

  • 0 = 0 °
  • 1 = 90 ° no sentido horário
  • 2 = 180 ° no sentido horário
  • 3 = 270 ° no sentido horário
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 teste

Arnauld
fonte
2

Rubi , 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}"}

Experimente online!

Orientação como número inteiro: 0 para 0 °, 1 para 90 ° e assim por diante.

GB
fonte
1

Python 3, 235 234 230 bytes

Um pouco feio, mas funciona para todos os casos de teste, exceto o primeiro, que não parece coincidir com a calculadora de exemplo. Tomo a rotação como 0-3 (0-270) e multiplico por 16 para compensar.

eval() é um recurso interno que tenta compilar cadeias de caracteres como código e manipula a conversão dos símbolos de texto em 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, ficou um pouco mais longo, mas eu realmente gosto dessa dica de SO para girar o 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])
nocturama
fonte
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;}

Decidi responder minha própria pergunta também. Tenho certeza de que pode jogar mais um pouco usando uma abordagem diferente.
Insira como int( 0-3) e int[][](indexado 0 / o mesmo que na descrição do desafio). Saída como floatà esquerda .0se o resultado for um número inteiro em vez de um número decimal.

Explicação:

Experimente aqui.

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
fonte