騎士と騎士


12

これはです。

この課題では、「Knights and Knaves」パズルを解決するプログラム/関数を作成します。

バックグラウンド

あなたは島にいることに気づく...など...あなた以外の島にいる人は皆、騎士か悪魔のいずれかです。

騎士は真の発言のみを行うことができます。

Knavesは虚偽のステートメントのみを作成できます。

「ステートメント」を厳密に定義したくありませんが、ステートメントは「true」または「false」のいずれかであると言います。これは逆説的な文章を除外することに注意してください。

この挑戦の目的のために、あなたは島民のグループに出くわします。彼らはあなたに声明を出します。

あなたの仕事は誰が騎士で誰がKnaveであるかを決定することです。

入力:

次の情報が(合理的な形式で)提供されます。

  • 出席者のリスト。大文字のアルファベット文字「AZ」で名前が付けられます。これにより課せられる人数の制限を超えることはありません。

  • 各人が行う声明。これに関する重要な詳細については、以下を参照してください。

出力

次に、各人が何であるかを(合理的な形式で)出力します。例えば、そこにあれば選手だったA B C DとA騎士ですが、残りknavesである、あなたは出力ができました

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

重要な詳細:

  • 大文字のアルファベットA〜Zは島民を指します。

  • 文字0(ゼロ)と1(1)は、それぞれ「Knave」と「Knight」を表します。(指定する限り、他の2つの非AZ文字を使用できます)

  • 出席している各島民は、自然な数の発言を行うか、何も言わないことを選択する場合があります。

  • 通常の論理演算子はステートメントで使用できます(IS *、AND、OR、NOT)。これに加えて、De Morganの法則と条件式を使用できます。以下は、音声パズルでどのように表示されるか、その後にプログラムに入力される方法の例です。

(*より技術的な注意。「IS」演算子は実際には封じ込めとして使用されます(論理演算子ではありません)。「Aは騎士です」と言うとき、私は本当に「AはKnights」。使用される真の演算子は「ϵ」です。簡単にするために、代わりに「=」を使用します。)

私は以下を使用します(合理的で一貫性がある限り、何でも使用できます)。

  • ^ そして
  • v または
  • = IS
  • ~ ない
  • => 実装
  • X:X人は...

人Zは、次のタイプのステートメントの任意の組み合わせを作成できます。

人Zは言う...

  1. 人Aは騎士です。

    Z: A = 1

  2. 人物QはKnaveです。

    Z: Q = 0

  3. 私は騎士です。

    Z: Z = 1

  4. 人Aは騎士、または人Bは騎士です。

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

  5. 人Cは騎士であり、私はKnaveです。

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

  6. 人Rは騎士ではありません。

    Z: ~( R = 1 )

さらに、入力にはDe Morganの法則を使用することもできます

  1. 人物Aと人物Bの両方がKnavesであることは真実ではありません

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

  2. 人Aまたは人Bのいずれかが騎士であることは誤りです

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

最後に、条件とその否定を使用できます

  1. 私が騎士なら、人BはKnaveです

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

  2. 人物Bが騎士である場合、人物CがKnaveであるというのは事実ではありません。

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

条件に関する注意

詳細については、ウィキペディアをご覧ください。

条件文はp => qの形式を取ります。ここで、pとqはそれ自体が文です。pは「前件」、qは「後件」です。ここにいくつかの有用な情報があります

  • 条件の否定は次のようになります。〜(p => q)はp ^〜qと同等です

  • 誤った前提は何でも意味します。つまり、pがfalseの場合、qが何であるかに関係なく、ステートメントp => qはtrue です。たとえば、「if 2 + 2 = 5 then I am Spiderman」は本当の声明です。

いくつかの簡単なテストケース

