Лицарі та ножі


12

Це .

У цьому виклику ми будемо писати програми / функції, які розгадують загадки " Лицарі та знать ".

Фон

Ви опиняєтесь на острові ... і т. Д. ... кожна людина на острові, окрім вас, є або лицарем, або монахою .

Лицарі можуть робити лише правдиві твердження.

Ножі можуть робити лише помилкові твердження.

Я не хочу чітко визначати "твердження", але ми скажемо, що твердження - це все, що є "правдивим" або "хибним". Зауважте, що це виключає парадоксальні речення.

Для цілей цього виклику ви натрапляєте на групи острівців; вони будуть робити вам заяви.

Ваше завдання - визначити, хто є Лицарем, а хто - Кнавом.

Вхід:

Вам нададуть (у будь-якому розумному форматі) таку інформацію:

  • Список присутніх. Вони будуть названі великими символами алфавіту "AZ". Обмеження кількості людей, накладене цим, не буде перевищено.

  • Твердження, які робить кожна людина. Нижче див. Важливі деталі щодо цього.

Вихідні дані

Потім ви виведете (у будь-якому розумному форматі) те, що є кожною людиною. Наприклад, якби були гравці A B C Dі Aє лицарем, а решта - монахини, ви могли б вивести

A: 1
B: 0
C: 0
D: 0

Важливі деталі:

  • Великі літери алфавіту AZ відносяться до острівців.

  • Символи 0(нуль) та 1(один) позначають відповідно "Кнав" та "Лицар". (Ви можете будь-які інші два символи AZ, якщо ви вказали)

  • Кожен присутній острівчанин може робити будь-яку природну кількість тверджень, а може і нічого не сказати.

  • Нормальні логічні оператори можуть використовуватися в операторах ( IS *, AND, OR, NOT ). На додаток до цього, можуть використовуватися Закони та умови Де Моргана . Нижче наведено приклади того, як вони можуть бути представлені у розмовній головоломці з подальшим введенням у вашу програму.

(* щодо більш технічної примітки. Оператор "IS" дійсно використовується як стримуючий елемент (що не є логічним оператором). Коли я кажу "A - лицар", я справді маю на увазі "A є членом набору Лицарі ". Справжній оператор, який використовується, був би" ϵ ". Для простоти, ми замість цього будемо використовувати" = ".)

Я використовую наступне (ви можете використовувати будь-що, якщо це розумно і послідовно):

  • ^ І
  • v АБО
  • = Є
  • ~ НЕ
  • => ВПРАВЛІННЯ
  • X:Особа X стверджує, що ...

Особа Z може скласти будь-яку комбінацію будь-якого з наступних типів висловлювань:

Person Z каже, що ...

  1. Особа А - лицар.

    Z: A = 1

  2. Людина Q - Кнав.

    Z: Q = 0

  3. Я лицар.

    Z: Z = 1

  4. Особа А - лицар АБО Особа Б - лицар.

    Z: ( A = 1 ) v ( B = 1)

  5. Людина С - Лицар І Я Кнав.

    Z: ( C = 1 ) ^ ( Z = 0 )

  6. Людина R НЕ є лицарем.

    Z: ~( R = 1 )

Крім цього, вхідні дані також можуть використовувати Закони Де Моргана

  1. НЕ ПРАВИЛЬНО, що і людина А, і Особа Б - це ножі

    Z: ~( ( A = 0 ) ^ ( B = 0 ) )

  2. Помилково, що або людина A, або людина B - лицар

    Z: ~( ( A = 1 ) v ( B = 1) )

Нарешті, можна використовувати умовні умови та їх заперечення

  1. Якщо я лицар, то людина Б - це Кнав

    Z: ( Z = 1 ) => ( B = 0 )

  2. НЕ ПРАВИЛЬНО, що якщо людина Б - лицар, то особа С - це Кнав.

    Z: ~( ( B = 1 ) => ( C = 0 ) )

Примітки до умовних умов

Перегляньте wikipedia для отримання додаткової інформації.

Умовний вираз має вигляд p => q , де p і q - самі твердження. p - "попередник", а q - "наслідковий". Ось корисна інформація

  • Заперечення умови виглядає так: ~ (p => q) еквівалентно p ^ ~ q

  • Неправдиве приміщення передбачає що-небудь. Тобто: якщо p хибний, то будь-яке твердження p => q є істинним, незалежно від того, що таке q . Наприклад: "якщо 2 + 2 = 5, то я павук" - це правдиве твердження.

Деякі прості тестові випадки

Ці випадки наведені наступним чином (1), як ми поставили б проблему в мовленні (2), як ми можемо поставити її перед комп'ютером (3) правильний вихід, який може дати комп'ютер.

  1. Особа A та людина B підходять до вас на дорозі і роблять такі заяви:

    A: B - коня, або я - лицар.

    Б: А - лицар.

Відповідь:

B - лицар, а A - лицар.

