Простая система счисления


19

Позвольте мне рассказать вам о простой системе счисления. (который я сделал только для этого вызова)

Эта система содержит функции (), [], {}и <>.

1. ()

Когда ()не приводятся аргументы, он оценивается как 0.

Когда ()дается один или несколько аргументов, он оценивается как сумма аргументов.

2. []

Когда []не приводятся аргументы, он оценивается как -1.

Когда []дается один или несколько аргументов, он оценивается как первый аргумент минус сумма других аргументов.

3. {}

Когда {}не приводятся аргументы, он оценивается как 1.

Когда {}дается один или несколько аргументов, он оценивается как произведение этих аргументов.

4. <>

Когда <>не приводятся аргументы, он оценивается как 1.

Когда <>дается один или несколько аргументов, он вычисляется как целое число первого аргумента, деленное на произведение других аргументов.

Твое задание

Если в этой простой системе счисления задана строка, которая содержит действительное число (это означает, что скобки сбалансированы, без деления на 0 и т. Д.), Выведите ее значение.

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

() -> 0
(()()) -> 0
([][]) -> -2
({}<>) -> 2
({}[]) -> 0
[] -> -1
[[][]] -> 0
[()<>] -> -1
{()} -> 0
{([]<>)} -> 0

Помните, что это , поэтому выигрывает код с наименьшим количеством байтов.


13
У меня есть отличное имя для этого, которое я просто придумала и больше нигде не получила: Brain-flake!
ETHproductions

4
@ETHproductions нет
Оливер Ни


2
Подразделение с плавающей запятой или целочисленное деление?
xnor

1
@Oliver Как должно работать целочисленное деление, когда один или оба операнда отрицательны? Каковы ожидаемые результаты 4 для 5/3, 5/-3, -5/3и -5/-3?
Мартин Эндер

Ответы:


2

Дьялог АПЛ , 94 байта

o←{(⊂(1⊃⍵),⍺⍺⊃⍵),2↓⍵}⋄u←{(⊃⍵,⍺⍺1)⍺⍺⍵⍵/1↓⍵}⋄⍎⍕'+/o' '-u+o' '×/o' '÷u×o' '(⊂⍬),'[')]}>'⍳⌽⍞],'⊂⍬'

использования ⎕IO←0

заменяет )]}>на вызов функции, который берет стек, применяет операцию к верхнему кадру, удаляет ее и добавляет результат к следующему кадру ( oдля этого используется монадический оператор ; двоичный оператор uобрабатывает более сложные случаи -и ÷)

