Şövalyeler ve Knaves


12

Bu .

Bu meydan okumada, " Şövalyeler ve Knaves " bulmacalarını çözen programlar / fonksiyonlar yazacağız .

Arka fon

Kendinizi bir adada buluyorsunuz ... vs. ... sizden başka adadaki herkes bir şövalye ya da bir knave .

Şövalyeler sadece gerçek ifadeler yapabilir .

Bıçaklar yalnızca yanlış ifadeler yapabilir .

"İfade" yi titizlikle tanımlamak istemiyorum ama bir ifadenin "doğru" veya "yanlış" olan herhangi bir şey olduğunu söyleyeceğiz. Bunun paradoksal cümleleri içermediğini unutmayın.

Bu meydan okuma için, adalı gruplarına rastlayacaksınız; size açıklama yapacaklardır.

Göreviniz kimin şövalye olduğunu ve kimin knave olduğunu belirlemektir.

Giriş:

Size (makul biçimlerde) aşağıdaki bilgiler verilecektir:

  • Mevcut insanların bir listesi. Büyük harfli alfabe karakterleri "AZ" olarak adlandırılacaktır. Bunun getirdiği kişi sayısındaki sınır aşılmayacaktır.

  • Her insanın yaptığı açıklamalar. Bununla ilgili önemli ayrıntılar için aşağıya bakın.

Çıktı

Daha sonra, her kişinin ne olduğunu (herhangi bir makul formatta) çıkartabilirsiniz. Örneğin, oyuncular varsa A B C Dve Abir şövalyeyse, ama geri kalanlar bıçaksa,

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

Önemli ayrıntılar:

  • Büyük alfabe karakterleri AZ adalılara atıfta bulunur.

  • 0(Sıfır) ve 1(bir) karakterleri sırasıyla bir "Knave" ve "Knight" anlamına gelir. (Belirttiğiniz sürece diğer iki AZ olmayan karakteri de kullanabilirsiniz)

  • Mevcut her adalı doğal sayıda ifade yapabilir veya hiçbir şey söylememeyi seçebilir.

  • Normal mantıksal işleçler ifadelerde kullanılabilir ( IS *, AND, OR, NOT ). Bunun üzerine De Morgan Yasaları ve Şartları da kullanılabilir. Aşağıda, sözlü bir bulmacada nasıl sunulabileceğine ve ardından programınıza nasıl girilebileceğine ilişkin örnekler verilmiştir.

(* daha teknik bir notta. "IS" operatörü gerçekten sınırlama olarak kullanılır (bu mantıksal bir operatör değildir). "A bir şövalye" derken, gerçekten de "A, Şövalyeler ". Kullanılan gerçek işleç 'ϵ' olurdu. Sadelik için bunun yerine '=' kullanacağız.)

Aşağıdakileri kullanıyorum (makul ve tutarlı olduğu sürece kullanabilirsiniz):

  • ^ VE
  • v VEYA
  • = DIR-DİR
  • ~ DEĞİL
  • => GELMEKTEDİR
  • X:Kişi X iddia ...

Kişi Z tabloların aşağıdaki türlerden herhangi bir kombinasyon yapabiliriz:

Kişi Z diyor ki ...

  1. Kişi A Şövalyesi olduğunu.

    Z: A = 1

  2. Kişi Q bir Knave'dir.

    Z: Q = 0

  3. Ben bir şövalyeyim.

    Z: Z = 1

  4. Kişi A Şövalyedir VEYA Kişi B Şövalyedir.

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

  5. Kişi C Şövalyesi olduğunu VE ben Knave değilim.

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

  6. Kişi R Şövalyesi değil.

    Z: ~( R = 1 )

Bunun da ötesinde, girdi De Morgan Yasalarını da kullanabilir

  1. Hem A kişisinin hem de B kişisinin bıçak olduğu doğru değildir.

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

  2. A kişisi veya B kişisinin bir şövalye olması yanlıştır

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

Son olarak, şartlar ve olumsuzlamaları kullanılabilir

  1. Eğer bir şövalyeysem, o zaman B kişisi bir Knave'dir

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

  2. Eğer B kişisi bir Şövalye ise, o zaman C Kişisinin bir Knave olduğu doğru değildir.

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

