コードゴルフ:英語を解析してKnights and Knavesの論理問題を解決する


16

バックグラウンド

ビルとジョンの2人がいます。そのうちの1人は常に真実を語る騎士であり、もう1人は常に嘘をつく悪魔です。あなたは誰が騎士であり、誰が悪党であるかを知りません。それから、各人はだれが騎士で、だれが騎士であるかについてのいくつかの声明を言います。この情報を使用して、誰が騎士で誰が悪党であるかを結論付けなければなりません。

騎士とKnavesロジックの問題は Booleen代数に基づいています。人が言う言葉はブーリアンの充足可能性の問題を形成します。knaveのステートメントは常にfalseでなければならず、他のKnightのステートメントは常にtrueでなければなりません。

ジョンは「私はどちらもナイフであり、ビルはナイフだ」と言います。ジョンが騎士だった場合、この声明は間違っているので、彼は騎士になることはできません。もし彼が悪党で、ビルが騎士なら、最初の部分が真実だと思っていたとしても、この声明はまだ間違っているでしょう。だから、ジョンは悪魔です。

チャレンジ

あなたの挑戦は、各人によって作られた声明のリストを取り、誰が悪党で誰が騎士であるかを把握する、可能な限り最短のプログラムを書くことです。カバーする詳細がたくさんあるので、この問題は3つのセクションで説明されています。

入力

入力は2行で、その後に改行が続きます。各行には、文字の1つの名前、コロン、その人が言ったいくつかの文が続きます。一人が騎士である場合、彼の文章はすべて真実になり、すべてのナイフの文章は偽になります。文の最初の文字は常に大文字で、すべての文はピリオドで終わります。以下に例を示します。

Joe: Both I am a knight and neither Steve is a knave nor I am a knave.
Steve: Joe is a knave. Either Joe is a knight or I am a knight.

解析

各文は、少なくとも1つの句で構成されます。各句には、いくつかの項目のいずれかが含まれています(できれば、私の表記法を理解できます)。

