Рыцари и Кнавесы

12

Это .

В этом задании мы будем писать программы / функции, которые решают головоломки « Рыцари и Кнавесы ».

Фон

Вы попадаете на остров ... и т. Д. ... каждый человек на острове, кроме вас, является либо рыцарем, либо мошенником .

Рыцари могут только делать правдивые заявления.

Knaves может только делать ложные заявления.

Я не хочу строго определять «утверждение», но мы скажем, что утверждение - это все, что является «истинным» или «ложным». Обратите внимание, что это исключает парадоксальные предложения.

В целях этого испытания вы встретите группы островитян; они сделают вам заявления.

Ваша задача - определить, кто такой рыцарь, а кто - мошенник.

Входные данные:

Вам будет предоставлена ​​(в любом разумном формате) следующая информация:

  • Список присутствующих. Они будут названы заглавными буквами алфавита "AZ". Ограничение на количество людей, наложенное этим, не будет превышено.

  • Заявления, которые делает каждый человек. Ниже приведены важные подробности об этом.

Выход

Затем вы выведете (в любом разумном формате), что это за человек. Например, если были игроки A B C Dи Aэто рыцарь, а остальные мошенники, вы можете вывести

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

Важные детали:

  • Прописные буквы алфавита AZ относятся к островитянам.

  • Символы 0(ноль) и 1(один) относятся к «мошеннику» и «рыцарю» соответственно. (Вы можете использовать любые два других символа, отличных от AZ, если вы укажете)

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

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

(* на более техническом примечании. Оператор «IS» действительно используется как сдерживание (что не является логическим оператором). Когда я говорю «А - это Рыцарь», я действительно имею в виду «А - член набора Рыцари ". Истинным оператором будет« ϵ ». Для простоты мы будем использовать« = ».)

Я использую следующее (вы можете использовать что угодно, если это разумно и последовательно):

  • ^ И
  • v ИЛИ
  • = ЯВЛЯЕТСЯ
  • ~ НЕ
  • => ПОДРАЗУМЕВАЕТ
  • X:Человек X утверждает, что ...

Человек Z может сделать любую комбинацию любого из следующих типов утверждений:

Человек 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. Ложно, что либо человек А, либо человек Б - рыцарь

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

Наконец, можно использовать условные выражения и их отрицания

  1. Если я рыцарь, то человек Б - мошенник

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

  2. Неверно, что если человек B - рыцарь, то человек C - мошенник.

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

Примечания об условных

Проверьте Википедию для получения дополнительной информации.

Условное утверждение принимает форму p => q , где p и q сами являются утверждениями. р является «предшественником», а q - «последующим». Вот некоторая полезная информация

  • Отрицание условия выглядит так: ~ (p => q) эквивалентно p ^ ~ q

  • Ложная предпосылка подразумевает что угодно. То есть: если p ложно, то любое утверждение p => q верно, независимо от того, что есть q . Например: «если 2 + 2 = 5, то я человек-паук» - это верное утверждение.

Несколько простых тестовых случаев

Эти случаи приведены следующим образом (1) как мы поставили бы проблему в речи (2) как мы могли бы поставить ее на компьютер (3) правильный вывод, который мог бы дать компьютер.

  1. Человек А и Человек Б подходят к вам на дороге и делают следующие заявления:

    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 - мошенник.

    B: Если это правда, то F тоже мошенник.

Ответ:

A - Рыцарь, B - Мошенник, 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 являются рыцарями.

    Q: Это правда.

    X: Если то, что говорит W, верно, то то, что говорит Q, неверно.

Ответ:

W и Q - рыцари. Х мошенник.

вход

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

Выход


    W = 1
    Q = 1
    X = 0
    

Существует аналогичная проблема от 3-х лет назад, которая фокусируется на разборе и не содержит условных выражений или де Моргана. И поэтому, я бы сказал, достаточно отличается по своей направленности и реализации, чтобы это не было обманом.

Этот вызов был кратко закрыт как обман. С тех пор он был вновь открыт.

Я утверждаю, что эта проблема, во-первых, отличается в фокусе. Другая проблема фокусируется на разборе английского, это не так. Во-вторых, он использует только И и ИЛИ, тогда как он использует условные выражения и позволяет решать гораздо больше головоломок. В конце концов, вопрос заключается в том, можно ли тривиально заменить этот ответ на этот вызов или нет, и я считаю, что включение условных и условных отрицаний добавляет достаточную сложность, чтобы потребовались более надежные изменения, чтобы чтобы соответствовать этому вызову.

Liam
источник
Что мы можем сделать вывод, если мошенник говорит (B=1)=>(C=0)? ~((B=1)=>(C=0))или (B=1)=>(C=1)или что-то еще?
njpipeorgan
Это невозможно сделать менее чем за 5 минут. Эта проблема известна как SAT и является экспоненциальной по сложности. Таким образом, для n = 26 в общем случае (не 2 SAT) невозможно решить на компьютере в разумные сроки.
Labo
Ваш первый тестовый пример имеет 2 возможных выхода. Поскольку вы используете логическое OR, это может быть A:1 B:1или A:1 B:0потому, что B B=1может быть ложным, в то время как A все еще будет истинным.
Катенкё
@njpipeorgan Если Мошенник - Б, он не может этого сказать. Ложная предпосылка подразумевает что угодно, и поэтому это утверждение будет правдой. Если у мошенника какой-то другой персонаж, вы бы взяли отрицание, (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 )'])

Следующий здесь использует тот же формат запросов, что и в OP, в нем также нет некоторых модификаций, которые я сделал в первом. Это 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}]

Ungolfed Объяснение:

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

Mathematica, 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 - мошенник. Если существует более одного решения, результат будет выглядеть{{...},{...},...}


Алгоритм очень прост. {True,False}~Tuples~Length@cдает все возможные комбинации рыцарей и Knaves среди персонажей. Затем 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/.#&]

выполняет замены и выбирает те комбинации, которые удовлетворяют условию.

njpipeorgan
источник
1

Руби, 128

Это тот же алгоритм, что и у всех остальных, попробуйте все возможные комбинации мошенников и рыцарей и посмотрите, какие палки. У меня есть другой, над которым я работаю, но я думаю, что это будет дольше (хотя и более интересно).

Входные данные оператора должны быть:

  • & И
  • | ИЛИ
  • == ЯВЛЯЕТСЯ
  • ! НЕ
  • > ПОДРАЗУМЕВАЕТ
  • X: Человек X утверждает, что ...

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

Чтобы ограничить это, я отправляю следующее в 168 байтах. Sub в 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}
Не тот Чарльз
источник