Şartlı notlar

Daha fazla bilgi için wikipedia'ya göz atın .

Koşullu bir ifade p => q şeklindedir ; burada p ve q ifadelerdir. p "öncül" ve q "sonuç" dur . İşte bazı yararlı bilgiler

  • Bir koşulun reddi şuna benzer: ~ (p => q) p ^ ~ q ile eşdeğerdir

  • Sahte bir öncül her şeyi ima eder. Şudur: eğer p yanlıştır, sonra herhangi bir açıklamada p => q olursa olsun ne doğrudur, q olduğunu. Örneğin: "2 + 2 = 5 ise ben Örümcek Adamım" gerçek bir ifadedir.

Bazı basit test senaryoları

Bu durumlar aşağıdaki şekilde (1) konuşmadaki problemi nasıl ortaya koyacağımız (2) bilgisayara nasıl sağlayabileceğimize (3) bilgisayarın verebileceği doğru çıktıyı verir.

  1. A kişisi ve B kişisi size yolda yaklaşır ve aşağıdaki ifadeleri yapar:

    C: B bir knave veya ben bir şövalyeyim.

    B: A bir şövalyedir.

Cevap:

B bir şövalyedir ve A bir şövalyedir.

Giriş:

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

Çıktı:


    A = 1
    B = 1
    

  1. A, B ve F kişileri size yolda yaklaşır ve aşağıdaki ifadeleri yapar:

    C: Ben bir Şövalyeysem, B o zaman bir Knave'dir.

    B: Bu doğruysa, F de bir Knave'dir.

Cevap:

A bir şövalye, B bir knave, F bir şövalye.

Giriş

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

Çıktı:


    A = 1
    B = 0
    F = 1
    

  1. Q, X ve W size yolda yaklaşıyor ve aşağıdaki ifadeleri yapıyorlar:

    W: Hem Q hem de X'in Şövalyeler olduğu doğru değil.

    S: Bu doğru.

    X: W'nin söylediği doğruysa, Q'nun söylediği yanlıştır.

Cevap:

W ve Q şövalyelerdir. X bir Knave'dir.

Giriş

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

Çıktı


    W = 1
    Q = 1
    X = 0
    

Bir yoktur benzer meydan 3 yıl ayrıştırma ve çıkarabilseniz içermiyor veya De Morgan o odaklarının öncesinin. Bu nedenle, bunun bir dupe olmasını önlemek için odaklanma ve uygulama konusunda yeterince farklı olduğunu iddia ediyorum.

Bu meydan okuma bir dupe olarak kısaca kapatıldı. O zamandan beri yeniden açıldı.

Bu zorluğun öncelikle farklı odaklandığını iddia ediyorum. Diğer zorluk İngilizce ayrıştırmaya odaklanır, bu değildir. İkincisi sadece VE ve VEYA kullanır, oysa bu koşullu kullanır ve daha fazla bulmacanın çözülmesine izin verir. Günün sonunda, soru, bu zorluğun cevaplarının önemsiz bir şekilde ikame edilip edilemeyeceğidir ve şartlı koşulların ve koşullu olumsuzlukların dahil edilmesinin, daha sağlam değişikliklerin sırayla yapılması gereken yeterli karmaşıklığı eklediğine inanıyorum. bu zorluğa uyması için.


Bir Knave diyorsa ne yapabiliriz (B=1)=>(C=0)? ~((B=1)=>(C=0))ya (B=1)=>(C=1)da başka bir şey?
njpipeorgan

Bunun 5 dakikadan daha kısa sürede yapılması imkansızdır. Bu sorun SAT olarak bilinir ve karmaşıklığı üsteldir. Bu nedenle, genel durumda n = 26 için (2 SAT değil), bir bilgisayarda makul bir sürede çözmek imkansızdır.
Labo

İlk test durumunuzda 2 olası çıktı bulunur. Mantıksal kullandığınız gibi OR, bu olabilir A:1 B:1veya A:1 B:0B'nin çünkü B=1yanlış olabilir bir hala gerçek olacağını ise.
Katenkyo

