Code golf: Giải quyết vấn đề logic của Hiệp sĩ và Knaves bằng cách phân tích tiếng Anh


16

Lý lịch

Có hai người, Bill và John. Một trong số họ là một hiệp sĩ, người luôn nói sự thật, và người kia là một tay sai, luôn nói dối. Bạn không biết ai là hiệp sĩ và ai là người biết điều. Mỗi người sau đó nói một vài câu về ai là người biết hiệp sĩ và ai là hiệp sĩ. Sử dụng thông tin này, bạn phải đi đến kết luận ai là hiệp sĩ và ai là người biết điều.

Bài toán logic của Hiệp sĩ và Knaves dựa trên đại số Booleen. Những từ mà một người nói tạo thành một vấn đề thỏa mãn Booleen. Các tuyên bố của knave phải luôn luôn sai và các tuyên bố của hiệp sĩ khác phải luôn luôn đúng.

John nói "Cả hai tôi là một knave và Bill là một knave". Nếu John là hiệp sĩ, thì tuyên bố này sẽ sai, vì vậy anh ta không thể là hiệp sĩ. Nếu anh ta là tay sai và Bill là hiệp sĩ, tuyên bố này vẫn sẽ sai, thậm chí còn nghĩ phần đầu tiên là đúng. Vì vậy, John là người biết điều.

Các thách thức

Thử thách của bạn là viết chương trình ngắn nhất có thể, sẽ lấy một danh sách các tuyên bố của mỗi người và sẽ tìm ra ai là người biết điều và ai là hiệp sĩ. Có rất nhiều chi tiết để đề cập, vì vậy vấn đề này được mô tả trong ba phần.

Đầu vào

Đầu vào sẽ là hai dòng theo sau là một dòng mới. Mỗi dòng sẽ cho biết tên của một trong các ký tự, theo sau là dấu hai chấm, theo sau là một vài câu được nói bởi người đó. Nếu một người là hiệp sĩ, thì tất cả các câu của anh ta sẽ là đúng, và tất cả các câu của knave sẽ là sai. Chữ cái đầu tiên của câu sẽ luôn được viết hoa và mỗi câu sẽ kết thúc bằng một dấu chấm. Đây là một ví dụ:

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.

Phân tích cú pháp

Mỗi câu bao gồm ít nhất một mệnh đề. Mỗi mệnh đề chứa một trong một số điều (hy vọng bạn có thể hiểu ký hiệu của tôi):

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

Điều này là phi tôn giáo vì nó có thể được hiểu theo cách tương tự như ký hiệu Ba Lan. Đây là một ví dụ về một câu:

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

Việc dịch sang đại số Booleen rất đơn giản. Câu lệnh "cả hai" là AND, câu lệnh "hoặc" là XOR và câu lệnh "không" là NOR.

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

Đầu ra

Đầu ra sẽ bao gồm hai dòng. Mỗi dòng bao gồm tên của một người (theo thứ tự) và sau đó cho biết anh ta là hiệp sĩ hay hiệp sĩ. Sẽ luôn có một hiệp sĩ và một hiệp sĩ. Đây là đầu ra cho ví dụ trên:

Joe is the knave.
Steve is the knight.

Nếu vấn đề không thể giải quyết được (bạn không thể biết ai là ai hoặc không có giải pháp nào), thì chương trình của bạn có thể làm bất cứ điều gì NGOẠI TRỪ tạo ra một đầu ra hợp lệ.

Thêm ví dụ

Đầu vào

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.

Đầu ra

Sir Lancelot is the knight.
Merlin is the knave.

Đầu vào

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.

Đầu ra

David is the knave.
Patrick is the knight.

Đầu vào

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

Một đầu ra có thể

Rock Paper Scissors

Quy tắc, quy định và ghi chú

  1. Luật golf tiêu chuẩn được áp dụng
  2. Chương trình của bạn phải được tạo thành từ ASCII có thể in được
  3. Tất cả đầu vào và đầu ra sẽ từ STDIN và STDOUT

Còn trường hợp nhạy cảm thì sao? Mô tả cú pháp của bạn là chữ thường, ví dụ của bạn là chữ hoa. Là trường hợp không nhạy cảm là một yêu cầu?
ugoren

Chữ cái đầu tiên của mỗi câu sẽ được viết hoa, nhưng ngoài tên đó chỉ được viết hoa. Vấn đề cụ thể bạn đang nhìn thấy là gì?
PhiNotPi

Vì bạn sử dụng viết hoa tiếng Anh đúng, chữ cái đầu tiên trong cả hai hoặc / không phụ thuộc vào ngữ cảnh. Tôi đoán là không phân biệt chữ hoa chữ thường là cách dễ dàng để đối phó với nó.
ugoren

Câu trả lời:


6

Python, 491 ký tự

Hoạt động bằng cách chuyển đổi từng dòng thành biểu thức Python và hiển thị nó.
Hiệp sĩ và hiệp sĩ được đánh giá là 0 và 1. Đối với hai người, chúng tôi thử cả hai tùy chọn.
Ví dụ, Joe: Steve is a knavetrở thành Joe==(Steve==knave). Bằng cách này, nếu Joelà một tay đấm, kết quả chỉ đúng nếu anh ta nói dối.
Bạn nhận được lỗi xấu khi nó không thể hoặc chưa quyết định. Nếu không thể, r[0]là một lỗi chỉ mục, bởi vì rtrống rỗng. Nếu không thể giải quyết được, việc nối r[1:]vào một danh sách các chuỗi gây ra sự cố.

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

Ruby, 352 ký tự

Giải pháp trở nên khá dài nên vẫn có thể có chỗ để chơi gôn. Nó đòi hỏi đầu vào phải được định dạng tốt (như tất cả các ví dụ ở trên - nhưng đừng cố đặt tên cho một người là "Cả hai" ...).

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

Bạn dường như bỏ đi các dấu chấm trong đầu ra, nhưng có vẻ như là sửa hai ký tự.
PhiNotPi

1
@PhiNotPi Xong. Đã sửa lỗi không có ký tự ...
Howard

0

Perl - 483 byte

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

Tương tự như giải pháp Python. Nó giảm các câu thành mã Perl và sau đó evals chúng. Nó có thể in đầu ra gần như hợp lệ nếu đầu vào là lạ nhưng không in bất cứ thứ gì nếu không thể xác định được. Đầu vào được hình thành tốt như mong đợi. Các câu được truyền vào dòng lệnh bên trong dấu ngoặc kép và không cần cờ đặc biệt.

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.