Hiệp sĩ và Knaves


12

Đây là .

Trong thử thách này, chúng tôi sẽ viết các chương trình / chức năng giải câu đố " Hiệp sĩ và Knaves ".

Lý lịch

Bạn thấy mình ở trên một hòn đảo ... vv ... mỗi người trên đảo ngoại trừ bạn là một hiệp sĩ hoặc một tay đấm .

Hiệp sĩ chỉ có thể đưa ra tuyên bố đúng .

Knaves chỉ có thể đưa ra tuyên bố sai .

Tôi không muốn định nghĩa chặt chẽ "tuyên bố", nhưng chúng tôi sẽ nói rằng một tuyên bố là bất cứ điều gì là "đúng" hoặc "sai". Lưu ý rằng điều này không bao gồm các câu nghịch lý.

Với mục đích của thử thách này, bạn sẽ bắt gặp những nhóm người dân đảo; họ sẽ tuyên bố với bạn

Nhiệm vụ của bạn là xác định ai là Hiệp sĩ và ai là Knave.

Đầu vào:

Bạn sẽ được cung cấp (ở bất kỳ định dạng hợp lý nào) các thông tin sau:

  • Một danh sách những người có mặt. Chúng sẽ được đặt tên bằng các ký tự chữ cái in hoa "AZ". Giới hạn về số lượng người áp đặt bởi điều này sẽ không được vượt quá.

  • Những tuyên bố mà mỗi người đưa ra. Xem bên dưới để biết chi tiết quan trọng về điều này.

Đầu ra

Sau đó, bạn sẽ xuất (ở bất kỳ định dạng hợp lý) mỗi người là gì. Ví dụ: nếu có người chơi A B C DAlà hiệp sĩ, nhưng phần còn lại là nô lệ, bạn có thể xuất

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

Chi tiết quan trọng:

  • Ký tự chữ cái chữ hoa AZ đề cập đến người dân đảo.

  • Các ký tự 0(không) và 1(một) tương ứng là "Knave" và "Knight". (Bạn có thể có bất kỳ hai ký tự không phải AZ nào khác, miễn là bạn chỉ định)

  • Mỗi người dân đảo có thể đưa ra bất kỳ số lượng tuyên bố tự nhiên nào, hoặc có thể chọn không nói gì.

  • Các toán tử logic thông thường có thể được sử dụng trong các câu lệnh ( IS *, AND, OR, NOT ). Trên hết, LuậtĐiều kiện của De Morgan có thể được sử dụng. Sau đây là những ví dụ về cách chúng có thể được trình bày trong một câu đố nói tiếp theo là cách chúng có thể được đưa vào chương trình của bạn.