これらのケースは、次のように与えられます(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はKnaveです。

    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の両方が騎士だというのは事実ではありません。

    Q:それは本当です。

    X:Wの言うことが本当なら、Qの言うことは偽です。

回答:

WとQは騎士です。XはKnaveです。

入力

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

出力


    W = 1
    Q = 1
    X = 0
    

ある 同様の課題の解析と条件またはド・モルガンのが含まれていないに焦点を当てた3年前からは。したがって、私は、これがだまされないように焦点と実装が十分に異なると主張します。

この挑戦はだまされたため一時的に終了しました。それ以来再開されました。

この課題は、まず焦点が異なると主張します。他の課題は英語の構文解析に焦点を当てていますが、これはそうではありません。次に、ANDとORのみを使用しますが、これは条件を使用し、さらに多くのパズルを解くことができます。結局のところ、問題はそのチャレンジからの答えをこれに簡単に置き換えることができるかどうかであり、条件と条件否定を含めると、より堅牢な変更を順番に行う必要がある十分な複雑さが追加されると思いますこの課題に合わせて。


Knaveが言ったら何を結論づけることができ(B=1)=>(C=0)ますか?~((B=1)=>(C=0))または(B=1)=>(C=1)他の何か?
— njpipeorgan

これは5分未満で行うことは不可能です。この問題はSATと呼ばれ、複雑さが指数関数的です。したがって、一般的な場合(2 SATではない)でn = 26の場合、妥当な時間内にコンピューターで解決することは不可能です。
— ラボ

最初のテストケースには2つの出力があります。logicalを使用しているため、B がfalse ORである可能性があるA:1 B:1かA:1 B:0、B=1Aがtrueのままである可​​能性があります。
— かてんきょう

@njpipeorgan KnaveがBの場合、彼はそれを言うことができません。誤った前提は何でも意味するため、その記述は真実です。悪党はどのような別の文字ならば、あなたは否定、かかる(B=1)^(C=1)条件文が正常に扱われる方法に従って
— リアム・

1
不思議に思う人にとって、本当の問題は、私が入力クエリを見て、彼が言葉のパズルを見ていたからです。それは修正されました
— キャメロンAavik

回答:


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で見られるのと同じ形式のクエリを使用しますが、最初のクエリに対して行った変更の一部もありません。2つの形式間で変換されるため、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を使用するため、2番目のソリューションには3.5(3.4ではなく)が必要です。


1

Mathematica、80バイト

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

説明

この関数Fは2つの引数を取ります。

  • c すべてのキャラクターの名前のリストです。
  • s ステートメントのリストです。各ステートメントには2つの部分が含まれています。

たとえば、Q、X、Wの3つの文字があります。

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であるというソリューションが1つしかないことを意味します。複数のソリューションがある場合、出力は次のようになります{{...},{...},...}


アルゴリズムは非常に簡単です。{True,False}~Tuples~Length@cキャラクター間の騎士とネイブスの可能な組み合わせをすべて提供します。次にThread[c->#]&/@、これらの組み合わせに基づいてルールの配列を作成します。2つの文字AとBの場合、配列は

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

ステートメントをこれらのルールの1行で置き換えると、配列は次のようになります

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

この配列の最初の列は発言者の識別情報であり、2番目の列は発言が真か偽かを示します。有効な解決策は、話者の身元と声明の一致を要求します。上記の配列は、この組み合わせが解決策ではないことを意味します。2番目のスピーカーであるナイトが誤った声明を出すためです。

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

置換を行い、条件を満たす組み合わせを選択します。


1

ルビー、128

これは他のみんなと同じアルゴリズムで、knavesとknightsの可能なすべての組み合わせを試して、どのスティックを確認します。私が取り組んでいる別のものがありますが、もっと長くなると思います(より興味深い)。

ステートメントの入力は次のとおりでなければなりません。

  • & そして
  • | または
  • == IS
  • ! ない
  • > 実装
  • X: X人は...

また、各ステートメントとサブステートメントを括弧で囲む必要があります。このバージョンの唯一の問題は、最大で2 ^ 26回の反復を経ることであり、それらがすべてknavesでない場合は、少なくとも2 ^(26-n)回の反復です!つまり、2人の人間がいて、少なくとも1人が知識を持っていない場合、最低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}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.