อัศวินและมีด


12

นี่คือรหัสกอล์ฟ

ในความท้าทายนี้เราจะเขียนโปรแกรม / ฟังก์ชั่นที่แก้ปริศนา " Knights and Knaves "

พื้นหลัง

คุณพบว่าตัวเองบนเกาะ ... ฯลฯ ... ทุกคนบนเกาะยกเว้นสำหรับคุณเป็นทั้งอัศวินหรือคนพาล

อัศวินสามารถสร้างข้อความที่แท้จริงได้เท่านั้น

Knaves สามารถสร้างข้อความเท็จได้เท่านั้น

ฉันไม่ต้องการกำหนด "คำสั่ง" อย่างจริงจัง แต่เราจะพูดว่าข้อความใด ๆ ที่เป็น "จริง" หรือ "เท็จ" โปรดทราบว่าสิ่งนี้ไม่รวมถึงประโยคขัดแย้ง

สำหรับจุดประสงค์ของการท้าทายนี้คุณจะเจอกลุ่มชาวเกาะ พวกเขาจะทำงบกับคุณ

งานของคุณคือการตัดสินว่าใครคืออัศวินและใครเป็นคน knave

การป้อนข้อมูล:

คุณจะได้รับ (ในรูปแบบที่เหมาะสม) ข้อมูลต่อไปนี้:

  • รายการของผู้คนในปัจจุบัน พวกเขาจะถูกตั้งชื่อด้วยตัวอักษรตัวพิมพ์ใหญ่ "AZ" ขีด จำกัด ของจำนวนคนที่กำหนดโดยสิ่งนี้จะไม่เกิน

  • งบที่แต่ละคนทำ ดูด้านล่างสำหรับรายละเอียดที่สำคัญเกี่ยวกับเรื่องนี้

เอาท์พุต

จากนั้นคุณจะแสดงผล (ในรูปแบบที่สมเหตุสมผล) ว่าแต่ละคนคืออะไร ตัวอย่างเช่นหากมีผู้เล่นA B C DและAเป็นอัศวิน แต่ส่วนที่เหลือเป็น knaves คุณสามารถส่งออก

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

รายละเอียดที่สำคัญ:

  • ตัวอักษรตัวพิมพ์ใหญ่ AZ หมายถึงชาวเกาะ

  • อักขระ0(ศูนย์) และ1(หนึ่ง) อ้างอิงถึง "Knave" และ "Knight" ตามลำดับ (คุณสามารถใช้อักขระ AZ อื่นที่ไม่ใช่อักขระสองตัวได้ตราบใดที่คุณระบุ)

  • ชาวเกาะแต่ละคนในปัจจุบันอาจทำให้จำนวนงบธรรมชาติหรืออาจเลือกที่จะพูดอะไร

  • ตัวดำเนินการเชิงตรรกะปกติสามารถใช้ในข้อความสั่ง ( IS *, AND, OR, NOT ) ยิ่งไปกว่านั้นอาจใช้กฎหมายและเงื่อนไขของ De Morgan ต่อไปนี้เป็นตัวอย่างของวิธีที่พวกเขาอาจนำเสนอในตัวต่อพูดแล้วตามด้วยวิธีที่พวกเขาอาจถูกป้อนเข้าสู่โปรแกรม

(* ในหมายเหตุด้านเทคนิคเพิ่มเติมตัวดำเนินการ "IS" ถูกใช้เป็นข้อ จำกัด จริง ๆ (ซึ่งไม่ใช่ตัวดำเนินการเชิงตรรกะ) เมื่อฉันพูดว่า "A is a Knight" ฉันหมายถึง "A เป็นสมาชิกของกลุ่ม Knights "ตัวดำเนินการจริงที่ใช้จะเป็น 'ϵ' เพื่อประโยชน์ของความเรียบง่ายเราจะใช้ '=' แทน)

ฉันใช้สิ่งต่อไปนี้ (คุณสามารถใช้อะไรก็ได้ตราบใดที่มันสมเหตุสมผลและสอดคล้องกัน):

  • ^ และ
  • v หรือ
  • = คือ
  • ~ ไม่
  • => IMPLIES
  • X:Person Xอ้างว่า ...