(* trên một ghi chú kỹ thuật hơn. Toán tử "IS" thực sự được sử dụng như ngăn chặn (không phải là toán tử logic). Hiệp sĩ ". Toán tử thực sự được sử dụng sẽ là ''. Để đơn giản, thay vào đó chúng tôi sẽ sử dụng '='.)

Tôi sử dụng như sau (bạn có thể sử dụng bất cứ điều gì, miễn là hợp lý và nhất quán):

  • ^
  • v HOẶC LÀ
  • =
  • ~ KHÔNG PHẢI
  • => HÌNH ẢNH
  • X:Người X tuyên bố rằng ...

Người Z có thể thực hiện bất kỳ kết hợp nào của bất kỳ loại câu lệnh nào sau đây:

Người Z nói rằng ...

  1. Người A là một Hiệp sĩ.

    Z: A = 1

  2. Người Q là một Knave.

    Z: Q = 0

  3. Tôi là một Hiệp sĩ.

    Z: Z = 1

  4. Người A là Hiệp sĩ HOẶC Người B là Hiệp sĩ.

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

  5. Người C là một Hiệp sĩ VÀ Tôi là một Knave.

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

  6. Người R KHÔNG phải là Hiệp sĩ.

    Z: ~( R = 1 )

Trên hết, đầu vào cũng có thể sử dụng Luật của De Morgan

  1. Không đúng khi cả người A và người B đều là người biết

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

  2. Đó là sai khi một trong hai người A hoặc người B là một Hiệp sĩ

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

Cuối cùng, điều kiện và phủ định của chúng có thể được sử dụng

  1. Nếu tôi là Hiệp sĩ, thì người B là Knave

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

  2. Không đúng nếu người B là Hiệp sĩ, thì Người C là Knave.

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

Ghi chú về điều kiện

Kiểm tra wikipedia để biết thêm.

Một câu lệnh có điều kiện có dạng p => q , trong đó pq là các câu lệnh. p là "tiền đề" và q là "hệ quả". Đây là một số thông tin hữu ích

  • Phủ định của một điều kiện trông như thế này: ~ (p => q) tương đương với p ^ ~ q

  • Một tiền đề sai lầm ngụ ý bất cứ điều gì. Đó là: nếu p sai, thì bất kỳ câu p => q nào cũng đúng, bất kể q là gì . Ví dụ: "nếu 2 + 2 = 5 thì tôi là Người nhện" là một tuyên bố đúng.

Một số trường hợp kiểm tra đơn giản

Những trường hợp này được đưa ra theo kiểu sau (1) về cách chúng ta đặt vấn đề trong lời nói (2) làm thế nào chúng ta có thể đặt nó vào máy tính (3) đầu ra chính xác mà máy tính có thể đưa ra.

  1. Người A và Người B tiếp cận bạn trên đường và đưa ra các tuyên bố sau:

    A: B là một knave hoặc tôi là một hiệp sĩ.

    B: A là một hiệp sĩ.

Câu trả lời:

B là Hiệp sĩ và A là Hiệp sĩ.

Đầu vào:

A B        # Cast of Characters
A: ( B = 0 ) v ( A = 1)
B: A = 1

Đầu ra:


    A = 1
    B = 1
    

  1. Người A, B và F tiếp cận bạn trên đường và đưa ra các tuyên bố sau:

    A: Nếu tôi là Hiệp sĩ, thì B là Knave.

    B: Nếu đó là sự thật, thì F cũng là một Knave.

Câu trả lời:

A là Hiệp sĩ, B là Knave, F là Hiệp sĩ.

Đầu vào

A B F
A: ( A = 1 ) => ( B = 0 )
B: ( A = 1 ) => ( F = 0 ) 

Đầu ra:


    A = 1
    B = 0
    F = 1
    

  1. Q, X và W tiếp cận bạn trên đường và đưa ra các tuyên bố sau:

    W: Không đúng khi cả Q và X đều là Hiệp sĩ.

    Q: Đó là sự thật.

    X: Nếu những gì W nói là đúng, thì những gì Q nói là sai.

Câu trả lời:

W và Q là Hiệp sĩ. X là một Knave.

Đầu vào

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

Đầu ra


    W = 1
    Q = 1
    X = 0
    

Có một thách thức tương tự từ 3 ​​năm trước, tập trung vào phân tích cú pháp và không chứa các điều kiện hoặc De Morgan. Và do đó, tôi sẽ tranh luận, là đủ khác biệt trong tập trung và thực hiện để tránh điều này là một bản sao.

Thử thách này đã được đóng lại trong một thời gian ngắn như một bản dupe. Nó đã được mở lại.

Tôi cho rằng thử thách này trước hết là khác biệt về trọng tâm. Các thách thức khác tập trung vào phân tích tiếng Anh, điều này không. Thứ hai, nó chỉ sử dụng AND và OR trong khi điều này sử dụng các điều kiện và cho phép giải nhiều câu đố hơn. Vào cuối ngày, câu hỏi là liệu câu trả lời từ thử thách đó có thể được thay thế một cách tầm thường cho vấn đề này hay không, và tôi tin rằng việc bao gồm các điều kiện và phủ định có điều kiện sẽ làm tăng thêm sự phức tạp mà cần phải thực hiện các thay đổi mạnh mẽ hơn theo thứ tự để phù hợp với thử thách này.


Chúng ta có thể kết luận điều gì nếu một Knave nói (B=1)=>(C=0)? ~((B=1)=>(C=0))hay (B=1)=>(C=1)cái gì khác?
njpipe tổ chức

Điều này là không thể làm trong vòng chưa đầy 5 phút. Vấn đề này được gọi là SAT, và theo cấp số nhân về độ phức tạp. Do đó, với n = 26 trong trường hợp chung (không phải 2 SAT), không thể giải quyết trên máy tính trong thời gian hợp lý.
Labo

Trường hợp thử nghiệm đầu tiên của bạn có 2 đầu ra có thể. Như bạn đang sử dụng logic OR, nó có thể A:1 B:1hoặc A:1 B:0bởi vì B B=1có thể sai trong khi A vẫn đúng.
Katenkyo

@njpipe Organ Nếu Knave là B, anh ta không thể nói điều đó. Một tiền đề sai hàm ý bất cứ điều gì và do đó tuyên bố đó sẽ là đúng. Nếu Knave là một nhân vật khác, bạn sẽ có phủ định, đó là (B=1)^(C=1)theo cách các điều kiện thường được xử lý
Liam

1
Đối với những người thắc mắc, vấn đề thực sự là bởi vì tôi đang xem truy vấn đầu vào và anh ta đang nhìn vào câu đố chữ. Điều đó đã được khắc phục
Cameron Aasta 16/2/2016

Câu trả lời:


6

Python 3, 450 342 307 byte

Chỉnh sửa: hóa ra tôi đã quên nhập ...

Giải pháp đầu tiên của tôi tận dụng việc đặt tên linh hoạt cho các truy vấn

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

Bạn có thể gọi một ở trên với

g('Q X W', ['W: not( ( Q == 1 ) and ( X == 1 ) )','Q: W == 1', 'X: ( W == 1 ) -> ( Q == 0 )'])

Cái tiếp theo ở đây sử dụng cùng một định dạng truy vấn như đã thấy trong OP, nó cũng không có một số sửa đổi tôi đã thực hiện cho cái đầu tiên. Nó là 417 byte vì nó chuyển đổi giữa hai định dạng.

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

Và nó có thể được gọi bởi:

g('Q X W', ['W: ~( ( Q = 1 ) ^ ( X = 1 ) )','Q: W = 1', 'X: ( W = 1 ) => ( Q = 0 )'])

Cả hai trở về

[{'X': 0, 'W': 1, 'Q': 1}]

Giải thích lộn xộn:

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

Ngoài ra, giải pháp thứ hai cần 3,5 (không phải 3,4) do sử dụng PEP 448


1

Toán học, 80 byte

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

Giải trình

Hàm Fcó hai đối số,

  • c là danh sách tên của tất cả các nhân vật,
  • s là một danh sách các câu lệnh, mỗi câu có hai phần - ai nói gì.

Ví dụ: có ba ký tự, Q, X và W.

characters={q,x,w};

Và họ nói,

statements=
   {{w, !((q==True)&&(x==True))   },
    {q, w==True                   },
    {x, Implies[w==True,q==False] }};

trong đó TrueFalsecó nghĩa là Hiệp sĩ và Knaves tương ứng. Sau đó

F[characters, statements]

sẽ đưa ra {{q->True, x->False, w->True}}, điều đó có nghĩa là chỉ có một giải pháp mà Q và W là Hiệp sĩ trong khi X là Knave. Nếu có nhiều hơn một giải pháp, đầu ra sẽ như thế nào{{...},{...},...}


Thuật toán rất đơn giản. {True,False}~Tuples~Length@cđưa ra tất cả các kết hợp có thể có của Hiệp sĩ và Knaves giữa các nhân vật. Sau đó Thread[c->#]&/@xây dựng một loạt các quy tắc dựa trên các kết hợp này. Trong trường hợp có hai ký tự A và B, mảng sẽ là

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

Thay thế các câu lệnh bằng một hàng của các quy tắc này, chúng ta sẽ nhận được một mảng trông giống như

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

Cột đầu tiên của mảng này là danh tính của người nói và cột thứ hai cho biết tuyên bố của họ là đúng hay sai. Một giải pháp hợp lệ đòi hỏi sự phù hợp giữa danh tính của người nói và tuyên bố của họ. Mảng trên có nghĩa là sự kết hợp này không phải là một giải pháp, vì người nói thứ hai, một Hiệp sĩ, đưa ra một tuyên bố không chính xác.

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

không thay thế và chọn những kết hợp thỏa mãn điều kiện.


1

Ruby, 128

Đây là thuật toán giống như mọi người khác, hãy thử tất cả các kết hợp có thể có của hiệp sĩ và hiệp sĩ và xem gậy nào. Tôi có một cái khác mà tôi đang làm việc, nhưng tôi nghĩ nó sẽ dài hơn (mặc dù thú vị hơn).

Các đầu vào câu lệnh phải là:

  • &
  • | HOẶC LÀ
  • ==
  • ! KHÔNG PHẢI
  • > HÌNH ẢNH
  • X: Người X tuyên bố rằng ...

Tôi cũng yêu cầu mỗi câu lệnh và câu lệnh con phải nằm trong ngoặc đơn. Vấn đề duy nhất với phiên bản này là nó trải qua tối đa 2 ^ 26 lần lặp và nếu chúng không phải là tất cả các nút, thì ít nhất là 2 ^ (26-n) lần lặp ! Để đặt điều đó trong viễn cảnh, điều đó có nghĩa là nếu có hai người, và ít nhất một người không phải là một tay sai, sẽ mất tối thiểu 16.777.216 lần lặp !

Để hạn chế điều đó, tôi gửi sau đây ở 168 byte. Sub trong 26cho #{o.size}cắt nó trở lại 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}

Nhưng nếu tôi có thể sử dụng một mảng người và bản đồ các câu lệnh, ví dụ:

c[[?A, ?B],
  {
    ?A=> "( B == 0 ) | ( A == 1)",
    ?B=> "A == 1"
  }
 ]

Sau đó, tôi nhận được nó xuống 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}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.