Давайте сделаем некоторую арифметику местоположения!


22

Из статьи Википедии :

Локальная арифметика (Latin arithmeticæ localis) - это аддитивные (непозиционные) двоичные системы счисления, которые Джон Нейпир исследовал как метод вычисления в своем трактате «Рабдология» (1617), как символически, так и на шахматной решетке.

Какая?

Расположение цифр - это способ написания чисел с использованием букв алфавита.

Двоичная запись еще не была стандартизирована, поэтому Нейпир использовал то, что он называл цифрами местоположения, для представления двоичных чисел. Система Нейпира использует нотацию знак-значение для представления чисел; он использует последовательные буквы английского алфавита для представления последовательных степеней двух: a = 2 ^ 0 = 1, b = 2 ^ 1 = 2, c = 2 ^ 2 = 4, d = 2 ^ 3 = 8, e = 2 ^ 4 = 16 и так далее.

Пример

ab = 1 + 2 = 3 в базе 10

aabb = 1 + 1 + 2 + 2 = 6 в базе 10

Обратите внимание, что aabbэто можно сократить bc, заменив любые 2 экземпляра буквы на более высокий.

прибавление

Вы просто соединяете два числа и упрощаете.

acd+ bde= acdbde= abcdde= acebe= abcf= 39в базе 10

Вычитание

Просто удалите все цифры, появляющиеся одинаково в обеих частях вычитания. Расширение (преобразование bв aa) может быть необходимым

abde- ad= be= 18 в базе 10

умножение

Это немного сложнее.

Допустим, мы хотим умножить acd(13) на def(56). Сначала вы расположите acdвертикально:

a
c
d

Затем вы добавляете defпосле первого a:

a def
c
d

Теперь c на 2 позиции в алфавите позже, чем a, поэтому мы добавляем 2 позиции в алфавите defдля создания fgh. Это добавляется во второй ряд.

a def
c fgh
d

Наконец, d на 1 позицию в алфавите позже, чем c, поэтому мы добавляем 1 позицию в алфавите fghдля создания ghi. Это добавлено в третий ряд.

a def
c fgh
d ghi

Тогда вы берете сумму справа: def+ fgh+ ghi= deffgghhi= deggghhi= deghhhi= deghii= deghj(728)

Еще один пример умножения

Входные данные:

bc * de

Первый:

b
c

затем

b ef
c 

затем

b ef
c fg

Обратите внимание, что мы записали efв первой строке. Это потому, что bcначинается с b, и bявляется второй буквой в алфавите, поэтому нам нужно сместиться deна 1 букву, чтобы она стала ef.

затем

ef+fg

Выход:

eh

разделение

Это не является частью этой проблемы, потому что это может быть очень сложным.

Ваш актуальный вызов

Ваша программа или функция должна принимать входные данные в виде строки, которая выглядит следующим образом:

a + b

И вы должны вывести:

ab

Конечно, ваша программа или функция должна поддерживать число произвольной длины (до строки или входного предела вашего языка) с любым из операторов +, -или *. Еще несколько примеров:

Входные данные:

ab + bd

Выход:

acd

Входные данные:

d - ab

Выход:

ac

Входные данные:

ab * cd

Выход:

cf

Заметки:

  • Порядок букв в выходных данных не имеет значения, но вы всегда можете предположить, что порядок букв в цифрах на входе будет возрастать (от a до z).
  • Вы можете получить ввод с завершающей новой строкой и вывод с завершающей новой строкой.
  • Вы не можете принимать входные данные в виде списка ab, *и bdдля ab * bd.
  • Используется английский алфавит ( abcdefghijklmnopqrstuvwxyz)
  • Ваш вывод должен быть упрощен ( aaне разрешен, bтребуется)
  • Ввод будет упрощен ( b+ c, а не aa+ bbили aa+ aaaa)
  • Вам может потребоваться пробел до и оператор ( +, -или *), или вы можете потребовать, чтобы их не было.
  • Для каждого входа будет только один оператор.
  • Вы можете предположить, что вывод и ввод никогда не пройдут 2 ^ 27-1 ( abcdefghijklmnopqrstuvwxyz)
  • Это , поэтому выигрывает самый короткий ответ в байтах!

2
d is 2 positions later in the alphabet than cэто Райт? не должно ли это быть 1? That is added to the second row.в том же предложении, не так ли third?
— Фелипе Нарди Батиста,

1
@FelipeNardiBatista здесь используется английский алфавит, отредактированный.
— programmer5000