заменяется ([{<кодом, который добавляет кадр в стек ( (⊂⍬),)

выполняет результирующее выражение (обратное, чтобы соответствовать порядку выполнения APL) с начальным стеком одного пустого кадра ( ⊂⍬)


5

Haskell, 357 306 277 251 228 224 188 185 180 байт

Парсер на основе токенов с явным стеком. (%)принимает стек токена и символ и нажимает (код операции, номер по умолчанию) или (0, число) для ({[<, или выдает самые верхние числа и один код операции и нажимает ответ для )}]>. Коды операций кодируются путем взлома перечисления ascii.

Престижность @ChristianSievers за его отличный ответ , из которого я позаимствовал некоторые идеи.

Один лайнер!

s%c|elem c"([<{",g<-div(fromEnum c)25=(g,[0,0,1,-1,1]!!g):s|(a,(o,n):b)<-span((==0).fst)s=(0,[foldr1(flip$[(+),quot,(-),(*)]!!(o-1))$snd<$>a,n]!!(0^length a)):b
snd.head.foldl(%)[]

Теперь с меньшей обработкой ошибок! Использование:

*Main> map (snd.head.foldl(%)[]) ["()","(()())","([][])","({}<>)","({}[])","[]","[[][]]","[()<>]","{()}","{([]<>)}"]
[0,0,-2,2,0,-1,0,-1,0,0]

Спасибо @ChristianSievers за сохранение 14 + 3 байтов!

Спасибо @Zgarb за сохранение + 4 байта!


1
Как насчет (0,[0,0,1,-1,1]!!o):sпятой строки?
Кристиан Сиверс

@ChristianSievers конечно!
Ангс

Переключите определения !, так что вы можете сделать (s:_)!_=d sкак второй случай. Кроме того, я думаю, что вы могли бы связать x<-p$d<$>init a,y<-d$last aв последнем случае %.
Згарб

@ Zgarb спасибо! Я нашел способ унифицировать оценку еще больше.
Ангс

1
На третьей строке %вы можете упасть вокруг скобки _:bи g c.
Згарб

3

Python 2, 292 265 248 235 223 206 204 байта

r=reduce
s=input()
for n in')]}>':s=s.replace(n,'),')
for a in'(*x:sum(x)','[a=-1,*x:a-sum(x)','{*x:r(int.__mul__,x,1)','<a=1,*x:r(int.__div__,x,a)':s=s.replace(a[0],'(lambda %s)('%a[1:])
print eval(s)[0]

Заменяет все скобки на лямбду, которая делает то же, что и скобка, а затем оценивает полученный код Python. Требуется его ввод в кавычках, вроде '[<><>([]{})]'.

Эта программа сохраняет тип скобки в качестве первого символа в каждой строке в for, и все после ключевого слова lambdaв качестве остальных. Затем он использует первый символ для замены; остальное объединяется в лямбда-лайк (lambda*x:sum(x))().

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


3

PEG.js (ES6) , 132 байта

x=a:[([{<]b:x*[)\]}>]{var x='([<'.indexOf(a)
b.length^1||b.push(0)
return~~eval(b.length?b.join(('+-/'[x]||'*')+' '):~-('10'[x]||2))}

Должно быть исправлено сейчас.

объяснение

Более читабельно:

x=a:[([{<]
  b:x*
  [)\]}>]
{
  var x='([<'.indexOf(a)
  b.length^1||b.push(0)
  return ~~eval(
    b.length?
      b.join(('+-/'[x]||'*')+' ')
    :~-('10'[x]||2))
  )
}

PEG.js - это расширенная версия Javascript, специально созданная для анализа. Это очень строго, поэтому я должен был использовать var. Кроме того, кажется, есть ошибка с скобками внутри строк, что значительно увеличило объем кода.

Для начала мы определим правило x, соответствующее любой скобке, aкоторая может содержать или не содержать несколько выражений, соответствующих правилу x.

Для каждого соответствия правилу xмы помещаем 0 в массив внутреннего соответствия, bесли bдлина равна 1.

Если bдлина> 0, то мы находим индекс aв ([<и получаем символ от +-/использования этого индекса. Если результат не определен (имеется в виду, что aбыл {), то мы превращаем результат в *. Наконец, мы выбираем место и присоединяемся bк результату.

Если bдлина = 0, то мы находим индекс aв ([<и получаем символ от 10использования этого индекса. Если результат не определен ( это означает , что aбыло {или <), то мы переходим результат в 2. Наконец, мы просто декремент.

В конце мы можем просто оценить выражение и получить результат.


3

Perl, 113 + 2 = 115 байт

Выполнить с -lp(штраф 2 байта).

/\W/,eval"sub $`\{\$#_?(shift)$&&$'1}"for qw'a+a:1- b-a:- c*c: d/c:';y/([{</a-d/;s/\W/0),/g;s/\pL\K/(/g;$_=eval

Более читабельный (примечание: эта «более читаемая версия» на самом деле не будет работать, потому что я размещаю комментарии там, где они синтаксически не разрешены):

              # -p option: read a line of input into $_ at program start
              # -l option: remove the final newline whenever reading
do {          # for each element of a list, given later:
  /\W/;       # place an initial identifier in $`, the next character in
              # $&, and the rest of the element in $'
  eval qq{    # then evaluate the following template, with substitutions:
    sub $` {  # define a subroutine named $`, that does this:
      \$#_ ?  # if there is more than one argument                   
      (shift) # then return the first argument $&-ed with
      $& &$'  # the result of a recursive call with the tail of the arguments
              # else (the "else" is a colon taken from $', not the template)
      1       # return (the remainder of $' applied to) 1
    }
  }
} for qw'     # specify the list by splitting the following on whitespace:        
  a+a:1-      # a(head,tail) = len(tail>1) ? head+a(tail) : 1-1
  b-a:-       # b(head,tail) = len(tail>1) ? head-a(tail) : -1
  c*c:        # c(head,tail) = len(tail>1) ? head*c(tail) : 1
  d/c:        # d(head,tail) = len(tail>1) ? head/c(tail) : 1
';
y/([{</a-d/;  # replace ( [ { < with a b c d in $_
s/\W/0),/g;   # replace whitespace, punctuation in $_ with the string "0),"
s/\pL\K/(/g;  # place a ( after (\K) each letter (\pL) in $_
$_=eval       # evaluate $_ as a Perl program, storing the result back in $_
              # -p option: print $_ to the user at program end
              # -l option: output a newline whenever printing

Основная идея заключается в том, что мы преобразуем входные данные, например, [()<>]в программу Perl, с b(a(0),d(0),0),помощью обработки текста; Perl просто в порядке с запятой. Ранее мы определили функции a, b, c, dчтобы иметь такое же воздействие , как (), [], {}, <>конструкции из языка мы реализующий; каждый из них игнорирует свой последний аргумент (0 в конце), который включен, чтобы гарантировать, что все входные данные анализируются правильно, и работать с использованием реализации, обычно наблюдаемой в функциональном программировании, где голова и хвост обрабатываются отдельно. Потому что b(e,f,g,0)означает e-f-g, т.е. обрабатывает свой первый аргумент специально, тогда как aобрабатывает его аргументы симметрично ( a(e,f,g,0)означает e+f+g), мы реализуемaрекурсивно и bчерез вызов a. cи dиметь похожие отношения. Все четыре из этих функций очень похожи, поэтому мы генерируем их во время выполнения, а не реализуем их отдельно; мы храним шаблон, который применяется ко всем четырем функциям в строке, а затем генерируем функции, подставляя символы в шаблон.

Поскольку Perl /выполняет деление с плавающей точкой, реализованное {}тоже. Я предполагаю, что либо это не является проблемой само по себе, либо -Minteger(выбор варианта языка, где все арифметические операции являются целочисленными операциями) является бесплатным, потому что в противном случае мне пришлось бы тратить дополнительные байты на написание целочисленного деления на Perl, которая, кажется, не в чем суть проблемы. (Я думаю , что вам придется потратить четыре байта изменения (shift)к int+(shift);. Я не проверял это)



2

PHP, 315 300 285 258 250 244 байта

for($s=$argv[1];$r=!$r;)foreach(["(+)1","[-]0","{*}2","</>2]as$p)if(preg_match("#$e$p[0]([-_\d]*)$e$p[2]#",$s,$m)){if(""==$v=strtok($m[1],_))$v=$p[3]-1;while(""<$n=strtok(_))eval("\$v$p[1]=$n;");$s=strtr($s,[$m[$r=0]=>_.$v]);}echo substr($s,1);

заменяет подвыражения символом подчеркивания + значение; разрывы цикла, когда итерация не заменяет.

19 лет с тех пор, как я впервые познакомился с C, 17 лет работал с PHP;
это первый раз, когда strtokимеет смысл ... помогает сэкономить 24 байта!

сломать

for($s=$argv[1];    // take input from argument
    $r=!$r;)        // toggle $r; loop until no replacement has taken place
    foreach(["(+)1","[-]0","{*}2","</>2]as$p) // loop through operations
        if(preg_match("#$e$p[0]([-_\d]*)$e$p[2]#",$s,$m))   // find a match
        {
            if(""==$v=strtok($m[1],_))  // init $v with first token from sub-match
                $v=$p[3]-1;             // if no token, init with default value
            while(""<$n=strtok(_))      // loop through tokens
                eval("\$v$p[1]=$n;");       // operate
            $s=strtr($s,[$m[$r=0]=>_.$v]);  // reset $r; replace match with underscore+value
        }
echo substr($s,1);  // print result

@ Оливер здесь никого не бьет; но спасибо за веселье!
Титус

2

ES6 (Javascript), 250, 171, 154, 149147 байт

Чистая версия Javascript.

«Метапрограммирование» (как и большинство других ответов здесь) преобразует текст входной программы в соответствующую программу Javascript, применяя к ней ряд прямых подстановок текста (т.е. сохраняя структуру программы как есть).

Может быть, можно играть в гольф дальше.

ОБНОВЛЕНИЕ (v2.1)

  • Минус два байта (убрана скобка в троичном выражении)
  • Отыграйте еще 5 байтов, используя переменную для извлечения результата и избавившись от лишних "[]"

ОБНОВЛЕНИЕ (v2)

Просто понял, что ожидающие запятые в массивах ES полностью действительны, поэтому весь код нормализации запятой можно удалить. Также последовал отличный совет @Titus по оптимизации поиска по алфавиту.

ОБНОВЛЕНИЕ (v1)

Удален дубликат "заменить" псевдоним.

ОБНОВЛЕНИЕ (v1)

  • Используйте лучший алфавит: () => 1+ [] => 0 {} => 2 * <> => 2 / (каждый символ может быть непосредственно повторно использован в качестве значения или оператора)

  • Замените, чтобы уменьшить () с заменой () (сопоставление алфавита)

  • Объединение постоянной вставки, обработки открытых и закрывающих скобок в один шаг

Гольф (v2.1)

s=>eval("o="+s.replace(/./g,r=>"2+1-3*3/"["()[]{}<>".indexOf(r)]).replace(/\d\D?|\D/g,r=>r[1]?r[0]-2+",":r*1?'([':`].reduce((r,a)=>r${r}a)),`)+"o

Гольф (v1)

(s,A="(2)+[1]-{3}*<3>/")=>eval(s[R="replace"](/./g,r=>A[A.indexOf(r)+1])[R](/\d\D?|\D/g,r=>r[1]?r[0]-2+",":(r[0]*1?'([':`].reduce((r,a)=>r${r}a)),`))[R](/,(\])|,$/g,"$1"))    

Гольф (v0)

([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')[R](/[aceg]/g,"([")[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)[R](/,(\])|,$/g,"$1"))

Объяснил (v0)

//BEGIN 

//s - input text, A - alphabet, R - "String.replace()" alias
E=([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(

//Replace input alphabet by a more friendly one, to avoid too much escaping and quoting
// () - ab, [] -cd, {} - ef, <> - gh
s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')

//Replace no-arg invocations with a corresponding constant value
// () => 0, [] => -1, {} => 1, <> => 1      
[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')

//Replace opening brackets with "(["
[R](/[aceg]/g,"([")

//Replace closing brackets with "].reduce(...)),"
//An arithmetic operation to apply (+-*/) is chosen based on the bracket type 
//and is substituted into the template 
[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)

//Strip excessive commas
[R](/,(\])|,$/g,"$1")
);

//END: eval() the result


Example:
E("{([]<>()<>{})(<><>)}")
=> eval("([([-1,1,0,1,1].reduce((r,a)=>r+a)),([1,1].reduce((r,a)=>r+a))].reduce((r,a)=>r*a))")
=> 4

Тестовое задание

E=([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')[R](/[aceg]/g,"([")[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)[R](/,(\])|,$/g,"$1"))

T=(s,a)=>{
    console.log(s,r=E(s),r==a?"OK":"NOT OK");
}

T("()",0)
T("(()())",0) 
T("([][])",-2)
T("({}<>)",2) 
T("({}[])",0) 
T("[]",-1)
T("[[][]]",0) 
T("[()<>]",-1) 
T("{()}",0) 
T("{([]<>)}",0)

Тестовый вывод

() 0 OK
(()()) 0 OK
([][]) -2 OK
({}<>) 2 OK
({}[]) 0 OK
[] -1 OK
[[][]] 0 OK
[()<>] -1 OK
{()} 0 OK
{([]<>)} 0 OK

1
Может ли ваша версия v0 идти с s.reduce((r,c)=>r+="abcdefgh"["()[]{}<>".indexOf(c)],'')(-5)? если это так, вы можете запомнить indexOfпеременную и взять оператор из третьего строкового литерала.
Титус

2

Haskell, 184 179 172 161 160 159 151 148 145 байтов

s%(c:i)|elem c")}]>"=([1?(*),sum,1?quot,(-1)?(-)]!!mod(fromEnum c)5$s,i)|(r,j)<-[]%i=(s++[r])%j
[v]%e=(v,e)
(v?_)[]=v
(_?o)s=foldl1 o s
fst.([]%)

Рекурсивный спуск, поток ввода, потому что Haskell. Как обычно, последняя строка не является определением, но описывает функцию, которая решает проблему. Чтобы проверить, поместите строки, кроме последней, в файл, загрузите его и сделайте что-то вроде этого:

*Main> fst.([]%) $ "{([][][])([][])}"
6

Спасибо @Zgarb за вдохновение и множество подробных советов, а также @Angs за вдохновение от его решения и дальнейших советов.

Не было указано, как деление должно вести себя с отрицательными целыми числами. В любом случае, повторное использование divкажется неправильным, поскольку это не то же самое, что использование divодин раз с произведением оставшихся значений. Теперь, используя quot, я получаю те же результаты для <{}([][])[]>и <{}{([][])[]}>.

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


Я думаю, что вы можете сэкономить пару байтов, определяя (!)=(,)и используя !вместо явных кортежей.
Згарб

Если определить m xи , d xкак 1#xи 0#xвы можете объединить дела m[x]и d[x]в одну, что я думаю , что экономит некоторые байты тоже.
Згарб

@ Zgarb Спасибо! Я чуть не пропустил последнюю пару, без которой !трюк не окупается. Ваше второе предложение - зло, вот мой почти читаемый код ... Умно!
Кристиан Сиверс

Хех, я только что понял, что определение s%(c:i)=(s?c,i)и s?')'=sum sт. Д. Будет намного короче, так как вы можете избавиться от повторяющихся iс. ..Не ждите, это, вероятно, не сработает из-за s%(_:i)дела.
Згарб

1
Потерять галочки elemи div, что должно сэкономить еще несколько байтов.
Згарб

1

JavaScript (ES6), нет eval, 156 байт

f=s=>s==(s=s.replace(/(.) ?([- \d]*)[\]})>]/,(_,c,s)=>` `+(s?s.split` `.reduce((l,r)=>c<`<`?l- -r:c<`[`?l/r|0:c<`{`?l-r:l*r):c==`[`?-1:c==`(`?0:1)))?+s:f(s)

Объяснение: Регулярное выражение находит первую необработанную закрывающую скобку и сопоставляет (предположительно) соответствующую открывающую скобку и любые аргументы между ними. Аргументы разделяются и уменьшаются в соответствии с операцией (к сожалению, '(' и '[' не являются оптимальной парой для +и -), или, если аргументов нет, то вычисляется соответствующее значение (опять же, сопоставление символов со значениями является неоптимальным). с моей точки зрения.) Затем результат заменяется начальным пробелом, чтобы отделить его от других результатов. Затем функция вызывает себя рекурсивно до тех пор, пока не останется никаких изменений, и в этом случае она возвращает полученное значение. Пример:

[()<>]
[ 0<>]
[ 0 1]
 -1

f ("([] [])") => 0 (вместо 2)
zeppelin

Некоторые другие тесты также терпят неудачу (вы можете попробовать тестовый код в моем ответе ), вероятно, из-за: f ("[]") => 0, так как "[]" является частью каждого неудачного теста.
Цеппелин

@zeppelin Ой, это было из-за плохой игры в гольф. Я вернулся к предыдущей версии, но, к сожалению, это стоит мне пару байтов.
Нил
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.