@njpipeorgan Eğer Knave B ise bunu söyleyemez. Yanlış bir öneri her şeyi ima eder ve bu nedenle bu ifade doğru olur. Eğer Knave ne farklı bir karakter ise, olumsuzlukları kabul edersiniz, ki bu (B=1)^(C=1)şartların normal olarak nasıl ele alındığına bağlıdır
Liam

1
Merak edenler için asıl mesele, giriş sorgusuna baktığım ve o da kelime bulmacasına baktığıydı. Bu düzeltildi
Cameron Aavik

Yanıtlar:


6

Piton 3, 450 342 307 bayt

Düzenleme: bir ithalat unuttum çıkıyor ...

İlk çözümüm, sorgular için esnek adlandırmaya sahip olmaktan yararlanıyor

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

Yukarıdakileri aşağıdakilerle arayabilirsiniz:

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

Bir sonraki burada OP'de görüldüğü gibi aynı sorgu biçimini kullanır, ayrıca birincisinde yaptığım bazı değişikliklere de sahip değildir. İki format arasında dönüştürdüğü için 417 bayttır.

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

Ve çağrılabilir:

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

İkisi de geri döndü

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

Açıklanamayan Açıklama:

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

Ayrıca, ikinci çözüm, PEP 448'in kullanılması nedeniyle 3.5'e (3.4 değil) ihtiyaç duyar


1

Mathematica, 80 bayt

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

açıklama

İşlev Fiki argüman alır,

  • c tüm karakterlerin isimlerinin bir listesidir,
  • s her biri iki bölümden oluşan ve kimin ne söylediğini içeren bir ifadeler listesidir.

Örneğin, Q, X ve W olmak üzere üç karakter vardır.

characters={q,x,w};

Ve diyorlar ki,

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

nerede Trueve FalseŞövalyeler ve Knaves sırasıyla anlamına gelir. Sonra

F[characters, statements]

verecek {{q->True, x->False, w->True}}, yani Q ve W'nin Şövalyeler olduğu tek bir çözüm var, X ise bir Knave. Birden fazla çözüm varsa, çıktı şöyle görünecektir{{...},{...},...}


Algoritma çok basit. {True,False}~Tuples~Length@ckarakterler arasında olası tüm Şövalyeler ve Knav kombinasyonlarını verir. Sonra Thread[c->#]&/@bu kombinasyonlara dayalı bir dizi kural oluşturun. İki A ve B karakteri olması durumunda, dizi

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

İfadeleri bu kuralların bir satırı ile değiştirdiğinizde, bir dizi

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

Bu dizinin ilk sütunu hoparlörlerin kimliğidir ve ikinci sütun ifadelerinin doğru mu yanlış mı olduğunu gösterir. Geçerli bir çözüm, konuşmacıların kimlikleri ve ifadeleri arasındaki uyumu gerektirir. Yukarıdaki dizi, bu kombinasyonun bir çözüm olmadığı anlamına gelir, çünkü ikinci konuşmacı, bir Şövalye yanlış bir ifade yapar.

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

ikameleri yapar ve koşulu karşılayan kombinasyonları seçer.


1

Yakut, 128

Bu, diğer herkesle aynı algoritmadır, tüm olası bıçak ve şövalye kombinasyonlarını deneyin ve hangi çubuklara bakın. Üzerinde çalıştığım bir tane daha var, ama daha uzun olacağını düşünüyorum (daha ilginç olsa da).

İfade girdileri şu şekilde olmalıdır:

  • & VE
  • | VEYA
  • == DIR-DİR
  • ! DEĞİL
  • > GELMEKTEDİR
  • X: X kişisi ...

Ayrıca her ifadenin ve alt ifadenin parantez içinde olmasını istiyorum. Bu sürümle ilgili tek sorun, en fazla 2 ^ 26 yinelemeden geçmesidir ve hepsi bıçak değilse, en az 2 ^ (26-n) yinelemedir ! Bunu perspektiften ifade etmek gerekirse, iki kişi varsa ve en azından biri bir knave değilse, en az 16.777.216 iterasyon alacaktır !

Bunu sınırlamak için, aşağıdakileri 168 bayta gönderirim. 161'e geri kesmek 26için sub #{o.size}.

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

Ama bunun yerine bir dizi insan ve ifadelerin bir harita örneğin kullanabilirsiniz:

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

Sonra 128'e indiriyorum.

->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}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.