@ programmer5000 до сих пор, bc*de==efghно efghэто 240не144
— Фелипе Nardi Батиста

1
bc*deдолжно бытьeh
— Фелипе Нарди Батиста

@ Дада будет только один оператор на вход.
— programmer5000

Ответы:


3

Желе , 26 25 байт

i@€Øað’2*S;ḟ.Ḣ
ḲÇ€VBṚTịØa

Использует операторы Jelly ( ×а не *и _вместо -) во входной строке, как это разрешено OP .

(Требуются места вокруг операторов)

Попробуйте онлайн! или посмотрите набор тестов

Как?

i@€Øað’2*S;ḟ.Ḣ - Link 1, transform from input sub-string to value or operator: sub-string
i@€            - 1st index of, for €ach (or 0 if not found) [reversed @rguments] in:
   Øa          -      lowercase alphabet (i.e. a->1, b->2, ..., non-alpha->0)
     ð         - dyadic chain separation i.e. f(result above, substring):
      ’        - decrement (i.e a->0, b->1, ..., non-alpha->-1)
       2*      - 2 raised to that power
         S     - sum
          ;    - concatenate with the substring
           ḟ   - filter out:
            .  -     0.5 (for an operator substring the evaluated 0.5 is removed)
             Ḣ - head (i.e. the evaluation for a location, and the operator otherwise)

ḲÇ€VBṚTịØa - Main link: string                        e.g. 'ab × cd'
Ḳ          - split on spaces                               [['a','b'],['×'],['c','d']]
 Ç€        - last link (1) as a monadic function for €ach  [3,'×',12]
   V       - evaluate as Jelly code                        36
    B      - convert to binary                             [1,0,0,1,0,0]
     Ṛ     - reverse                                       [0,0,1,0,0,1]
      T    - truthy indexes                                [3,6]
       ị   - index into:
        Øa -     lowercase alphabet                        ['c','f'] (i.e. "cf", which is implicitly printed when run as a full program)

7

Mathematica, 168 байт

