Spin the Calculator

16

Вступление:

Давайте посмотрим на стандартный калькулятор в Windows: для этой задачи мы рассмотрим только следующие кнопки и проигнорируем все остальное:
введите описание изображения здесь

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

Вызов:

Вход:
вы получите два входа:

  • Одним из них является то, что указывает на поворот с шагом 90 градусов
  • Другой - это список координат, представляющих кнопки, нажимаемые на повернутом калькуляторе.

Основываясь на первом входе, мы поворачиваем указанную выше схему по часовой стрелке с шагом 90 градусов. Так что, если ввод 0 degrees, он остается как есть; но если это вход 270 degrees, он будет вращаться три раза по часовой стрелке (или один раз против часовой стрелки). Вот четыре возможных макета:

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

Второй вход представляет собой список координат в любом приемлемом формате . Например (2D-целочисленный массив с 0 индексами):

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

Вывод:
выводим как сумму, так и результат (и знак равенства =).

Пример:
Итак, если входное значение равно 270 degreesи [[1,2],[2,3],[0,3],[1,0],[1,1]], выходное значение станет:

517*6=3102

Правила вызова:

  • Входные данные могут быть в любом разумном формате. Первый вход может быть 0-3, 1-4, A-D,0,90,180,270 и т.д. второй вход может быть 0 индексированные 2D массив, 1-индексированных 2D массив, строка, список точечных объектов и т.д. Ваш вызов. Можно даже поменять координаты x и y по сравнению с приведенными примерами входных данных. Пожалуйста, укажите, какие форматы ввода вы использовали в своем ответе!
  • Вам разрешено добавлять пробелы (т.е. 517 * 6 = 3102 ), если вы хотите.
  • Вы можете добавить завершающие нули после запятой, максимум до трех (т.е. 3102.0/ 3102.00/ 3102.000вместо 3102или 0.430вместо0.43 ).
  • Вам не разрешено добавлять круглые скобки в вывод, поэтому (((0.6+4)-0)/2)/4=0.575 не является допустимым выводом.
  • Вам разрешено использовать другие символы-операнды для вашего языка. Так ×или ·вместо *; или ÷вместо/ ; и т.п.
  • Поскольку калькулятор автоматически вычисляет при вводе операнда, вы должны игнорировать приоритет оператора! Таким образом 10+5*3, результатом будет 45( (10+5)*3=45), а не 25( 10+(5*3)=25)
    (т.е. 10+5*(теперь отображается 15 на дисплее) → 3=(теперь отображается ответ 45)). Помните об этом при использовании evalаналогичных функций и полученной суммы.
  • Там не будет никаких тестов для деления на 0.
  • Не будет никаких тестовых случаев с более чем тремя десятичными цифрами в результате, поэтому нет необходимости округлять результат.
  • Не будет никаких тестовых случаев, когда несколько операндов следуют друг за другом или когда две точки следуют друг за другом.
  • Там не будет никаких тестов для отрицательных чисел. Знак минус ( -) будет использоваться только как операнд, а не как отрицательный.
  • Не будет никаких тестов .##без запятой перед запятой (т.е. 2+.7не будет допустимым тестом, но 2+0.7может быть).

Основные правила:

  • Это , поэтому выигрывает самый короткий ответ в байтах.
    Не позволяйте языкам кода-гольфа отговаривать вас от публикации ответов на языках, не относящихся к кодексу. Попробуйте найти как можно более короткий ответ для «любого» языка программирования.
  • Применяются стандартные правила вашему ответу , поэтому вы можете использовать STDIN / STDOUT, функции / метод с соответствующими параметрами, полные программы. Ваш звонок.
  • По умолчанию лазейки запрещены.
  • Если возможно, добавьте ссылку с тестом для вашего кода.
  • Также, пожалуйста, добавьте объяснение, если это необходимо.

Тестовые случаи:

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
Кевин Круйссен
источник
1
В тестовых примерах много ошибок (например, в 3-м и 4-м
местах
2
Должна ли программа обрабатывать странные нажатия кнопок? 1+-*/+-*/2даст 0.5на Windows (10) калькулятор.
user202729
1
Второй тестовый случай должен начаться с[1,3],
Уриэль
1
Должны ли мы обрабатывать десятичные числа меньше 1 без начальных 0, как в 2+.7?
Тутлеман
4
Приоритет оператора - вот почему я никогда не использую калькулятор Windows в стандартном режиме.
Нил

Ответы:

4

SOGL V0.12 , 70 69 67 байтов

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

Попробуйте здесь или попробуйте версию, которая принимает входные данные, указанные в тестовых примерах

использует Iоператор SOGL , который вращает массив. Затем считывает строку в виде массива JavaScript и, где используется операция, заключает предыдущий результат в скобки, оценивает как JavaScript, а затем удаляет скобки.

dzaima
источник
3

Dyalog APL, 94 88 86 85 байт

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

Попробуйте онлайн!

Принимает повороты как левый аргумент, 0-3а индексы на основе 1 - как правый аргумент, как список y xкоординат, как (1 1)(2 3)(4 5)и т. Д.

Это стало довольно грязно из-за правосторонней оценки выражений в APL.

Уриэль
источник
3

C (gcc) , 282294 295 296 300 304 306 310 байтов

Все оптимизации должны быть отключены и работать только на 32-битном 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 байт благодаря @Orion!

Попробуйте онлайн!

Функциональный прототип:

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

Формат ввода (как на 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>

Беззвучная версия с комментариями:

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

Код может обрабатывать такие случаи, как 1+.7или -8*4.

Очень грустный C не имеет eval😭.

Кейу Ган
источник
Вы действительно можете считать случаи 3*-5недействительными. Я указал это в правилах.
Кевин Круйссен
Учитывая требуемую точность в правилах есть только 3 места, вы могли бы заменить doubleс floatдля свободного байта. Кроме того, не putc()идентичен putchar()? Хотя я могу ошибаться.
Орион
@ Помню, мне putcнужен второй аргумент, чтобы указать, в какой поток вы пишете?
Кейу Ган
292 байта
floorcat
2

JavaScript (ES6), 162 160 157 байт

Принимает ввод как ориентацию oи массив (y, x) координат aв синтаксисе каррирования (o)(a).

Ориентация является целым числом в [0..3] :

  • 0 = 0 °
  • 1 = 90 ° по часовой стрелке
  • 2 = 180 ° по часовой стрелке
  • 3 = 270 ° по часовой стрелке
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`)`)

Контрольные примеры

Arnauld
источник
2

Рубин , 135 133 132 байта

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

Попробуйте онлайн!

Ориентация в виде целого числа: 0 для 0 °, 1 для 90 ° и так далее.

гигабайт
источник
1

Python 3, 235 234 230 байт

Немного некрасиво, но это работает для всех тестовых случаев, кроме первого, что, похоже, не соответствует примеру калькулятора. Я принимаю вращение за 0-3 (0-270) и умножаю на 16, чтобы сместить.

eval() является встроенным, который пытается скомпилировать строки в виде кода и обрабатывает преобразование текстовых символов в операторы.

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

Альтернативный метод, оказалось немного дольше, но мне очень нравится этот совет по вращению массива.

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])
Ноктюрама
источник
1

Java 10, 418 380 байт

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

Решил ответить и на свой вопрос. Я уверен, что это можно сыграть еще немного, используя другой подход.
Введите как int( 0-3) и int[][](0-индексированный / такой же, как в описании вызова). Выведите как floatс начальным, .0если результатом является целое число вместо десятичного числа.

Объяснение:

Попробуй это здесь.

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
Кевин Круйссен
источник