기사와 칼


12

이것은 입니다.

이 도전에서 우리는 " 기사와 칼 "퍼즐 을 해결하는 프로그램 / 기능을 작성합니다 .

배경

당신은 섬에서 자신을 찾을 수 있습니다 ... 당신을 제외하고 섬의 모든 사람은 기사 또는 건달 입니다.

기사는 진실한 진술 만 할 수 있습니다 .

칼은 거짓 진술 만 할 수 있습니다 .

"문장"을 엄격하게 정의하고 싶지는 않지만, "설명"은 "참"또는 "거짓"이라고 말할 것입니다. 여기에는 역설적 문장이 포함되지 않습니다.

이 도전의 목적을 위해, 당신은 섬 주민들을 만나게 될 것입니다. 그들은 당신에게 진술 할 것입니다.

당신의 임무는 누가 기사이고 누가 Knave인지 결정하는 것입니다.

입력:

다음과 같은 정보가 (합리적인 형식으로) 제공됩니다 :

  • 참석 한 사람들의 목록입니다. 대문자 알파벳 "AZ"로 이름이 지정됩니다. 이에 의해 부과되는 인원 수의 한도를 초과하지 않습니다.

  • 각 사람의 진술. 이에 대한 자세한 내용은 아래를 참조하십시오.

산출

그런 다음 각 개인의 내용을 합리적인 형식으로 출력합니다. 예를 들어,이 경우 플레이어했다 A B C DA기사이지만, 나머지 knaves는, 당신은 출력을 할 수

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

중요한 세부 사항 :

  • 대문자 알파벳 문자 AZ는 제도자를 나타냅니다.

  • 문자 0(0) 및 1(1)은 각각 "Knave"및 "Knight"를 나타냅니다. (지정하는 한 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 's Laws를 사용할 수도 있습니다.

  1. 사람 A와 사람 B가 모두 나이프 인 것은 사실이 아닙니다

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

조건에 대한 참고 사항

자세한 내용은 Wikipedia 를 확인하십시오 .

조건문은 p => q 형식을 취하며 , 여기서 pq 는 명령문입니다. p 는 "antecedent"이고 q 는 "consequent"입니다. 여기 유용한 정보가 있습니다

  • 조건의 부정은 다음과 같습니다. ~ (p => q)는 p ^ ~ q와 같습니다.

  • 거짓 전제는 무엇이든 의미합니다. 즉, p 가 false 이면, 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는 Knave입니다.

    B : 그것이 사실이라면, F도 역시 Knave입니다.

대답:

A는 기사, B는 Knave, 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
    

유사한 도전 삼년 분석 및 조건문을 포함하지 않거나 드 모건의에 그 초점을 맞추고 전부터는. 따라서 나는 이것이 속임수를 피하기 위해 초점과 구현이 충분히 다르다고 주장합니다.

이 도전은 속임수로 잠깐 닫혔습니다. 그 후 다시 열렸습니다.

나는이 도전이 우선 초점이 다르다고 주장한다. 다른 과제는 영어 파싱에 중점을 두지 만 그렇지 않습니다. 둘째, AND와 OR 만 사용하는 반면 조건을 사용하고 더 많은 퍼즐을 풀 수 있습니다. 하루가 끝날 무렵, 문제는 그 도전에 대한 답변이이 질문에 대한 사소한 대안으로 대체 될 수 있는지 여부이며, 조건부와 조건부 제외를 포함하면보다 강력한 변경이 순서대로 이루어져야 할만큼 복잡성이 높아진다고 생각합니다 이 도전에 맞습니다.


Knave가 말하면 무엇을 결론을 내릴 수 (B=1)=>(C=0)있습니까? ~((B=1)=>(C=0))또는 (B=1)=>(C=1)다른 것?
njpipeorgan

5 분 이내에는 불가능합니다. 이 문제는 SAT라고하며 복잡성이 기하 급수적으로 증가합니다. 따라서 일반적인 경우 (2 SAT 아님) n = 26 인 경우 적절한 시간에 컴퓨터에서 해결할 수 없습니다.
Labo

첫 번째 테스트 케이스에는 2 가지 출력이 있습니다. 당신이 논리적 사용하고있는 것처럼 OR, 그것은 수 A:1 B:1또는 A:1 B:0B의가 있기 때문에 B=1거짓이 될 수 A는 여전히 사실 일 것입니다 동안.
Katenkyo

@njpipeorgan Knave가 B라면 그는 말할 수 없습니다. 거짓 전제는 무엇이든 암시하므로 그 진술은 사실입니다. Knave가 다른 성격을 가진다면, 당신은 (B=1)^(C=1)조건을 다루는 방법에 따라 부정을 할 것 입니다
Liam

1
궁금한 사람들에게는 실제 문제는 내가 입력 쿼리를보고 그가 단어 퍼즐을보고했기 때문입니다. 즉 수정되었습니다
카메론 Aavik을

답변:


6

파이썬 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수단 각각 기사와 Knaves. 그때

F[characters, statements]

{{q->True, x->False, w->True}}Q와 W가 Knights이고 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}}

이 배열의 첫 번째 열은 화자의 신원이며 두 번째 열은 해당 문장이 참인지 거짓인지를 나타냅니다. 유효한 해결책은 화자의 신원과 진술 사이의 일치가 필요합니다. 위의 배열은 두 번째 스피커 인 Knight가 잘못된 진술을하기 때문에이 조합이 해결책이 아님을 의미합니다.

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

대체를 수행하고 조건을 만족하는 조합을 선택하십시오.


1

루비, 128

이것은 다른 모든 사람들과 같은 알고리즘이며, 가능한 모든 나이프와 기사 조합을 시도하고 어떤 막대기를 봅니다. 나는 다른 일을하고 있지만 더 길어질 것이라고 생각합니다.

명령문 입력은 다음과 같아야합니다.

  • &
  • | 또는
  • == IS
  • ! 아니
  • > 임 플리
  • 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}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.