Розв’яжіть позначення задачі з математики


14

Уявіть, у мене є нескінченна кількість домашніх завдань (!), Кожна з яких отримала ціле число.

Позначення проблеми математики - це позначення для опису підмножини проблеми за допомогою специфікаторів проблеми.

Вираз MPN може складатися з кількох речей:

  • Єдине значення. Це являє собою набір , що містить номер: 99 -> {99}.
  • Простий діапазон. Це являє собою набір , що містить всі цифри від початку до кінця діапазону: 10~13 -> {10, 11, 12, 13}. Якщо ліва або права сторона відсутня, то вони вважаються відповідно -бесконечністю або нескінченністю відповідно ~10 -> {x|x ≤ 10}; ~ -> ℤ.
  • Вираз MPN, за яким слідує «пропустити» та інший вираз MPN. Це являє собою різницю двох множин: 10~20 skip 12~14 -> {10, 11, 15, 16, 17, 18, 19, 20}.
  • Два вирази MPN, розділені комою. Це являє собою об'єднання двох множин: 1,8~9,15~17 -> {1,8,9,15,16,17}.

Оператор "пропустити" прив'язується більш жорстко, ніж оператор комами, тому 16,110~112 skip 16 -> {16,110,111,112}(16 не входить у набір {110,111,112}, тому виключення 16 не має значення.)

Ви також можете вводити вирази в дужки для розрізнення: 1~9 skip (2~8 skip (3~7 skip (4~6 skip 5))) -> {1,3,5,7,9}

Це граматика:

<expr>  ::= "(" <expr> ")"
         || <number>
         || [<number>] "~" [<number>]
         || <expr> "skip" <expr>
         || <expr> "," <expr>

Ваше завдання - написати програму, яка займає два входи:

  • Вираз MPN
  • Номер

і виводить деяке значення truthy або falsey залежно від того, чи є ця проблема у наборі, описаному виразом MPN.

Технічні умови

  • Можна припустити, що перший вхід є добре сформованим виразом MPN (тобто, що він відповідає вищевказаній граматиці)
  • Числа у виразі MPN завжди є цілими числами. Вони можуть бути негативними або нульовими, але ніколи не матимуть дробової частини.
  • Це , тому виграє найкоротше дійсне подання (вимірюється в байтах).
  • Ви можете використовувати різні символи для ~та ,, якщо хочете.

Випробування

10~20             14 -> True
10~20             20 -> True
10~20 skip 14~18  17 -> False
~ skip 6          8  -> True
16,17 skip 16     16 -> True
(16,17) skip 16   16 -> False
~10,5~            8  -> True
~10,5~            4  -> True
6 skip 6,~        6  -> True

Чи можна використовувати інші символи для представлення операторів? Для прикладу, використовуючи # замість ~
rahnema1

1
@ rahnema1 For ~ і ,, але не для skip.
Esolanging Fruit

3
Чому ~ 10,5 ~ невірно для 4? Тому що це об'єднання -бесконечності до 10 і 5 до нескінченності, перше з яких включає 4
ev3commander

@ ev3commander Відредаговано. Я завжди псую свої тестові справи. Б'юсь об заклад, що мої виклики будуть зрозумілішими, якби я не додав їх: P
Esolanging Fruit

