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


19

Дозвольте розповісти про просту систему числення. (яку я склав саме для цього виклику)

Ця система містить функції (), [], {}і <>.

1. ()

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

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

2. []

Коли []не дано аргументів, вона оцінюється -1.

Коли []йому надано один або декілька аргументів, він оцінює перший аргумент за вирахуванням суми інших аргументів.

3. {}

Коли {}не дано аргументів, вона оцінюється 1.

Коли {}йому надано один або кілька аргументів, він оцінює добуток цих аргументів.

4. <>

Коли <>не дано аргументів, вона оцінюється 1.

Коли <>дається один або більше аргументів, він оцінює перше ціле число аргументу, поділене на добуток інших аргументів.

Ваше завдання

З огляду на рядок, який містить дійсне число (це означає, що дужки врівноважені, без поділу на 0s тощо) у цій простій системі числення надрукуйте його значення.

Тестові справи

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

Пам'ятайте, що це , тому виграє код з найменшими байтами.


13
У мене є чудове ім’я цього, яке я зовсім щойно склав і нікуди не дістався: Мозок-луска!
ETHproductions

4
@ETHproductions ні
Олівер Ні


2
Чи поділ поплавкового поділу чи ціле ділення?
xnor

1
@Oliver Як повинен діяти цілочисельний поділ, коли один або обидва операнди є негативними? Які очікувані результати 4 для 5/3, 5/-3, -5/3і -5/-3?
Мартін Ендер

Відповіді:


2

Діалог APL , 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

Пітон 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's length = 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),за допомогою обробки тексту; Перл просто чудовий із комою. Раніше ми визначили функції 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

@Oliver нікого тут не б’є; але дякую за задоволення!
Тит

2

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

Чиста версія 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
Втратіть backtikks 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)

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

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

f ("([] [])") => 0 (замість 2)
цепелін

Деякі інші тести також не спрацьовують (ви можете дати тестовий код у моїй відповіді спробувати), ймовірно, через: f ("[]") => 0, оскільки "[]" є частиною кожного провального тесту.
zeppelin

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