FixedPoint[StringReplace[x_~~x_:>FromCharacterCode[c@x+1]],Table["a",ToExpression@StringReplace[#,x:LetterCharacter..:>ToString@Tr[2^((c=ToCharacterCode)@x-97)]]]<>""]&

Мое первоначальное решение (до того, как пост был отредактирован, чтобы уточнить, что вывод должен быть упрощен) было на 64байты короче:

Table["a",ToExpression@StringReplace[#,x:LetterCharacter..:>ToString@Tr[2^(ToCharacterCode@x-97)]]]<>""

Это просто изменило это решение для работы. Вероятно, на самом деле короче использовать методы, описанные в задании, но я все равно хотел это поднять.

Объяснение:

Заменяет каждую последовательность букв на соответствующее целое число с помощью арифметики кода символа, затем преобразует результирующую строку в выражение (которое автоматически упростится до целого числа), затем создает строку aсимволов длиной, равной этому целому числу, и, наконец, заменяет смежные идентичные символы с кодом следующего символа, пока не будет достигнута фиксированная точка.


2
О, нет встроенного 1-символа? Удивительно , !
— programmer5000

7

JavaScript (ES6), 136 134 133 байта

Сохранено 1 байт благодаря Люку

s=>[...a='abcdefghijklmnopqrstuvwxyz'].filter((c,i)=>eval(s.replace(/\w+/g,s=>[...s].reduce((p,c)=>p|1<<a.search(c),0)))&1<<i).join``

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


Красиво сделано! Вы победили меня в этом ...
— programmer5000

Преобразует ли это в десятичную и обратно? Похоже, так.
— programmer5000

1
@ programmer5000 Да, действительно. Я подозреваю, что многие ответы будут. (За исключением, конечно, Mathematica, которая, вероятно, имеет встроенный для него. ^^)
— Арно

Похоже, ваш комментарий пропустил ссылку. Что имеет встроенный для этого?
— programmer5000

@ programmer5000 (На самом деле, ему не хватало ни слова.)
— Арно

5

Perl 5 , 95 байт

94 байта кода + -pфлаг.

s/\w/a x 2**(-97+ord$&)/ge;s/(.*)-\1|\+//;/\*/&&($_=$`x length$');1while s/(.)\1/chr 1+ord$1/e

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

Три шага здесь:
- s/\w/a x 2**(-97+ord$&)/ge;преобразует ввод в строку aтолько.
- s/(.*)-\1|+//;/*/&&($_=$`x length$')выполнит оператор (который очень прост для строк a): +это конкатенация, -означает удаление из первой части столько, aсколько имеется во второй части, и *означает дублирование первой части столько раз, сколько aво второй часть.
- 1while s/(.)\1/chr 1+ord$1/eскладывает последовательные одинаковые буквы в следующую букву в алфавите.


Единственный ответ, который не конвертируется в десятичную! Хорошая работа!
— programmer5000

1
@ programmer5000 Из 2 ответов я бы не назвал это впечатляющим!
— Дада

5

05AB1E , 29 байт

ð¡À¬U¦v0yvAyko+}}X.VbRvyiANèJ

Попробуйте онлайн! или как тестовый набор

объяснение

ð¡                             # split input on string
  À                            # rotate left
   ¬U¦                         # get the operator, store it in X and remove it from list
      v                        # for each side of the equation
       0                       # push 0 as an accumulator
        yv                     # for each letter in each side of the equation
          Ayk                  # get its index in the alphabet
             o                 # raise 2 to this power
              +                # add to the accumulator
               }}              # end loops
                 X.V           # apply the operator to the 2 numbers now on the stack
                    bR         # convert to binary and reverse
                      v        # for each binary digit
                       yi      # if it is true
                         ANè   # get the letter at that index in the alphabet
                            J  # join stack to a single string

5

C & x86 asm, 340 байт

Компилировать с -O0

#define G getchar()
g(){int c,a=0;for(;islower(c=G);)a+=1<<(c-97);return a;}
main(){short o[]={[43]=0x4403,[45]=0x442b,[42]=0x6cf7};
mprotect((long)&&l&~4095,4096,7);
for(;;){int c,b=0,a=g();*(short*)&&l=o[G];G;g();asm("xchg %%eax,%0":"+m"(a));
l:asm("addl %1,%%eax":"=a"(c):"m"(a));
for(;a=c>>b;b++)if(a&=1)putchar(97+b);putchar(10);}}

объяснение

Поскольку C не имеет eval(), я использовал вместо него таблицу инструкций x86. Я должен был выбрать инструкции, которые были бы одинаковой длины (или дополнены nops), и которые ожидали src и назначение тех же типов. Особую досаду вызвало то, что MUL может писать только в регистры, а однобайтовые коды операций MUL могут писать только в EAX. Кроме того, казалось, что не было инструкции SUB для записи в регистр, которая вычитала бы из памяти, а не наоборот, отсюда и XCHG.

редактировать

Поскольку это было задано в комментариях, более традиционная оценка будет выглядеть так:

#define G getchar()
#define return r
#define int i
g(){i c,a=0;for(;islower(c=G);)a+=1<<(c-97);r a;}
a(i x,i y){r x+y;}s(i x,i y){r x-y;}m(i x,i y){r x*y;}
main(){i(*o[])(i,i)={[43]=a,[45]=s,[42]=m};
for(;;){i c,b,a=g();b=G;G;g();c=o[b](a,g());
for(b=0;a=c>>b;b++)if(a&=1)putchar(97+b);putchar(10);}}

Это на самом деле немного короче, в 301 символах, по нескольким причинам: 1. Поскольку должно быть много функций, накладные расходы каждой из них можно сократить с помощью некоторых правил препроцессора. 2. Современный linux защищает от выполнения в стеке, поэтому вызов mprotect () отключает эти пожертвованные 34 байта. 3. Вызов XCHG очень неоптимален и стоит еще 30 байтов. Если бы не эти вещи, комбинация x86 выиграла бы примерно на 10-20 байтов.

Также отрезал 2 байта от обоих, улучшив вызов islower () в g.


Я не могу сказать, как это можно сравнить с более классическим подходом с точки зрения размера кода, но мне действительно нравится ваше решение. +1
— Арно

5

GNU sed + coreutils, 329 байт

Да, я понятия не имею, что на меня нашло, но, по крайней мере, теперь я знаю, что писать сценарии sed немного лучше. Обратите внимание, что для этого решения требуется eрасширение GNU sed , которое запускает команду оболочки.

/\+/{s/\+//
b S}
/-/{:E
/a+-a+/{s/(a*)(a*)-\2/\1/
b S}
s/.*/echo &|tr b-z- A-Y-/
e
s/([A-Z])/\L\1\1/g
b E}
/\*/{h
:M
/^\*/{x
s/[^\n]*//
s/\n//g
b S}
s/(.).*\*(.*)/echo \2|tr a-z \1-za-z/
e
H
g
s/.(.*)/\1/
h
s/\n.*//
b M}
:S
s/^.*$/echo &|grep -o .|sort|tr -d '\n'/
e
:L
s/(.)\1/\u\1/g
/^[a-z]*$/ q
s/.*/echo &|tr A-Z b-za/;e
b L

Я предполагаю, что вокруг операторов не будет пробелов. Из моего терминала:

$ sed -rf golf.sed <<< a+b
ab
$ sed -rf golf.sed <<< ab+bd
acd
$ sed -rf golf.sed <<< abc+b
ad
$ sed -rf golf.sed <<< d-ab
ca
$ sed -rf golf.sed <<< ab*cd
cf
$ sed -rf golf.sed <<< bc*de
eh
$ sed -rf golf.sed <<< acd*def
deghj

И для тех, кто более здравый, чем я: закомментированная версия!

#!/bin/sed -rf

/\+/ {
    s/\+//
    b simplify
}

/-/ {
    # expand pattern space; everything will now be 'a's
    :E
    /a+-a+/{
        # Remove doubled 'a's on either side of the dash. For example,
        # for input d-ab, space is now 'aaaa-aaa'; substitute this to 'a'
        s/(a*)(a*)-\2/\1/
        b simplify
    }
    # shift letters that aren't 'a' down and double them
    s/.*/echo &|tr b-z- A-Y-/;e
    s/([A-Z])/\L\1\1/g
    b E
}

/\*/ {
    # Hold space: line 1 is pattern, other lines are output
    h
    :M

    # if space starts with *, we've eaten entire arg0; sum and simplify
    /^\*/ {
        x
        s/[^\n]*//      # remove first line, which is our pattern
        s/\n//g         # remove newlines to add results together
        b simplify
    }

    # convert pattern into shifting command
    s/(.).*\*(.*)/echo \2|tr a-z \1-za-z/

    # execute it, append result to hold space
    e
    H

    # restore pattern, with leading char and all output lines removed
    g
    s/.(.*)/\1/
    h
    s/\n.*//

    b M
}

:simplify
# reorder all letters so all 'a's are before all 'b's are before all 'c's
# are before ... etc    
# See /programming/2373874
s/^.*$/echo &|grep -o .|sort|tr -d '\n'/
e

:L
# Replace repeated characters with themselves upper-cased, then translate
# upper-cased characters to what they should be.
s/(.)\1/\u\1/g
/^[a-z]*$/ q
s/.*/echo &|tr A-Z b-za/;e
b L

+1 за код sed и добро пожаловать в PPCG! Соглашение здесь, когда не решается в чистом GNU sed (или в любом другом чистом языке), заключается в добавлении к заголовку используемых системных команд, например, таких как «GNU sed + coreutils», даже если вы упоминаете вызов команды оболочки в описании. , Это сделано для того, чтобы отличать, особенно в задачах с лидерами, от чистых ответов GNU sed.
— Сешумара

Кроме того, за исключением флага 'f', необходимого каждый раз, любой другой флаг должен учитываться как 1 байт. Таким образом, ваш счет 329. Вы можете упомянуть это в описании. И в завершение вы можете подумать о добавлении ссылки на онлайн-переводчик sed, такой как TIO .
— Сешумара

Чтобы не было всего разговоров и никаких действий, вот на 43 байта короче! версия вашего кода (286 байт, включая -r), которую я нашел, играя в гольф командами. Я уверен, что это может быть даже короче.
— Сешумара

Ах, хорошо, приятно знать! Кроме того, приятно играть в гольф! Какую версию sed вы используете? Твой работает в TIO, но в GNU sed 4.4 я просто получаюsed: file golf.sed line 24: ":" lacks a label
— charliegreen

Безымянный ярлык - это хорошо известная ошибка в GNU sed, которая была исправлена ​​в версии 4.3. Но на PPCG вы можете писать программы для любого варианта и версии sed, используя ошибки в качестве функций, если это помогает в игре в гольф. Различия между версиями слишком малы, чтобы их упоминать (4.2 против 4.4), но в названии должен быть указан вариант (стандартный POSIX sed против расширенного GNU sed) с упоминанием системных программ, которые называются, если таковые имеются.
— Сешумара

4

PHP, 168

Выход по возрастанию с использованием eval

[$a,$o,$b]=explode(" ",$argn);function d($s){for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);return$n;}for(eval("\$k=d($a)$o d($b);");$i<26;)echo$k&2**$i++?chr(96+$i):"";