Вхід:

A B        # Cast of Characters
A: ( B = 0 ) v ( A = 1)
B: A = 1

Вихід:


    A = 1
    B = 1
    

  1. Особи A, B і F підходять до вас на дорозі і роблять такі заяви:

    A: Якщо я лицар, то B - знахар.

    Б: Якщо це правда, то і F - це Кнав.

Відповідь:

A - лицар, B - Knave, F - лицар.

Вхідні дані

A B F
A: ( A = 1 ) => ( B = 0 )
B: ( A = 1 ) => ( F = 0 ) 

Вихід:


    A = 1
    B = 0
    F = 1
    

  1. Q, X і W підходять до вас на дорозі і роблять такі заяви:

    W: Неправда, що і Q, і X - лицарі.

    З: Це правда.

    X: Якщо те, що говорить W, є істинним, то те, що говорить Q, є помилковим.

Відповідь:

W і Q - лицарі. X - Кнав.

Вхідні дані

Q X W
W: ~( ( Q = 1 ) ^ ( X = 1 ) )
Q: W = 1
X: ( W = 1 ) => ( Q = 0 )

Вихідні дані


    W = 1
    Q = 1
    X = 0
    

Існує аналогічний виклик з 3 років тому, який зосереджується на синтаксичному розборі і не містить умовних умов або де-морганівських. І тому, я заперечу, достатньо різний у фокусі та здійсненні, щоб уникнути того, що це було дурнем.

Цей виклик ненадовго було закрито як дурпа. З тих пір вона була відновлена.

Я стверджую, що цей виклик, по-перше, відрізняється по фокусу. Інша проблема зосереджена на синтаксичному розборі англійської мови, це не так. По-друге, він використовує лише І і АБО, тоді як це використовує умовні умови та дозволяє вирішувати ще багато загадок. Зрештою, питання полягає в тому, чи можна відповіді з цього виклику тривіально замінити на цей, і я вважаю, що включення умовних та умовних заперечень додає достатньої складності, що для того, щоб зробити необхідні більш ґрунтовні зміни, щоб відповідати цьому виклику.


Що ми можемо зробити висновок, якщо говорить Кнав (B=1)=>(C=0)? ~((B=1)=>(C=0))або (B=1)=>(C=1)чи щось інше?
njpipeorgan

Це зробити неможливо менше, ніж за 5 хвилин. Ця проблема відома як SAT і є експоненціальною за складністю. Таким чином, для n = 26 в загальному випадку (не 2 SAT) вирішити на комп’ютері неможливо в розумний час.
Лабо

Ваш перший тестовий випадок має два можливі результати. Оскільки ви використовуєте логічне OR, це може бути A:1 B:1або A:1 B:0тому, що B B=1може бути помилковим, а A все-таки буде правдою.
Katenkyo

@njpipeorgan Якщо Knave B, він не може цього сказати. Неправдиве припущення передбачає що-небудь, і тому це твердження було б істинним. Якщо у Кнава якийсь інший персонаж, ви приймете заперечення, яке відповідає (B=1)^(C=1)тому, як умовами зазвичай займаються
Ліам

1
Для тих, хто цікавиться, справжнє питання полягало в тому, що я дивився на вхідний запит, а він розглядав сформульовану головоломку. Це було виправлено
Камерон Аавік

Відповіді:


6

Python 3, 450 342 307 байт

Редагувати: виявляється, я забув імпорт ...

Першим моїм рішенням є використання гнучких імен для запитів

from functools import*
def g(c,r):c=c.split();l,y=len(c),range;d=[dict((c[i],n>>i&1)for i in y(l))for n in y(2**l)];return[n[1]for n in[[eval(reduce(lambda x,y:x.replace(y,str(d[i][y])),d[i],')and '.join(['not',''][d[i][s[0]]]+'('+s[2:].replace('->','<1or')for s in r)+')')),d[i]]for i in y(len(d))]if n[0]]

Ви можете зателефонувати вище за допомогою

g('Q X W', ['W: not( ( Q == 1 ) and ( X == 1 ) )','Q: W == 1', 'X: ( W == 1 ) -> ( Q == 0 )'])

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

from functools import*
def g(c,r):c=c.split();l,y=len(c),range;d=[{**dict((c[i],n>>i&1)for i in y(l)),**{'v':'or','^':'and','=':'==','~':'not'}}for n in y(2**l)];f=lambda r,c:reduce(lambda x,y:x.replace(y,str(c[y])),c,('(0<1'+''.join([')^ '+['~',''][c[t[0]]]+'('+t[1]for t in[s.split(":")for s in r]])+')').replace('=>','<1or'));return[dict((o,j) for o,j in n[0].items() if o in c) for n in[[d[i],eval(f(r,d[i]))]for i in y(len(d))]if n[1]]

І це можна назвати:

