Оцініть вираз потрійних операторів


29

Розглянемо граматику над алфавітом { 0, 1, ?, :} визначається правилом виробництва

s → 010 ?років :з ┃ 1 ?и :и

Давши рядок, згенерований з s , проаналізуйте його як вираз, де ?:є правильним асоціативним (наприклад, a?B?X:Y:c?d:e?f:gзасоби a?(B?X:Y):(c?d:(e?f:g))), та оцініть його за допомогою наступної семантики:

eval(0) = 0
eval(1) = 1
eval(0?a:b) = eval(b)
eval(1?a:b) = eval(a)

Якщо результат дорівнює 0 , виведіть деяке фіксоване значення; якщо вихід 1 , виведіть інше фіксоване значення. Вкажіть вибрані вихідні значення (наприклад, 0/ 1або False/ True) у своїй відповіді.

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

0 -> 0
1 -> 1
0?0:1 -> 1
0?1:0 -> 0
1?0:1 -> 0
1?1:0 -> 1
0?1?0:1:1 -> 1
1?0?1:1:1 -> 1
1?0:1?0:1?1:1 -> 0
1?1?1:0?1?0:0:0:0 -> 1
1?0:1?0?1:1?1:0:1?1?1:1:1?0:1 -> 0
1?1?1:0?0?1:1:0?1:0:1?1?0?0:0:1?1:0:0?1?0:1:1?0:1 -> 1
0?0?1?0?0:1:0?0:0:0?0?1:1:1?0:1:0?0?0?1:0:0?1:1:1?1?0:1:1 -> 0