PHP, 185 байт

Выход по возрастанию

[$a,$o,$b]=explode(" ",$argn);function d($s){for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);return$n;}for(;$i<26;)echo(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b))&2**$i++?chr(96+$i):"";

Онлайн версия

расширенный

[$a,$o,$b]=explode(" ",$argn); # part the input into variables
function d($s){ # make decimal value
    for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);
    return$n;
}
for(;$i<26;)
echo(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b))&2**$i++?chr(96+$i):""; # Bitwise Compare and Output

PHP, 201 байт

Выход по убыванию

[$a,$o,$b]=explode(" ",$argn);function d($s){for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);return$n;}for($r=(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b));$r;$r-=2**$l)$t.=chr(97+$l=log($r,2)^0);echo$t;

Онлайн версия

расширенный

[$a,$o,$b]=explode(" ",$argn); # part the input into variables
function d($s){ # make decimal value
    for(;$i<strlen($s);)$n+=2**(ord($s[$i++])-97);
    return$n;
}
for(
$r=(bc.[mul,add,0,sub][ord($o)-42])(d($a),d($b)) # result of the operation
;$r;
$r-=2**$l) # subtract the letter value 
$t.=chr(97+$l=log($r,2)^0); # find greatest letter
echo$t; # Output

4

Python 3 , 176 167 байт