g('Q X W', ['W: ~( ( Q = 1 ) ^ ( X = 1 ) )','Q: W = 1', 'X: ( W = 1 ) => ( Q = 0 )'])

Вони обидва повертаються

[{'X': 0, 'W': 1, 'Q': 1}]

Пояснення без вогню:

from functools import *
def knight_and_knaves(cast,rules):
    # turns 'A B C' into ['A','B','C']
    cast = cast.split()
    # gets all numbers that can fit in len(cast) bits
    bitmasks = range(2 ** len(cast))
    # for every bitmask, apply the value for a bit to the boolean value for each cast member.
    # This returns a dictionary of all possible outcomes.
    d=[dict((cast[i], n>>i & 1) for i in range(len(cast))) for n in bitmasks]
    # Split rules at colon
    rules = [s.split(":")for s in rules]
    # Turns list of rules into one python expression, joins each rule with ')and ', maybe a 'not' depending on if the hypothesis has the rule as a lie, and '('.
    # Also replaces '->' with '<1or' which is equivalent to it. Also starts with '(True' and ends with ')' to resolve missing parentheses
    transform_rules = lambda d, rules: ('(True' + ''.join([')and ' + ['not', ''][d[rule[0]]] + '(' + rule[1].replace('->','<1or') for rule in rules]) + ')')
    # Applys transform_rules on each outcome and evaluates the result, storing it into a list of lists where each element is [outcome, value]
    outcomes=[[d[i],eval(reduce(lambda x,y:x.replace(y,str(d[i][y])),d[i],transform_rules(d[i], rules)))] for i in range(len(d))]
    # Filters outcomes if value is True
    return[n[0]for n in outcomes if n[1]]

Також для другого рішення потрібно 3,5 (а не 3,4) завдяки використанню PEP 448


1

Математика, 80 байт

F[c_,s_]:=Select[Thread[c->#]&/@{True,False}~Tuples~Length@c,And@@Equal@@@s/.#&]

Пояснення

Функція Fбере два аргументи,

  • c перелік імен усіх символів,
  • s це перелік тверджень, кожна з яких містить дві частини - хто що говорить.

Наприклад, є три символи, Q, X і W.

characters={q,x,w};

І вони кажуть:

statements=
   {{w, !((q==True)&&(x==True))   },
    {q, w==True                   },
    {x, Implies[w==True,q==False] }};

де Trueі Falseозначає Лицарі та Кнави відповідно. Потім

F[characters, statements]

дасть {{q->True, x->False, w->True}}, а це означає, що існує лише одне рішення, що Q і W - лицарі, а X - Knave. Якщо рішення більше, ніж один, результат буде мати вигляд{{...},{...},...}


Алгоритм дуже простий. {True,False}~Tuples~Length@cдає всі можливі комбінації Лицарів та Кнавсів серед персонажів. Потім Thread[c->#]&/@побудуйте масив правил на основі цих комбінацій. У випадку двох символів A і B масив буде

{{a->True, b->True },
 {a->True, b->False},
 {a->False,b->True },
 {a->False,b->False}}

Підставивши висловлювання одним рядком цих правил, ми отримаємо такий масив, як виглядає

{{True,True},{True,False},{False,False}}

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

Select[...,And@@Equal@@@s/.#&]

робить заміни та вибирає ті комбінації, які задовольняють умові.


1

Рубі, 128

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

Введення оператора повинно бути:

  • & І
  • | АБО
  • == Є
  • ! НЕ
  • > ВПРАВЛІННЯ
  • X: Особа X стверджує, що ...

Я також вимагаю, щоб кожне твердження та підтвердження були в дужках. Єдина проблема з цією версією полягає в тому, що вона проходить щонайбільше 2 ^ 26 ітерацій, і якщо вони не всі кити, принаймні 2 ^ (26-n) ітерацій ! Якщо говорити про це в перспективі, це означає, що якщо двоє людей, і принаймні один не є монашем, знадобиться мінімум 16 777 216 ітерацій !

Щоб обмежити це, я надсилаю наступне в 168 байт. Підробіть 26для того, #{o.size}щоб скоротити його до 161.

->s{o=s[/.*?$/].split
i=0
eval h=o.zip(("%0#{o.size}b"%i+=1).chars).map{|k|k*?=}*?;until h&&o.all?{|t|!s[/#{t}:(.*)$/]||eval("(#{t}<1)^(#{$1.gsub(?>,'!=true||')})")}
h}

Але якщо я можу замість цього використовувати масив людей та карту висловлювань, наприклад:

c[[?A, ?B],
  {
    ?A=> "( B == 0 ) | ( A == 1)",
    ?B=> "A == 1"
  }
 ]

Тоді я знижую її до 128.

->o,s{i=0
eval h=o.zip(("%026b"%i+=1).chars).map{|k|k*?=}*?;until h&&s.all?{|t,k|eval("(#{t}<1)^(#{k.gsub(?>,'!=true||')})")}
h}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.