1
@ Challenger5 Я додав тестовий випадок, 6 skip 6,~який, я вважаю, я правильно інтерпретував. Інші 2 відповіді поки що не задовольняють її (знову ж таки, припускаючи, що я правильно інтерпретую). Якщо я неправильно зрозумів, будь ласка, виправте його та уточніть, але, з мого розуміння, воно повинно відповідати будь-якому (це об'єднання множини, яке нічого не відповідає, з набором, який відповідає всім). Це такі випадки, про які я говорив раніше, і, на мою думку, вони могли б допомогти багато під час тестування наших рішень.
британіст

Відповіді:


3

PowerShell , 189 195 байт

param($m,$q)('$m',"'(\d*)~(\d*)','($q-ge(`$1)-and$q-le(`$2))'","'\(\)',$q","'((?<=,|skip )\d+|\d+(?=,| skip))','($q-eq`$1)'","'skip','-and!'"-join'-replace'|iex|% Sp* ','|%{"($_)"})-join'-or'|iex

Пояснення

Я рано зрозумів, що нескінченності роблять це неможливим для генерування масивів і тестування значень.

Я роздивився діапазони, але в. Ні, вони не мають необхідного діапазону ( довжина діапазону обмежена підписаним (32-бітовим) цілим числом, так що навіть якщо було б нормально обмежити діапазон підписаним 32-бітовим int , Я б не впорався з усіма діапазонами.

Тож я почав просто думати про це з точки зору початку та кінця, і, врешті-решт, ряд булевих тестів і почав створювати купу регексу, замінюючи, щоб перетворити MPN в булевий вираз, який PowerShell розуміє.

Я в основному розбив це на кілька правил:

  • Спершу з діапазонами було легше працювати, оскільки вони не можуть бути виразами на будь-якому кінці, але відкритість була невдовзі реалізацією. Приміщення - 2~8це як би сказати n >=2 && n <=8, але коли один із кінців відсутній, залиште &&сторону та пропущену сторону. Коли обоє відсутні, я спочатку збирався замінити його$true . Що я в кінцевому підсумку робив, це насправді не було тестування на відсутніх сторонах взагалі, але я переконався, що обертаю кожне число ().
  • а потім зробіть пряму заміну, яка замінює порожні дужки ()на вхідне значення. Так, у випадку MPN, як ~8із вхідним значенням55 , перша заміна буде генерувати (55-ge()-and55-le(8)), а потім приходить друга заміна, щоб зробити його(55-ge55-and55-le(8)) , по суті анулюючи цю частину діапазону.
  • Далі мені довелося розібратися з окремими номерами в MPN, але я повинен був подбати про те, щоб не возитися з тими, які я вставив раніше. Це дійсно просто числа в комах, списках, , та індивідуальні числа до або після а skip, тому я використовував нещасні довгі lookarounds.
  • skipв основному те саме, що -and -notя роблю пряму заміну skipна -and!(використовуючи! як скорочення для-not ).
  • Наступною хитрою річчю був низький порядок черговості в косах, що залишилися. Я спочатку просто замінив їх, -orале він не враховував наступних виразів, тому 16,17 skip 16генерував код, як ($n-eq16)-or($n-eq17) -and! ($n-eq16). Це потребувало круглих дужок, але це здавалося нездійсненним при прямій заміні. Оскільки всі інші речі були замінені, окрім коми, і вони мають найнижчий пріоритет, я просто розділив всю генеровану рядок на решітки, а потім загорнув кожен елемент у дужки та з’єднав його з-or .

Зрештою, згенерований код просто вкладається в Invoke-Expression( iex) для виконання, і тоді ми отримуємо бульний результат ( ви можете побачити код, який генерується замість результату тут ).

Це зайняло занадто довго, і я впевнений, що є трохи місця, щоб вичавити ще кілька байтів, але я не можу на це більше дивитися :-p


2

Perl, 99 130 байт

sub f{($_,$n)=@_;s/(-?\d+)?~(-?\d+)?|(-?\d+)/!(defined$3?$n!=$3:length$1&&$1>$n||length$2&&$n>$2)+0/ge;s/skip/&&!/g;s/,/||/g;eval}

Спробуйте це на Ideone.

Безголівки:

sub f {
    my ($e, $n) = @_;

    $e =~ s/(-?\d+)?~(-?\d+)?|(-?\d+)/ (defined($3) ? $n == $3 : (!length($1) || $n >= $1) && (!length($2) || $n <= $2)) + 0 /ge;
    $e =~ s/skip/ && ! /g;
    $e =~ s/,/ || /g;

    return eval($e);
}

1
Не вдається ~ -2 для введення -2. Також при вставці -? перед усіма трьома \ d *
Kjetil S.

@KjetilS. Виправлено для від'ємних чисел і нуля.
Денис Ібаєв

приємний код (повний розбір граматики часто не потрібен, регулярні виразки простіші)
Kjetil S.

1

JavaScript (ES6), 221 292 287 309 274 277 278 байт

(-5 байт завдяки Okx)

(j,v,m=1/0,Z=/(skip)([^,]+)/g)=>eval(j[M='replace'](/(-?\d*)~(-?\d*)/g,(e,a,b)=>(a[M]('-','#')||-m)+'<='+(T=v[M]('-','#'))+'&&'+T+'<='+(b[M]('-','#')||m))[M](Z,i=o=>o.match(Z)?i(o[M](Z,'&&!($2)')):o)[M](/,/g,'||')[M](/(^|[^=&#\d])(\d+)([^<\d]|$)/g,'$1$2=='+v+'$3')[M](/#/g,'-'))

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

Тест-фрагмент

D=(j,v,m=1/0,Z=/(skip)([^,]+)/g)=>eval(j[M='replace'](/(-?\d*)~(-?\d*)/g,(e,a,b)=>(a[M]('-','#')||-m)+'<='+(T=v[M]('-','#'))+'&&'+T+'<='+(b[M]('-','#')||m))[M](Z,i=o=>o.match(Z)?i(o[M](Z,'&&!($2)')):o)[M](/,/g,'||')[M](/(^|[^=&#\d])(\d+)([^<\d]|$)/g,'$1$2=='+v+'$3')[M](/#/g,'-'))
MPN Expression:<input type="text" value="1~9 skip (2~8 skip (3~7 skip (4~6 skip 5)))" id="MPN"></input>
<br>
Integer:<input type="number" id="INT" value=6></input>
<input type="button" value="Submit" onclick="T=r=>document.getElementById(r).value;console.log(D(T('MPN'),T('INT')))"></input>


@AriaAx Це має працювати зараз.
Р. Кап

@ R.Kap Ви можете використовувати 1/0для Infinity.
Окс

@ R.Kap Я спробував значення 6з виразом, 6 skip 6,~який, на мою думку, повинен бути, trueале він повертається false.
британіст

@briantist Насправді, я вважаю, що це має повернутися, falseяк це skipстосується всього, що слідує за ним ( 6,~у даному випадку) до тих пір, поки воно не загорнеться у дужки. Тому, я вважаю , що повинен повернутися trueна , (6 skip 6),~а не 6 skip 6,~з цілим входом 6.
Р. Кап

@briantist Іншими словами, нічого не6 skip 6,~ повинно відповідати, оскільки це означає різницю між множиною та множиною . {6}{6,-Infinity...Infinity}
Р. Кап

0

Röda + bc, 183 байт

f x{{["x=",x,"\n"];replace" ","",",","||","skip\\(","&&!","skip([0-9~]+)","&&!($1)","(?<!~|\\d)(\\d+)(?!~|\\d)","x==$1","(\\d*)~(\\d*)","x>=($1)&&x<=($2)","\\(\\)",x;["\n"]}|exec"bc"}

Це схоже на відповідь PowerShell (або я так думаю, я не розумію PowerShell). Це число приймає як аргумент, а код - як значення у вхідному потоці, наприклад:main { push("1~9") | f(5) } .

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

main {
    readLines("/tmp/tests.txt") | split(sep=";") | for code, num, ans do
        push(code, " -> ")
        print(code) | replace" ","",",","||","skip\\(","&&!","skip([0-9~]+)","&&!($1)","(?<!~|\\d)(\\d+)(?!~|\\d)","x==$1","(\\d*)~(\\d*)","x>=($1)&&x<=($2)","\\(\\)",num
        a := push(code) | f(num) | head()
        result := push("OK") if [ (a = "0" and ans = "False") or (a = "1" and ans = "True") ] else push("FAIL")
        print code, " ; ", num, " -> ", a, " ", ans, " (", result, ")\n"
    done
}

І тести:

10~20;14;True
10~20;20;True
10~20 skip 14~18;17;False
~ skip 6;8;True
16,17 skip 16;16;True
(16,17) skip 16;16;False
~10,5~;8;True
~10,5~;4;True
6 skip 6,~;6;True
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.