i=lambda a:str(sum(1<<ord(i)-97for i in a))
def f(a):
 a,b,c=a.split();m=eval(i(a)+b+i(c));r=''
 while m:
  t=0
  while m>=2**t*2:t+=1
  r+=chr(97+t);m-=2**t
 return r

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

  • сэкономлено 9 байт: благодаря tutleman

1
Если я не ошибаюсь, вы можете сбрить два байта, заменив m>=2**(t+1)на m>=2**t*2, и пять байтов, заменив a=a.split();m=eval(i(a[0])+a[1]+i(a[2]))что-то вроде b,c,d=a.split();m=eval(i(b)+c+i(d)).
— Тутлеман

1
Да, и еще два байта, заменив 2**(ord(i)-97)на 1<<ord(i)-97.
— Тутлеман

1
Я поражен, насколько читаемо это решение по сравнению с другими решениями.
— Оле Танге

Спасибо :). Но я думаю, что это также из-за того, что язык Python используется. Отступы увеличивают количество байтов, однако читаемые. ;)
— officialaimm

2

PHP, 130

for($d=a;$e=$argn[$i++];)$e!=' '?$d!=b?$$d+=1<<ord($e)-97:$b=$e:++$d;eval("for(;\$j++<27;)echo($a$b$c>>\$j-1)&1?chr(96+\$j):'';");

расширенная версия:

for($d=a;$e=$argn[$i++];)       // for each char in the input
  $e!=' '?                      //   if space
    $d!=b?                      //     if not the operation
      $$d+=1<<ord($e)-97:       //       add 2^(char - 'a')
      $b=$e:                    //     else save operation
    ++$d;                       //   else increase "pointer"
eval("for(;\$j++<27;)           // for each bit in the output
        echo($a$b$c>>\$j-1)&1?  //   calulate the result and check the bit
          chr(96+\$j):          //     output corrosponding char
          '';                   //     output nothing
     ");

беги с php -R <code>.


1

AWK, 201 байт

BEGIN{RS="(.)"}n=index(V="abcdefghijklmnopqrstuvwxyz",RT){s+=2^--n}index("+-*",RT){a=s RT
s=0}END{RS="\n"
"(awk '$0="a s"'<<<1)"|getline v
for(j=26;j--;)if((s=v-2^j)>=0){v=s;c=substr(V,j+1,1)c}print c}

"(awk '$0="a s"'<<<1)"|getline vэто лучший способ, который я мог придумать, чтобы сделать evaluateв AWK. Возможно, я немного «обманываю», чтобы назвать это просто AWK, так как я выполняю команду, но, по крайней мере, команда тоже AWK:)

Я уверен, что упускаю какой-то способ уменьшить количество байтов, но я точно не вижу этого.

Использование довольно стандартно, например, введите код FILEи сделайте:

awk -f FILE <<< "bc + ab"

Обратите внимание, что пробелы не требуются, и любой неоперационный / не [аз] символ будет игнорироваться. Может быть расширен для работы с числами больше, чем "abcdefghijklmnopqrstuvwxyz", изменив цикл. Для деления просто добавьте /символ в строку операции :). Кроме того, будет печатать пустую строку, если result <= 0.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.