Person Zสามารถสร้างชุดคำสั่งประเภทใด ๆ ต่อไปนี้:

Person Zบอกว่า ...

  1. บุคคลAคืออัศวิน

    Z: A = 1

  2. Person Qคือ Knave

    Z: Q = 0

  3. ฉันเป็นอัศวิน

    Z: Z = 1

  4. บุคคลAคืออัศวินหรือบุคคลBคืออัศวิน

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

  5. Person Cคือ Knight และฉันเป็น Knave

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

  6. Person Rไม่ใช่อัศวิน

    Z: ~( R = 1 )

ยิ่งไปกว่านั้นข้อมูลอาจใช้กฎของ De Morgan ด้วย

  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 เป็นผู้มีความรู้

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

หมายเหตุเกี่ยวกับเงื่อนไข

ตรวจสอบวิกิพีเดียสำหรับข้อมูลเพิ่มเติม

คำสั่งแบบมีเงื่อนไขใช้แบบฟอร์มp => qโดยที่pและqเป็นคำสั่งของตัวเอง pคือ "บรรพบุรุษ" และqคือ "สืบเนื่อง" นี่คือข้อมูลที่เป็นประโยชน์บางอย่าง

  • การปฏิเสธเงื่อนไขมีลักษณะดังนี้: ~ (p => q) เทียบเท่ากับ p ^ ~ q

  • หลักฐานเท็จหมายถึงอะไร นั่นคือ: ถ้าpเป็นเท็จดังนั้นข้อความใด ๆp => qนั้นเป็นจริงโดยไม่คำนึงว่าqคืออะไร ตัวอย่างเช่น: "if 2 + 2 = 5 ดังนั้นฉันคือ Spiderman" เป็นข้อความจริง

กรณีทดสอบง่ายๆ

กรณีเหล่านี้จะได้รับในลักษณะดังต่อไปนี้ (1) วิธีที่เราจะทำให้เกิดปัญหาในการพูด (2) วิธีที่เราอาจวางลงในคอมพิวเตอร์ (3) ผลลัพธ์ที่ถูกต้องที่คอมพิวเตอร์อาจให้

  1. Person A และ Person 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 เข้าหาคุณบนท้องถนนและทำข้อความต่อไปนี้:

    ตอบ: ถ้าฉันเป็นอัศวิน B จะเป็นผู้มีไหวพริบ

    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 เป็น Knights

    ถาม: นั่นเป็นเรื่องจริง

    X: ถ้าสิ่งที่ W พูดว่าเป็นจริงดังนั้นสิ่งที่ Q พูดว่าเป็นเท็จ

ตอบ:

W และ Q คือ Knights X คือ Knave

อินพุต

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

เอาท์พุต


    W = 1
    Q = 1
    X = 0
    

มี ความท้าทายที่คล้ายกันจาก 3 ปีที่ผ่านมาซึ่งมุ่งเน้นไปที่การแยกวิเคราะห์และไม่ได้มีเงื่อนไขหรือเดมอร์แกน ดังนั้นฉันจะเถียงว่ามีความแตกต่างในการมุ่งเน้นและการนำไปปฏิบัติเพื่อหลีกเลี่ยงปัญหานี้

ความท้าทายนี้ถูกปิดชั่วครู่เป็นผู้ล่อลวง มันถูกเปิดใหม่อีกครั้ง

ฉันอ้างว่าความท้าทายนี้แตกต่างกันไปก่อน ความท้าทายอื่น ๆ มุ่งเน้นไปที่การแยกวิเคราะห์ภาษาอังกฤษสิ่งนี้ไม่ได้ อันดับที่สองใช้เพียง AND และหรือในขณะที่ใช้เงื่อนไขและช่วยให้การแก้ปริศนาอีกมากมาย ในตอนท้ายของวันคำถามคือว่าคำตอบจากความท้าทายนั้นสามารถทดแทนได้เล็กน้อยกับสิ่งนี้หรือไม่และฉันเชื่อว่าการรวมเงื่อนไขและการปฏิเสธตามเงื่อนไขเพิ่มความซับซ้อนเพียงพอที่จะต้องมีการเปลี่ยนแปลงที่แข็งแกร่งมากขึ้น เพื่อให้เหมาะกับความท้าทายนี้