both [clause] and [clause]
either [clause] or [clause]
neither [clause] nor [clause]
[I am | (other person's name) is] a [knight | knave]

これは、ポーランドの表記法と同様の方法で理解できるため、明確です。文の例を次に示します。

Both I am a knight and neither Steve is a knave nor I am a knave.

ブール代数への変換は簡単です。「両方」のステートメントはANDであり、「いずれか」ステートメントはXORであり、「どちらでもない」ステートメントはNORです。

(I am a knight) AND ((Steve is a knave) NOR (I am a knave))

出力

出力は2行で構成されます。各行は(順番に)人の名前で構成され、その後、彼が騎士であるか、悪党であるかを示します。常に1人の騎士と1人の小人がいます。上記の例の出力は次のとおりです。

Joe is the knave.
Steve is the knight.

問題が解決できない場合(だれが何であるかわからない場合、または解決策がない場合)、プログラムは有効な出力を生成する以外は何でもできます。

その他の例

入力

Sir Lancelot: Either both I am a knight and Merlin is a knave or both I am a knave and Merlin is a knight.
Merlin: Either both I am a knight and Sir Lancelot is a knight or both I am a knave and Sir Lancelot is a knave.

出力

Sir Lancelot is the knight.
Merlin is the knave.

入力

David: Neither I am a knave nor Patrick is a knight. Either I am a knight or Patrick is a knave.
Patrick: Either I am a knight or both I am a knight and David is a knight.

出力

David is the knave.
Patrick is the knight.

入力

Lizard: I am a knight.
Spock: I am a knave.

1つの可能な出力

Rock Paper Scissors

規則、規制、および注記

  1. 標準コードのゴルフ規則が適用されます
  2. プログラムは印刷可能なASCIIのみで構成されている必要があります
  3. すべての入力と出力は、STDINとSTDOUTからのものです。

大文字と小文字の区別はどうですか?構文の説明は小文字で、例は大文字です。大文字と小文字を区別しないことが要件ですか?
-ugoren

各センテンスの最初の文字は大文字になりますが、それ以外は名前のみが大文字になります。どのような具体的な問題が発生していますか?
PhiNotPi

適切な英語の大文字を使用しているため、両方/どちらか/どちらでもない最初の文字はコンテキストに依存します。大文字と小文字を区別しないことは、それに対処する簡単な方法だと思います。
ウゴレン

回答:


6

Python、491文字

各行をPython式に変換し、それを検証することにより機能します。
knaveとknightは0と1として評価されます。2人の場合、両方のオプションを試します。
たとえば、にJoe: Steve is a knaveなりJoe==(Steve==knave)ます。このように、もしJoe悪魔であれば、結果は彼が嘘をついている場合にのみ真実です。
不可能または未定の場合、Youいエラーが発生します。不可能な場合r[0]は、r空であるため、インデックスエラーです。決定できない場合r[1:]、文字列のリストに連結すると問題が発生します。

import sys
def p():
    a=s.pop(0)
    try:return{"both":"(%s*%s)","either":"(%s|%s)","neither":"(1-(%s|%s))"}[a.lower()]%(p(),p())
    except KeyError:r=s[2];del s[:4];return"(%s==%s)"%((a,m)[a=="I"],r)
x=[];w=[]
for l in sys.stdin:
    m,l=l.split(":");w+=[m]
    for s in l.split("."):
        s=s.split()
        while s:x+=["%s==%s"%(m,p())]
k=("knave","knight")
r=[a for a in[{w[0]:z,w[1]:1-z}for z in(0,1)]if all(eval(l,{k[0]:0,k[1]:1},a)for l in x)]
print"\n".join(x+" is the "+k[r[0][x]]+"."for x in w+r[1:])

3

ルビー、352文字

解決策は非常に長くなったので、まだゴルフをする場所があるかもしれません。入力は整形式である必要があります(上記のすべての例がそうであるように-しかし、人を "Both"と名付けようとしないでください...)。

q=->{gets.split /: |\.\s/}
C,*E=q[]
D,*F=q[]
r=->c,m{t=c.shift;t[1]?(x=r[c,m];c.shift;y=r[c,m];t[0]==?B?x&y :t[0]==?E?x^y :1-(x|y)):(c.shift(2);h=c.shift[2]==?I?m : 1-m;t==?I?h :1-h)}
s=->u,v,b{u.map{|c|r[c.gsub(v,?J).upcase.split,b]==b}.all?}
t=->b{s[E,D,b]&&s[F,C,1-b]}
u=->v,b{v+" is the kn#{b ?:ight: :ave}."}
puts t[1]^t[0]&&u[C,t[1]]+$/+u[D,t[0]]

出力ではピリオドを省略しているように見えますが、2文字修正されているようです。
-PhiNotPi

1
@PhiNotPi完了。ゼロ文字修正でした...
ハワード

0

Perl-483バイト

(($a,$b),($c,$d))=map{split':'}@ARGV;$h='y';$i='x';$s=' is the kn';$g='ight.';$v='ave.';for($b,$d){$_.=' 1';s/ am a | is a /==/g;s/knight/1)/g;s/knave/0)/g;s/I=/(\$$i=/g;s/($a|$c)=/(\$$h=/g;s/([^.]+)\./($1)and/g;s/ or / xor /g;s/ nor / or /g;while(s/(?<= )(\w+ \((?:[^()]+|(?1))\) \w+ \((?:[^()]+|(?1))\))/($1)/g){}s/neither/!/gi;s/both|either//gi;$h=$i++}$x=0;$y=1;$k=!eval($b)&&eval($d);$x=$y--;$n=!eval($d)&&eval($b);print"$a$s$v
$c$s$g"if($k&&!$n);print"$a$s$g
$c$s$v"if($n&&!$k)

Pythonソリューションに似ています。文をPerlコードに減らしてから、evalsにします。入力が奇妙な場合はほぼ有効な出力を印刷できますが、決定できない場合は何も印刷しません。整形式の入力は期待どおりに機能します。文はコマンドラインで引用符内に渡され、特別なフラグは必要ありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.