코드 골프 : 영어를 파싱하여 기사와 나이프 논리 문제 해결


16

배경

Bill과 John의 두 사람이 있습니다. 그들 중 하나는 항상 진실을 말하는 기사이고, 다른 하나는 항상 거짓말을하는 칼입니다. 당신은 누가 기사이고 누가 칼인지 모릅니다. 그런 다음 각 사람은 누가 칼과 누가 기사인지에 대해 몇 가지 진술을합니다. 이 정보를 사용하여 누가 기사인지, 누가 건달인지에 대해 결론을 내려야합니다.

기사와 Knaves 로직 문제는 Booleen 대수를 기반으로합니다. 사람이 말하는 단어는 Booleen 만족도 문제를 형성합니다. Knave의 진술은 항상 거짓이어야하고 다른 기사의 진술은 항상 참이어야합니다.

존은 "내가 건달이고 빌은 건달이다"고 말합니다. 요한이 기사라면,이 진술은 거짓이되어 기사가 될 수 없습니다. 그가 건달이고 빌이 기사 였다면,이 진술은 여전히 ​​틀렸을 것입니다. 심지어 첫 번째 부분이 사실이라고 생각했습니다. 요한은 건달입니다.

도전

당신의 도전은 가능한 한 가장 짧은 프로그램을 작성하여 각 사람이 작성한 진술 목록을 취하고 누가 칼과 기사인지 알아내는 것입니다. 다룰 세부 사항이 많으므로이 문제는 세 가지 섹션으로 설명됩니다.

입력

입력은 두 줄에 이어 줄 바꿈이됩니다. 각 줄에는 문자 중 하나의 이름, 콜론, 그 사람이 말한 여러 문장이 표시됩니다. 한 사람이 기사라면 그의 모든 문장은 사실이되고 모든 건달의 문장은 거짓이됩니다. 문장의 첫 글자는 항상 대문자로 표시되며 모든 문장은 마침표로 끝납니다. 예를 들면 다음과 같습니다.

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.

파싱

각 문장은 하나 이상의 절로 구성됩니다. 각 절에는 몇 가지 사항 중 하나가 포함되어 있습니다 (내 생각에 따라 내 표기법을 이해할 수 있음).

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.

Booleen 대수로의 번역은 간단합니다. "둘 다"문은 AND이고 "둘 중 하나"문은 XOR이고 "둘 다"문은 NOR입니다.

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

산출

출력은 두 줄로 구성됩니다. 각 줄은 사람의 이름 (순서대로)으로 구성되어 있으며 기사인지 건반인지를 말합니다. 기사와 칼 하나가 항상 있습니다. 위 예제의 결과는 다음과 같습니다.

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.

하나의 가능한 출력

Rock Paper Scissors

규칙, 규정 및 참고 사항

  1. 표준 코드 골프 규칙이 적용됩니다
  2. 프로그램은 인쇄 가능한 ASCII로만 구성되어야합니다.
  3. 모든 입력 및 출력은 STDIN 및 STDOUT에서

대소 문자 구분은 어떻습니까? 구문 설명은 소문자이고 예제는 대문자입니다. 대소 문자를 구분하지 않아도됩니까?
ugoren

각 문장의 첫 글자는 대문자를 사용하지만 그 이외의 이름은 대문자를 사용합니다. 어떤 구체적인 문제가 있습니까?
PhiNotPi

올바른 영어 대문자를 사용하기 때문에 두 글자 모두 첫 글자는 문맥에 따라 다릅니다. 대소 문자를 구분하지 않는 것이 처리하기 쉬운 방법이라고 생각합니다.
ugoren

답변:


6

파이썬, 491 자

각 줄을 파이썬 표현식으로 변환하고 그것을 풀어서 작동합니다.
칼과 기사는 0과 1로 평가됩니다. 두 사람은 두 가지 옵션을 모두 시도합니다.
예를 들어, Joe: Steve is a knave진다Joe==(Steve==knave) . 이런 식으로, Joe건달 인 경우 거짓말을하는 경우에만 결과가 적용됩니다.
불가능하거나 결정되지 않은 경우 추악한 오류가 발생합니다. 불가능한 경우 비어 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 자

이 솔루션은 상당히 길어 졌으므로 여전히 골프장이있을 수 있습니다. 입력의 형식이 양호해야합니다 (위의 모든 예가 있듯이 사람 이름을 "모두"로 지정하지 마십시오).

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

출력에서 마침표를 남기는 것처럼 보이지만 두 문자 수정으로 보입니다.
PhiNotPi

1
@PhiNotPi 완료했습니다. 제로 문자 수정되었습니다 ...
Howard

0

펄-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)

파이썬 솔루션과 비슷합니다. 문장을 Perl 코드로 줄이고 evals로 바꿉니다. 입력이 이상하면 거의 유효한 출력을 인쇄 할 수 있지만 결정할 수없는 경우 아무것도 인쇄하지 않습니다. 올바른 형식의 입력이 예상대로 작동합니다. 문장은 명령 행에서 따옴표 안에 전달되며 특별한 플래그는 필요하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.