สิ่งที่เราสามารถสรุปได้ถ้าคนพาลกล่าวว่า(B=1)=>(C=0)? ~((B=1)=>(C=0))หรือ(B=1)=>(C=1)อย่างอื่น?
njpipeorgan

ไม่สามารถทำได้ภายใน 5 นาที ปัญหานี้เป็นที่รู้จักกันในชื่อ SAT และมีความซับซ้อนในการชี้แจง ดังนั้นสำหรับ n = 26 ในกรณีทั่วไป (ไม่ใช่ 2 SAT) จึงเป็นไปไม่ได้ที่จะแก้ไขในคอมพิวเตอร์ในเวลาที่เหมาะสม
Labo

กรณีทดสอบครั้งแรกของคุณมี 2 เอาต์พุตที่เป็นไปได้ ในขณะที่คุณกำลังใช้ตรรกะORมันอาจเป็นเพราะA:1 B:1หรือA:1 B:0ว่า B B=1เป็นเท็จในขณะที่ A ก็ยังเป็นจริง
Katenkyo

@njpipeorgan ถ้าผู้เป็น Kn คือ B เขาไม่สามารถพูดได้ หลักฐานเท็จหมายถึงอะไรและดังนั้นคำสั่งนั้นจะเป็นจริง ถ้าคน Knave เป็นตัวละครที่แตกต่างออกไปคุณจะต้องถูกปฏิเสธซึ่งเป็นไป(B=1)^(C=1)ตามเงื่อนไขของการรับมือกับสถานการณ์โดยทั่วไป
Liam

1
สำหรับผู้ที่สงสัยว่าปัญหาที่แท้จริงคือเพราะฉันกำลังดูที่การป้อนข้อมูลและเขาก็มองปริศนาคำศัพท์ ที่ได้รับการแก้ไข
Cameron Aavik

คำตอบ:


6

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

นอกจากนี้โซลูชันที่สองต้องการ 3.5 (ไม่ใช่ 3.4) เนื่องจากการใช้PEP 448


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

ที่ไหนTrueและFalseหมายถึงอัศวินและ Knaves ตามลำดับ แล้วก็

F[characters, statements]

จะให้{{q->True, x->False, w->True}}ซึ่งหมายความว่ามีทางออกเดียวที่ Q และ W เป็น Knights ในขณะที่ X คือ Knave หากมีมากกว่าหนึ่งวิธีทางออกจะมีลักษณะ{{...},{...},...}


อัลกอริทึมง่ายมาก {True,False}~Tuples~Length@cให้การรวมกันที่เป็นไปได้ของ Knights and Knaves ระหว่างตัวละคร จากนั้น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}}

คอลัมน์แรกของอาเรย์นี้คือตัวตนของผู้พูดและคอลัมน์ที่สองระบุว่าข้อความนั้นเป็นจริงหรือเท็จ วิธีการแก้ปัญหาที่ถูกต้องต้องการความสอดคล้องระหว่างตัวตนของผู้พูดและคำพูดของพวกเขา อาร์เรย์ด้านบนหมายความว่าชุดค่าผสมนี้ไม่ใช่วิธีการแก้ปัญหาเนื่องจากลำโพงตัวที่สองคืออัศวินทำให้คำสั่งไม่ถูกต้อง

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

การทดแทนและเลือกชุดค่าผสมที่ตรงตามเงื่อนไข


1

ทับทิม, 128

นี่เป็นอัลกอริธึมเดียวกับทุกคนลองชุด knaves และ knights ที่เป็นไปได้ทั้งหมดแล้วดูว่าแท่งไหน ฉันมีอีกอันที่ฉันกำลังทำงานอยู่ แต่ฉันคิดว่ามันจะนานกว่า (แม้ว่าจะน่าสนใจกว่า)

อินพุตข้อความสั่งต้องเป็น:

  • & และ
  • | หรือ
  • == คือ
  • ! ไม่
  • > IMPLIES
  • X: Person 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.