骑士和小刀


12

这是

在这个挑战中,我们将编写解决“ 骑士与刀 ”难题的程序/功能。

背景

您发现自己在一个岛上……等等。岛上除您以外的每个人都是骑士或is

骑士只能发表真实的声明。

刀只能做出虚假陈述。

我不想严格定义“语句”,但是我们要说一个语句是“ true”或“ false”的任何内容。请注意,这不包括矛盾的句子。

为了这个挑战,您将遇到一群岛民。他们会向您陈述。

您的任务是确定谁是骑士和谁是K夫。

输入:

您将(以任何合理的格式)获得以下信息:

  • 在场人员清单。它们将以大写字母字符“ AZ”命名。由此所施加的人数限制不会被超过。

  • 每个人的陈述。有关此的重要详细信息,请参见下文。

输出量

然后,您将输出(以任何合理的格式)每个人的身份。例如,如果有玩家A B C D并且A是骑士,而其他人是骑士,则可以输出

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

重要细节:

  • 大写字母字符AZ表示岛民。

  • 字符0(零)和1(一)分别表示“刀”和“骑士”。(您可以指定任意两个其他非AZ字符)

  • 在场的每个岛民都可以发表任何自然数的陈述,或者可以选择不说话。

  • 普通逻辑运算符可以在语句(IS *,AND,OR,NOT)中使用。最重要的是,可以使用De Morgan的法律条件。下面是如何在口语难题中呈现它们的示例,然后是如何将其输入到程序中的示例。

(*在更多技术说明上。“ IS”运算符实际上用作遏制(这不是逻辑运算符)。当我说“ A是骑士”时,我的意思是“ A是该集合的成员。 Knights”。使用的真正运算符为'ϵ'。为简单起见,我们将改用'='。)

我使用以下方法(只要合理且一致,您可以使用任何方法):

  • ^
  • v 要么
  • =
  • ~
  • => 暗示
  • X:X人声称...

Z人可以将以下任何类型的陈述进行任意组合:

Z人说...

  1. A是骑士。

    Z: A = 1

  2. Q是个n夫。

    Z: Q = 0

  3. 我是骑士

    Z: Z = 1

  4. A是骑士,人B是骑士。

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

  5. C人是一名骑士,我是一名n夫。

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

  6. R人不是骑士。

    Z: ~( R = 1 )

最重要的是,输入也可以使用De Morgan定律

  1. 人A和人B都是小刀是不正确的

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

  2. 人A或人B是骑士是错误的

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

最后,可以使用条件及其取反

  1. 如果我是骑士,那么人B是K夫

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

  2. 如果人B是一个骑士,那么人C是一个n夫,这是不正确的。

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

条件注释

查阅Wikipedia了解更多信息。

条件语句的形式为p => q,其中pq本身就是语句。p是“前人”,q是“后人”。这是一些有用的信息

  • 条件的否定看起来像这样:〜(p => q)等效于p ^〜q

  • 错误的前提意味着任何东西。即:如果p为假,则无论q是什么,任何语句p => q为真。例如:“如果2 + 2 = 5,那么我就是蜘蛛侠”是正确的说法。

一些简单的测试用例

这些情况以以下方式给出:(1)我们将如何在语音中提出问题(2)我们如何将其提出给计算机(3)计算机可能给出的正确输出。

  1. A人和B人在路上接近您,并作以下陈述:

    A:B是个小刀,或者我是个骑士。

    B:A是骑士。

回答:

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是个K夫。

    B:如果这是真的,那么F也是一个Knave。

回答:

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都是骑士,这是不对的。

    问:是的。

    X:如果W所说的是正确的,那么Q所说的是错误的。

回答:

W和Q是骑士。X是个n夫。

输入值

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

输出量


    W = 1
    Q = 1
    X = 0
    

3年前有一个 类似的挑战,它着重于分析并且不包含条件或De Morgan的挑战。因此,我认为,在重点和实施上有足够的不同,可以避免这种欺骗。

这项挑战作为骗局被暂时关闭。此后已重新打开。

我声称,首先,这一挑战的重点不同。另一个挑战集中在英语解析上,而事实并非如此。其次,它仅使用AND和OR,而使用条件条件并允许解决更多难题。归根结底,问题是该挑战的答案是否可以轻而易举地替代这一挑战,我相信加入条件和条件否定会增加足够的复杂性,因此需要进行更强大的更改才能进行以应对这一挑战。


如果一个Knave说了什么,我们可以得出什么结论(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:1A:1 B:0因为B的B=1可能是假的,而一个仍然是正确的。
Katenkyo '16

@njpipeorgan如果Knave是B,他不能这么说。错误的前提意味着任何东西,因此该陈述将是正确的。如果Knave的角色与众不同,那么您将采取否定的方式,这(B=1)^(C=1)与通常处理条件的方式相同
Liam

1
对于那些想知道的人,真正的问题是因为我正在查看输入查询,而他正在查看措辞难题。已解决问题
Cameron Aavik

Answers:


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}]

取消说明:

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]]

另外,由于使用了PEP 448,第二种解决方案需要3.5(而不是3.4)


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] }};

其中TrueFalse分别指骑士和刀。然后

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}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.