Правила

  • Ви не можете використовувати вбудовані мови, які інтерпретують рядки як код у деякій мові програмування та запускають його (наприклад, JavaScript / Perl / Ruby / Python's eval).
  • При цьому ваш код насправді не повинен аналізувати, а потім оцінювати рядок введення. Ви можете скористатися будь-яким підходом, який досягає еквівалентних результатів і не порушує попереднє правило.
  • Ваша програма буде перевірена perl -le 'print eval<>'.
  • Виграє найкоротший код (у байтах).

Як щодо використання вбудованих мов, таких як eval, які інтерпретують рядки як код $ my_language після докорінної зміни рядка?
Адам

А що з вбудованими, які інтерпретують рядки як код $ some_other_language ?
Мего

@ Adám Це було б заборонено, вибачте.
Лінн

@Mego Хм, там є тривіальна шахрайська можливість, тому я розширив правило, щоб охопити всі такі вбудовані модулі.
Лінн

1
У світлі тестів Мартіна, можливо , було б простіше визначити граматику , як S → T | T ? S : S, T → 0 | 1, усуваючи необхідність говорити про асоціативності?
Пітер Тейлор

Відповіді:



17

Сітківка , 23 байти

r-1=+`0\?.:|1\?(.):.
$1

Спробуйте в Інтернеті! (Перший рядок включає тестовий набір, відокремлений виведенням ліній.)

Пояснення

Насправді це досить просто. Введення зменшується до результату за рахунок багаторазової ( +) оцінки терміналів, які містять лише літерали. Щоб переконатися, що це робиться правильно асоціативно, ми шукаємо збіги справа наліво ( r) і замінюємо лише останній збіг, який ми знайдемо ( -1=).

Сам регулярний вираз або відповідає 0\?.:і видаляє його (залишаючи лише матеріал після :) або 1\?.:.замінює його значенням після ?.


Якщо регулярний вираз починається справа, чи не слід обробляти 1матч st замість -1st?
Leaky Nun

@LeakyNun На жаль, я думаю, що я перетворюю відповідність, перш ніж застосувати ліміт.
Мартін Ендер

10

Haskell, 106 101 100 90 83 байт

Це значною мірою покладається на можливості узгодження моделей Haskell. Перш за все, ми обертаємо рядок таким чином, що ми можемо просто досягти першого появи b:a?x(що зазвичай читається як x?a:b) і замінити його на його значення. Це автоматично забезпечує правильну асоціативність . Тут ми використовуємо x:xsвізерунок. Це те, що функція fвиконує. Тоді ми в основному застосовуємо fйого до виводу знову і знову, поки у нас не залишиться єдине число (0 або 1).

Дякую @Lynn за 12 байт!

f(b:':':a:'?':x:l)|x>'0'=a:l|1>0=b:l
f(x:l)=x:f l
f x=x
until((<2).length)f.reverse

8

Brainfuck, 82 64 63 байт

+
[
  ,>>,>
  +++++++[<---<<-[------>>]<-]
  <<
  [
    ->[<++>[+]]
  ]
  +>[>>]
  <<<-
]
<.

Вихід - \xffдля 0і \x00для 1. Реалізація brainfuck повинна дозволяти переходити зліва від вихідної комірки.

Для цього використовується по суті той же підхід, що і відповідь Python xsot , але, мабуть, важче дотримуватися розгалуження порівняно з моїм початковим 82-байтним поданням:

-
[
  +
  [
    ->,,>+++++++[<--------->-]
    <[<++>[+]]
    <
  ]
  ,->,>+++++++[<[-------<]>>-->-]
  <[<]
  <
]
>>.

(Для цього рішення, вихід \xfeдля 0і \xffдля 1, і більш широкої сумісності досягається тоді , коли вхідні кінці з нового рядка.)

Якщо ви не можете зайнятися аналізом рішення xsot, ідея така: Пройдіть зліва направо. Якщо ви бачите, 1?тоді жадібно відмовтесь від нього. Якщо ви бачите, 0?тоді відкиньте все, що між цим і відповідним :. Коли ?не відображається як другий символ, припиніть циклічно та надрукуйте перший символ рядка, що залишився.

Отже, 82-байтне рішення насправді відображає цю схему досить близько. Внутрішня петля обробляється так 0?само, як і внутрішня петля xsot. Певна обережність доводиться до того, щоб увійти в основний цикл, не перевіряючи жодних вхідних символів; тобто ми хочемо перевірити, чи другий символ є ?лише один раз в кінці основного циклу, а не також на початку перед тим, як увійти в основний цикл.

63-байтне рішення, по суті, поєднує внутрішню і зовнішню петлі в одну, що, як я підозрював, було можливим з огляду на подібність між цими петлями. Макет пам'яті в основному циклі можна описати як:

[s] d c

де [x]означає поточну комірку - sпочинається як фіктивне ненульове значення, яке просто вказує на те, що ми все ще цикли, і негайно перезаписується символом введення (або 0або 1). dКлітка утримує (негативну) глибину в разі , якщо ми знаходимося в середині 0?, в іншому випадку 0. cЗбирається бути ?або :або нового рядка або EOF.

Після оновлення sі cми обробляємо цей 0?випадок, оновивши dвідповідним чином і коригуючи вказівник, інакше ми використовуємо поточне значення cяк значення dнаступної ітерації, або зупиняємося, якщо ми закінчили.


7

Python 2, 76 74 73 72 байт

a=`id`
for c in input()[::-1]:a=(c+a,a[ord(c)*7%9]+a[4:])[a>'?']
print a

Із введенням як літеральним рядком, якого слід уникати raw_.

Результатом є 0або 1слідує його <built-in function id>.


1
Ха-ха, я щойно прочитав вашу відповідь за b lang і збирався опублікувати майже однакову відповідь! Ось додаткова оптимізація:3>>int(c)
xsot

Хочете пояснити, як це працює? Виглядає по-справжньому акуратно
WorldSEnder

@WorldSEnder Я думаю, що це рішення може бути складним, але легко зрозуміти, коли ви його бачите. Він проходить через рядок назад і неодноразово обробляє найправіше умовне, як це робили і інші вирішувачі.
Мітч Шварц

Та `id`хитрість…! Молодці :)
Лінн

5

Python 2, 89 байт

s=input()
while'?'<=s[1:]:
 n=s<'1'
 while n:s=s[2:];n+=-(s[1]<'?')|1
 s=s[2:]
print s[0]

Введення приймається як літеральний рядок.


5

Grime , 34 31 байт

E=d|d\?E.E
e`\1|\1\?_.E|\0\?E._

Принти 1для правдоподібних матеріалів та 0для хибних. Спробуйте в Інтернеті! В останньому тестовому випадку, на жаль, не вистачає пам'яті на TIO.

Пояснення

Право-асоціативність по суті означає, що в a?b:c, aзавжди є 0або 1, ніколи більше, вираженням. Я просто рекурсивно визначу шаблон, що відповідає такому вірному виразу, і перевіряю вхід проти нього. Також непотрібно перевіряти, що кожне :дійсно є a :, якщо ?всі перевірені: у вході є однакова кількість ?s і :s, а якщо деякі ?неправильно класифіковані як a :, відповідні :не збігаються, і відповідність Grime двигун буде відхилятися.

E=d|d\?E.E
E=                      Define nonterminal E (for "expression") as
  d|                     a digit, OR
    d                    a digit,
     \?                  a literal ?,
       E                 a match of E,
        .                any character (will match a :), and
         E               another match of E.
e`\1|\1\?_.E|\0\?E._
e`                      Match entire input against this pattern (truthy expression):
  \1|                    a literal 1, OR
     \1\?                a literal 1?,
         _               a recursive match of truthy expression,
          .              any character (will match a :), and
           E|            any expression, OR
             \0\?E._     the same, but with 0 in front, and _ and E swapped.

5

Хаскелл, 79 71 70 62 60 56 байт

Редагувати: Дякую @Zgarb за 3 байти та @nimi за 4 байти!

e(x:'?':r)|a:_:s<-e r=last$e s:[a:tail(e s)|x>'0']
e x=x

Це рекурсивний підхід, який дещо зловживає правилом випуску "деяке фіксоване значення" . Редагувати: Позбавлення кортезів не лише економить 8 байтів, але й дає кращий вихід: "0"або "1".

Безгольова версія:

eval (x:'?':r1) = if x=='1' then (a, r3) else (b, r3)
    where (a,':':r2) = eval r1
          (b, r3)    = eval r2
eval (x:r) = (x,r)

Як це працює? Функція перетинає неявне дерево виразів
eval

eval 1?0?0:1:0?1:0 -> eval 1?          :
                             eval 0?0:1 eval 0?1:0

і повертає кортеж форми (result, rest).
Перший зразок (x:'?':r1)відповідає « xдо» '1'та « r1до» "0?0:1:0?1:0". Рекурсивно застосовується evalдля r1оцінки суб-виразу 0?0:1та повернення (0,":0?1:0"). Відповідність цього випуску (a,':':r2)досягає a=0та r2=0?1:0. Ця підформула також рекурсивно оцінюється так, що b='0'і r3="". Перевірте, xє '1'чи '0'й повернення або (a, r3)або (b, r3).


1
Гарний підхід! Буде x>'0'працювати замість x=='1'?
Згарб

Дякую, я не думав про це, маючи справу з символами.
Лайконі

1
Я думаю , ви також можете замінити ':'на _.
Згарб

Так, тоді код працює навіть для довільних роздільників, а не просто :. Знову дякую!
Лайконі

1
Приємно! Ви можете замінити if .. then .. elseз last$e s:[a:tail(e s)|x>'0'].
німі

3

JavaScript (ES6), 53 байти

f=s=>s[1]?f(s.replace(/0\?.:|1\?(.):.(?!\?)/,"$1")):s

Повернення 0або 1для дійсного введення; висить для недійсного введення. Пояснення: оскільки повернення рядка незручне в JavaScript, моя перша 71-байтна спроба спрацювала, використовуючи негативну пошукову коду, для ?якої інакше буде порушено асоціативність:

f=s=>s[1]?f(s.replace(/(.)\?(.):(.)(?!\?)/,(_,a,b,c)=>+a?b:c)):s

Оскільки це було дещо довго, я замислювався над тим, чи можу я покращити питання, включивши прийняття рішень у регулярне вираження. Як виявилося, це не було негайним успіхом, оскільки він також займав 71 байт:

f=s=>s[1]?f(s.replace(/0\?.:(.)(?!\?)|1\?(.):.(?!\?)/,"$1$2")):s

Тоді мені спало на думку , що 0?0:і 0?1:не завжди НЕ-OPS, не звертаючи уваги на асоціативності. Це врятувало мене майже на 25%.


Блок вашого коду вгорі відсутній f=. Я не перевіряв, враховує чи ваш байт чи ні.
Патрік Робертс

@PatrickRoberts Я це роблю назавжди, тому що копіюю з журналу, який показує лише результат завдання (що, звичайно, достатньо для нерекурсивних функцій).
Ніл

@Neil ви можете скопіювати з введення журналу замість виводу
лише для ASCII

@MarsUltor Вхід журналу включає в себе підказку, яку я повинен пам'ятати, щоб виключити. Це незручний додатковий крок для нерекурсивних функцій, тому я копіюю з виводу за замовчуванням.
Ніл

3

Perl, 32 + 1 ( -pпрапор) = 33 байти

Повна заслуга @Mitch Swartch , оскільки його рішення було на 14 байт коротше мого!
Дякую також @Neil, який запропонував рішення на 1 байт довше, ніж Mitch.

s/.*\K(0\?..|1\?(.)..)/\2/&&redo

Потрібно -pпрапор, а також -M5.010або -Eбігти. Наприклад :

perl -pE 's/.*\K(0\?..|1\?(.)..)/\2/&&redo' <<< "0
0?0:1
0?1?0:1:1
1?0:1?0?1:1?1:0:1?1?1:1:1?0:1
0?0?1?0?0:1:0?0:0:0?0?1:1:1?0:1:0?0?0?1:0:0?1:1:1?1?0:1:1"

Пояснення : В основному це зводить блоки a?b:c(починаючи з кінця, щоб бути впевненим, що не ?випливає) на bабо cзалежно від істинності a, знову і знову, поки рядок не містить 1або 0.


Чи -не враховується ваш рахунок? Грн. Цікаво ... Гарна відповідь!
МерМонти

@MayorMonty Для 1-лайнера ви можете викликати його в командному рядку, використовуючи, perl -e '<code>'таким чином, додавши pлише 1 байт perl -pe '<code>'.
Ніл

@Neil Ahh, це має сенс
мер міста

Насправді вам не потрібно обертати рядок, ви можете просто заперечити loakahead для a ?, я зміг скоротити це до 34 байт таким чином.
Ніл

Ось 32 + 1:s/.*\K(1\?(.)..|0\?..)/\2/&&redo
Мітч Шварц

2

Python 3, 93 69 байт

def f(s):z=s.pop;r=z(0);return s and':'<z(0)and(f(s),f(s))[r<'1']or r

Введення - це рядок як список символів, вихід - "0"або"1"

>>>f(list("0?0:1"))
<<<"1"

Безгольова версія:

def parse(s):
    predicate = s.pop(0)
    if s and s.pop(0) == '?':
        left, right = parse(s), parse(s)
        if predicate == '0':
            return right
        return left
    return predicate

Ще одна спроба, але зі значно більшою кількістю байтів:

i=input()[::-1]
a=[i[0]]
for o,z in zip(i[1::2],i[2::2]):a+=[z]if o<'?' else[[a.pop(),a.pop()][z>'0']]
print(a[0])

Ваша відповідь може бути функцією - ви можете видалити другий рядок.
Лінн

Це явно не перевірено, оскільки воно не проходить тестових випадків, а версія, що не має волі, дає помилку під час виконання. Ваша основна ідея, проте, добре. З деякими корективами я отримую 68 у Python 2 та 69 у Python 3.
Mitch Schwartz

1
Ну, я думаю, для мене є більш сенсом дати вам відповідь, ніж редагувати її в моєму власному (оскільки я не замислювався над таким підходом до того, як побачив вашу відповідь) або сидіти навколо, чекаючи, поки ваша відповідь буде баггі. Ось 68 я, про які я згадував def f(s):x=s.pop(0);return[]<s<s.pop(0)>'>'and(f(s),f(s))[x<'1']or x, а для Python 3 з невеликою відстані редагування до вашої def f(s):z=s.pop;r=z(0);return s and':'<z(0)and(f(s),f(s))[r<'1']or r.
Мітч Шварц

Дякую @MitchSchwartz, досить сильно розберемо справа, а не ліворуч,
gotcha

1
В іншому випадку ліворуч замість правої, ~~~
WorldSEnder

1

СЕД, 75 74 68 (40 + 1 за -р) 41

:
s,(.*)1\?(.):.,\1\2,
s,(.*)0\?.:,\1,
t

Ви, ймовірно, можете скоротити це за допомогою трюку @ MitchSchwartz у своєму коментарі , хоча вам, можливо, доведеться використовувати (.*)та додавати додатковий термін заміни.
Ніл

@Neil, ти можеш мати рацію, але я не можу зрозуміти, як змусити це працювати.
Райлі

Я написав це у чаті, оскільки форматування в коментарі може бути заплутаним: chat.stackexchange.com/transcript/message/31709640#31709640
Mitch Schwartz

@MitchSchwartz Heh, чисті етикетки працюють? Але я думаю, що ти мав на увазі \3замість цього \2. Крім того, ви можете приєднатися до ліній, ;щоб отримати :;s/(.*)(1\?(.):.|0\?.:)/\1\3/;t.
Ніл

@Neil У мене \3так було, це означає, що я випадково скопіював попередню версію. Я знаю про крапки з комою. Але юк, чому б ти хотів використовувати крапки з комою.
Мітч Шварц

0

Утиліти Bash + GNU, 42

rev|sed -r ':
s/(.):.\?0|.:(.)\?1/\1\2/
t'

Подібна ідея до більшості інших відповідей, що відповідають шаблону.

Ідеон .


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