CS50 使用 Python 進行人工智能簡介-“騎士與流氓”謎題

如何使用邏輯推理來解決“騎士與騙子”(Knights and Knaves)類型的邏輯難題。具體來說,任務是根據每個角色的陳述推理出他們是“騎士”還是“騙子”。

任務背景:

  1. 騎士與騙子問題:每個角色要么是騎士,要么是騙子。騎士總是說真話,騙子總是說假話。通過他們的陳述,我們需要推理出每個角色是騎士還是騙子。

  2. 目標:你需要編寫邏輯來表示這些角色的行為,并且通過邏輯推理得出每個角色的身份。

  3. 給定文件

    • logic.py:該文件包含了許多邏輯連接詞的類定義,比如“與(And)”,“或(Or)”,“非(Not)”等,以及一個model_check函數,用于進行模型檢查,驗證知識庫是否推導出一個給定的查詢。
    • puzzle.py:該文件定義了幾個命題符號,比如AKnight表示A是騎士,AKnave表示A是騙子等。你需要在這個文件中填充不同的知識庫(knowledge0knowledge1等)來推理出每個角色的身份。
  4. 具體的邏輯任務:對于每個謎題(Puzzle 0、Puzzle 1等),你需要:

    • 理解角色的陳述。
    • 使用邏輯符號表達這些陳述,并將它們添加到對應的知識庫中。
    • 然后,使用model_check函數來推理每個角色是騎士還是騙子。

具體任務:

對于每個謎題,你需要:

  1. Puzzle 0:只有A一個角色。A說:“我既是騎士又是騙子”。你需要通過邏輯推理來確定A是騎士還是騙子。

  2. Puzzle 1:有兩個角色A和B。A說:“我們都是騙子”。B什么也沒說。你需要推理出A和B各自是騎士還是騙子。

  3. Puzzle 2:有兩個角色A和B。A說:“我們是同一類”。B說:“我們是不同的類”。你需要推理出A和B各自是騎士還是騙子。

  4. Puzzle 3:有三個角色A、B和C。A說:“我既是騎士又是騙子”,B說:“A說‘我既是騙子’”,然后B說:“C是騙子”,C說:“A是騎士”。你需要推理出A、B和C各自是騎士還是騙子。

如何表示:

  1. 邏輯表達式:每個謎題中,角色的陳述可以通過邏輯表達式來表示,例如,A的陳述可以轉化為“如果A是騎士,那么A所說的就是對的;如果A是騙子,那么A所說的就是假的”。

  2. 知識庫(Knowledge Base):每個謎題都要求你構建一個知識庫,將每個角色的陳述和身份條件寫成邏輯表達式。然后使用model_check函數,推導出每個角色的身份。

  3. AI推理:你的目標是讓AI代替你完成推理。你應該專注于如何合理地用邏輯表達謎題中的信息,而不是直接推理。

總結:

  • 知識庫:通過定義與每個角色的陳述相關的邏輯表達式,建立每個謎題的知識庫。
  • 推理:使用model_check函數推導出每個角色是騎士還是騙子。

這些任務的核心在于如何將角色的陳述和身份約束轉化為邏輯公式,然后通過邏輯推理來得到謎題的答案。

import itertools# 定義邏輯句子的基類
class Sentence():def evaluate(self, model):"""評估邏輯句子的真值。model是一個字典,表示每個符號的值。這個方法會被子類重寫。"""raise Exception("nothing to evaluate")def formula(self):"""返回邏輯句子的字符串公式表示。"""return ""def symbols(self):"""返回邏輯句子中所有符號的集合。"""return set()@classmethoddef validate(cls, sentence):"""驗證給定的句子是否是合法的邏輯句子。"""if not isinstance(sentence, Sentence):raise TypeError("must be a logical sentence")@classmethoddef parenthesize(cls, s):"""如果表達式沒有括號,給它加上括號以確保優先級正確。"""def balanced(s):"""檢查字符串中括號是否平衡。"""count = 0for c in s:if c == "(":count += 1elif c == ")":if count <= 0:return Falsecount -= 1return count == 0# 如果字符串不為空,且不是字母或已經是平衡的括號表達式,直接返回if not len(s) or s.isalpha() or (s[0] == "(" and s[-1] == ")" and balanced(s[1:-1])):return selse:return f"({s})"# 定義邏輯符號類,繼承自Sentence
class Symbol(Sentence):def __init__(self, name):"""初始化符號,符號是一個字符串表示的邏輯變量。"""self.name = namedef __eq__(self, other):"""重載等于運算符,用于比較符號是否相等。"""return isinstance(other, Symbol) and self.name == other.namedef __hash__(self):"""重載哈希函數,保證Symbol對象可以作為字典的鍵。"""return hash(("symbol", self.name))def __repr__(self):"""返回符號的字符串表示。"""return self.namedef evaluate(self, model):"""評估符號的真值,model是一個字典,存儲了每個符號的值。"""try:return bool(model[self.name])except KeyError:raise Exception(f"variable {self.name} not in model")def formula(self):"""返回符號的公式表示,即符號本身。"""return self.namedef symbols(self):"""返回符號本身的集合。"""return {self.name}# 定義“非”邏輯句子,繼承自Sentence
class Not(Sentence):def __init__(self, operand):"""初始化一個“非”邏輯句子,操作數是一個邏輯句子。"""Sentence.validate(operand)self.operand = operanddef __eq__(self, other):"""重載等于運算符,判斷兩個Not句子是否相等。"""return isinstance(other, Not) and self.operand == other.operanddef __hash__(self):"""重載哈希函數,用于字典操作。"""return hash(("not", hash(self.operand)))def __repr__(self):"""返回“非”邏輯句子的字符串表示。"""return f"Not({self.operand})"def evaluate(self, model):"""評估“非”邏輯句子的真值。"""return not self.operand.evaluate(model)def formula(self):"""返回“非”邏輯句子的公式表示。"""return "?" + Sentence.parenthesize(self.operand.formula())def symbols(self):"""返回“非”邏輯句子中涉及的符號集合。"""return self.operand.symbols()# 定義“與”邏輯句子,繼承自Sentence
class And(Sentence):def __init__(self, *conjuncts):"""初始化一個“與”邏輯句子,包含多個合取項。"""for conjunct in conjuncts:Sentence.validate(conjunct)self.conjuncts = list(conjuncts)def __eq__(self, other):"""重載等于運算符,判斷兩個“與”邏輯句子是否相等。"""return isinstance(other, And) and self.conjuncts == other.conjunctsdef __hash__(self):"""重載哈希函數,用于字典操作。"""return hash(("and", tuple(hash(conjunct) for conjunct in self.conjuncts)))def __repr__(self):"""返回“與”邏輯句子的字符串表示。"""conjunctions = ", ".join([str(conjunct) for conjunct in self.conjuncts])return f"And({conjunctions})"def add(self, conjunct):"""添加一個新的合取項。"""Sentence.validate(conjunct)self.conjuncts.append(conjunct)def evaluate(self, model):"""評估“與”邏輯句子的真值。"""return all(conjunct.evaluate(model) for conjunct in self.conjuncts)def formula(self):"""返回“與”邏輯句子的公式表示。"""if len(self.conjuncts) == 1:return self.conjuncts[0].formula()return " ∧ ".join([Sentence.parenthesize(conjunct.formula())for conjunct in self.conjuncts])def symbols(self):"""返回“與”邏輯句子中所有符號的集合。"""return set.union(*[conjunct.symbols() for conjunct in self.conjuncts])# 定義“或”邏輯句子,繼承自Sentence
class Or(Sentence):def __init__(self, *disjuncts):"""初始化一個“或”邏輯句子,包含多個析取項。"""for disjunct in disjuncts:Sentence.validate(disjunct)self.disjuncts = list(disjuncts)def __eq__(self, other):"""重載等于運算符,判斷兩個“或”邏輯句子是否相等。"""return isinstance(other, Or) and self.disjuncts == other.disjunctsdef __hash__(self):"""重載哈希函數,用于字典操作。"""return hash(("or", tuple(hash(disjunct) for disjunct in self.disjuncts)))def __repr__(self):"""返回“或”邏輯句子的字符串表示。"""disjuncts = ", ".join([str(disjunct) for disjunct in self.disjuncts])return f"Or({disjuncts})"def evaluate(self, model):"""評估“或”邏輯句子的真值。"""return any(disjunct.evaluate(model) for disjunct in self.disjuncts)def formula(self):"""返回“或”邏輯句子的公式表示。"""if len(self.disjuncts) == 1:return self.disjuncts[0].formula()return " ∨  ".join([Sentence.parenthesize(disjunct.formula())for disjunct in self.disjuncts])def symbols(self):"""返回“或”邏輯句子中所有符號的集合。"""return set.union(*[disjunct.symbols() for disjunct in self.disjuncts])# 定義“蘊含”邏輯句子,繼承自Sentence
class Implication(Sentence):def __init__(self, antecedent, consequent):"""初始化一個蘊含邏輯句子,包含前提和結論。"""Sentence.validate(antecedent)Sentence.validate(consequent)self.antecedent = antecedentself.consequent = consequentdef __eq__(self, other):"""重載等于運算符,判斷兩個蘊含邏輯句子是否相等。"""return (isinstance(other, Implication)and self.antecedent == other.antecedentand self.consequent == other.consequent)def __hash__(self):"""重載哈希函數,用于字典操作。"""return hash(("implies", hash(self.antecedent), hash(self.consequent)))def __repr__(self):"""返回蘊含邏輯句子的字符串表示。"""return f"Implication({self.antecedent}, {self.consequent})"def evaluate(self, model):"""評估蘊含邏輯句子的真值。"""return ((not self.antecedent.evaluate(model))or self.consequent.evaluate(model))def formula(self):"""返回蘊含邏輯句子的公式表示。"""antecedent = Sentence.parenthesize(self.antecedent.formula())consequent = Sentence.parenthesize(self.consequent.formula())return f"{antecedent} => {consequent}"def symbols(self):"""返回蘊含邏輯句子中所有符號的集合。"""return set.union(self.antecedent.symbols(), self.consequent.symbols())# 定義“等價”邏輯句子,繼承自Sentence
class Biconditional(Sentence):def __init__(self, left, right):"""初始化一個等價邏輯句子,包含左邊和右邊的表達式。"""Sentence.validate(left)Sentence.validate(right)self.left = leftself.right = rightdef __eq__(self, other):"""重載等于運算符,判斷兩個等價邏輯句子是否相等。"""return (isinstance(other, Biconditional)and self.left == other.leftand self.right == other.right)def __hash__(self):"""重載哈希函數,用于字典操作。"""return hash(("biconditional", hash(self.left), hash(self.right)))def __repr__(self):"""返回等價邏輯句子的字符串表示。"""return f"Biconditional({self.left}, {self.right})"def evaluate(self, model):"""評估等價邏輯句子的真值。"""return ((self.left.evaluate(model)and self.right.evaluate(model))or (not self.left.evaluate(model)and not self.right.evaluate(model)))def formula(self):"""返回等價邏輯句子的公式表示。"""left = Sentence.parenthesize(str(self.left))right = Sentence.parenthesize(str(self.right))return f"{left} <=> {right}"def symbols(self):"""返回等價邏輯句子中所有符號的集合。"""return set.union(self.left.symbols(), self.right.symbols())# 定義模型檢查函數
def model_check(knowledge, query):"""檢查知識庫是否推導出查詢。"""def check_all(knowledge, query, symbols, model):"""給定一個模型,檢查知識庫是否推導出查詢。"""# 如果模型中已經包含所有符號的值if not symbols:# 如果知識庫在這個模型中為真,那么查詢也必須為真if knowledge.evaluate(model):return query.evaluate(model)return Trueelse:# 選擇一個剩余的未賦值的符號remaining = symbols.copy()p = remaining.pop()# 創建一個符號為真的模型model_true = model.copy()model_true[p] = True# 創建一個符號為假的模型model_false = model.copy()model_false[p] = False# 確保在兩個模型中都能推導出查詢return (check_all(knowledge, query, remaining, model_true) andcheck_all(knowledge, query, remaining, model_false))# 獲取知識庫和查詢中所有符號symbols = set.union(knowledge.symbols(), query.symbols())# 檢查知識庫是否推導出查詢return check_all(knowledge, query, symbols, dict())
  • Sentence類:所有邏輯句子的基類,包含了所有邏輯句子的基本接口和方法,例如evaluate(評估句子的真值)、formula(返回句子的公式表示)和symbols(返回該句子的符號集合)。
  • Symbol類:代表一個基本符號(變量),它是邏輯句子中最簡單的元素。每個Symbol表示一個邏輯變量。
  • Not、And、Or、Implication、Biconditional類:這些類分別代表邏輯運算符(非、與、或、蘊含、等價)。每個類實現了相關的邏輯運算規則,如evaluate方法根據模型的賦值返回真值,formula方法返回相應的邏輯公式。
  • model_check函數:這個函數用于檢查給定的知識庫(knowledge)是否推導出查詢(query)。它采用遞歸的方法嘗試對所有可能的符號賦值,檢查知識庫是否在每個模型中為真,如果為真,則檢查查詢是否也為真。

為了完成這段代碼,我們需要根據每個謎題的描述來填寫knowledge0knowledge1knowledge2knowledge3。每個謎題包含不同的條件,這些條件將形成一個邏輯公式,以供模型檢查(model_check)來推理每個人的身份(騎士或小人)。

解釋每個謎題的含義:

  • Puzzle 0:A 說:“我既是騎士,又是小人。”

    • 如果 A 是騎士,他的陳述必須為真。所以 A 的陳述“我既是騎士又是小人”就應該是真的。然而這顯然是一個自相矛盾的陳述,因為一個人不能同時是騎士和小人。所以 A 必須是小人,他的陳述是假話。
  • Puzzle 1:A 說:“我們都是小人。”

    • A 的陳述為假,如果 A 是小人,他的陳述為真,所以 A 必須是小人。B 的身份可以根據 A 的陳述推理出來。
  • Puzzle 2:A 說:“我們是同類。” B 說:“我們是不同類。”

    • A 和 B 的陳述相互矛盾,因此如果 A 是騎士(真話),B 必須是小人(假話)。如果 A 是小人,則 A 的陳述為假,B 的陳述為真。
  • Puzzle 3:A 說:“我既是騎士,也許是小人。”但我們不知道是哪一個;B 說:“A 說‘我是小人’”,并且 B 還說:“C 是小人。” C 說:“A 是騎士。”

    • 我們需要根據 B 和 C 的陳述來推理,尤其是 B 是否準確地轉述了 A 的話。根據這些謎題描述來構造邏輯公式:
Puzzle 0:A 說“我既是騎士,又是小人。”
# Puzzle 0
# A says "I am both a knight and a knave."
# A的陳述是 "我既是騎士,又是小人"
# 如果A是騎士,那么A的陳述必須為真,但這顯然是自相矛盾的,因此A必須是小人。knowledge0 = And(# A 是小人(假的)AKnight, Not(AKnave),# A 的陳述 "我既是騎士,又是小人" 必須為假Not(And(AKnight, AKnave))
)
Puzzle 1:A 說“我們都是小人。”B 沒有說話。
# Puzzle 1
# A says "We are both knaves."
# A 說 "我們都是小人"
# 如果A是小人,那么A的陳述就為假,因此A必須是小人。knowledge1 = And(# A 是小人AKnight, Not(AKnave),# A的陳述 "我們都是小人" 為假Not(And(AKnave, BKnave))
)
Puzzle 2:A 說“我們是同類。”B 說“我們是不同類。”
# Puzzle 2
# A says "We are the same kind."
# B says "We are of different kinds."
# A和B的陳述是互相矛盾的。
# 如果A是騎士,那么A的陳述應該為真,所以B是小人,B的陳述應該為假。
# 如果A是小人,那么A的陳述應該為假,B是騎士,B的陳述為真。knowledge2 = And(# A的陳述 "我們是同類" 為真,B的陳述 "我們是不同類" 為假Implication(AKnight, And(AKnight, BKnight)),Implication(AKnave, And(And(AKnave, BKnave), Implication(BKnight, AKnave)))
)
Puzzle 3:A 說“我既是騎士,也許是小人。”B 說“A 說‘我是小人’”。B 說“C 是小人。”C 說“A 是騎士。”
# Puzzle 3
# A says either "I am a knight." or "I am a knave."
# B says "A said 'I am a knave'."
# B says "C is a knave."
# C says "A is a knight."
# A的陳述是模棱兩可的,“我既是騎士也可能是小人”。所以我們可以假設A要么是騎士,要么是小人。
# B的陳述和C的陳述可以用來推理A、B和C的身份。knowledge3 = And(# A 的陳述模棱兩可:A 可能是騎士,也可能是小人Or(AKnight, AKnave),# B 說 A 說 "我是小人" Implication(AKnave, BKnight),# B 說 C 是小人BKnave,# C 說 A 是騎士Implication(CKnight, AKnight)
)

完整代碼:

from logic import *  # 導入邏輯庫# 定義邏輯符號
AKnight = Symbol("A is a Knight")
AKnave = Symbol("A is a Knave")BKnight = Symbol("B is a Knight")
BKnave = Symbol("B is a Knave")CKnight = Symbol("C is a Knight")
CKnave = Symbol("C is a Knave")# Puzzle 0
# A 說 "我既是騎士,又是小人"
# A 的陳述自相矛盾,因此 A 必須是小人
knowledge0 = And(# A 是小人AKnight, Not(AKnave),# A 的陳述 "我既是騎士又是小人" 必須為假Not(And(AKnight, AKnave))
)# Puzzle 1
# A 說 "我們都是小人"
# 如果 A 是小人,那么 A 的陳述為假,因此 A 必須是小人
knowledge1 = And(# A 是小人AKnight, Not(AKnave),# A 的陳述 "我們都是小人" 為假Not(And(AKnave, BKnave))
)# Puzzle 2
# A 說 "我們是同類"
# B 說 "我們是不同類"
# A 和 B 的陳述互相矛盾
# A 為騎士時,A 說的是真話,B 必須是小人;A 為小人時,A 說的是假話,B 必須是騎士
knowledge2 = And(# A 的陳述 "我們是同類" 為真,B 的陳述 "我們是不同類" 為假Implication(AKnight, And(AKnight, BKnight)),Implication(AKnave, And(And(AKnave, BKnave), Implication(BKnight, AKnave)))
)# Puzzle 3
# A 說 "我既是騎士,也許是小人"
# B 說 "A 說‘我是小人’"
# B 說 "C 是小人"
# C 說 "A 是騎士"
knowledge3 = And(# A 的陳述是模棱兩可的:A 可能是騎士,可能是小人Or(AKnight, AKnave),# B 說 A 說 "我是小人"Implication(AKnave, BKnight),# B 說 C 是小人BKnave,# C 說 A 是騎士Implication(CKnight, AKnight)
)def main():symbols = [AKnight, AKnave, BKnight, BKnave, CKnight, CKnave]puzzles = [("Puzzle 0", knowledge0),("Puzzle 1", knowledge1),("Puzzle 2", knowledge2),("Puzzle 3", knowledge3)]for puzzle, knowledge in puzzles:print(puzzle)if len(knowledge.conjuncts) == 0:print("    Not yet implemented.")else:for symbol in symbols:if model_check(knowledge, symbol):print(f"    {symbol}")if __name__ == "__main__":main()
  • 通過AndOr構造每個謎題的知識庫。知識庫定義了每個人的陳述和真值。
  • model_check函數用于檢查每個符號(A、B、C)是否符合知識庫中的條件,并推理出每個人是騎士還是小人。
  • 每個謎題都包含若干邏輯條件,表示不同人物的陳述和相互之間的關系。

這個項目的目標是解決經典的“騎士和小人”邏輯謎題。每個謎題的設定都包含一組角色,每個角色要么是騎士(總是說真話),要么是小人(總是說假話)。我們的任務是通過推理每個角色的陳述,利用邏輯公式來判斷每個角色的身份。

項目流程

  1. 定義符號和角色

    • 我們首先為每個角色(A, B, C)定義邏輯符號,這些符號代表角色是否是騎士或小人。例如,AKnight表示A是騎士,AKnave表示A是小人。
    • 這些符號通過Symbol類來表示,每個符號有自己的名稱,并可以在推理過程中被評估為真或假。
  2. 編寫每個謎題的知識庫

    • 每個謎題都有一組條件,描述了角色的陳述以及它們之間的邏輯關系。我們將這些條件用邏輯公式表達。
    • 例如,A的陳述可能是“我們都是小人”,這個陳述可以通過AndNotImplication等邏輯連接符來表示。
    • 知識庫通常是多個邏輯公式的集合,表示了我們已知的關于角色和陳述的所有信息。
  3. 模型檢查

    • 模型檢查(model_check)是通過遍歷所有可能的真值組合來推理每個角色的身份。給定一個知識庫和一個查詢,model_check會檢查是否可以推導出查詢符號為真。
    • 這個過程通過遞歸檢查每個符號的真值來完成,直到知識庫中的所有公式都被滿足。
  4. 推理過程

    • 通過模型檢查,我們可以得出每個角色是否是騎士或小人。這是通過驗證角色陳述的真假來推理出來的。
    • 對于每個謎題,model_check會輸出一個結果,告訴我們每個角色的身份。

詳細的推理過程

Puzzle 0為例,推理過程如下:

Puzzle 0:A說“我既是騎士,又是小人。”
  1. 知識庫

    • A的陳述是“我既是騎士,又是小人”,我們知道一個人不能同時是騎士和小人。所以,A的陳述是假的。
    • 如果A是騎士,那么A的陳述必須為真,但顯然這是不可能的,所以A必須是小人。
  2. 邏輯公式

    • Not(And(AKnight, AKnave)):表示A的陳述“我既是騎士又是小人”必須為假。
    • Not(AKnave):表示A是小人。
  3. 模型檢查

    • 通過模型檢查,AKnight為假,AKnave為真,因此A是小人。
Puzzle 1:A說“我們都是小人”,B什么也沒說。
  1. 知識庫

    • A的陳述“我們都是小人”是假的,因此A是小人。
    • 由于A的陳述是假的,如果A是小人,那么B也必須是小人。
  2. 邏輯公式

    • Not(And(AKnave, BKnave)):表示A的陳述“我們都是小人”是假的。
    • AKnave:A是小人。
  3. 模型檢查

    • 通過模型檢查,得出A是小人,B也是小人。
Puzzle 2:A說“我們是同類”,B說“我們是不同類”。
  1. 知識庫

    • A和B的陳述是矛盾的。如果A是騎士,那么A的陳述為真,B必須是小人。
    • 如果A是小人,那么A的陳述為假,B是騎士。
  2. 邏輯公式

    • Implication(AKnight, And(AKnight, BKnight)):表示如果A是騎士,則A和B是同類。
    • Implication(AKnave, And(AKnave, BKnave)):表示如果A是小人,則A和B是不同類。
  3. 模型檢查

    • 通過模型檢查,得出A是騎士,B是小人。
Puzzle 3:A說“我既是騎士,也許是小人”,B說“A說‘我是小人’”,B說“C是小人”,C說“A是騎士”。
  1. 知識庫

    • A的陳述模棱兩可,可以是騎士,也可以是小人。
    • B的陳述“A說‘我是小人’”和“C是小人”可以幫助推理A和C的身份。
    • C的陳述“A是騎士”也可以進一步推理A的身份。
  2. 邏輯公式

    • Or(AKnight, AKnave):表示A可能是騎士,也可能是小人。
    • Implication(AKnave, BKnight):表示B說A是小人,并且B是騎士。
    • BKnave:表示B是小人。
    • Implication(CKnight, AKnight):表示C說A是騎士。
  3. 模型檢查

    • 通過模型檢查,推理出A是騎士,B是小人,C是騎士。

流程圖

+------------------------------------+
|         1. 定義符號和角色         |
|  - 為每個角色(A, B, C)定義邏輯符號 |
+---------------------+--------------+|v
+------------------------------------+
|  2. 編寫謎題的知識庫            |
|  - 根據角色的陳述,創建邏輯公式    |
|  - 使用And、Or、Not等連接符      |
+---------------------+--------------+|v
+------------------------------------+
|  3. 使用模型檢查推理              |
|  - 遞歸地檢查所有可能的真值組合    |
|  - 確定每個角色是騎士還是小人      |
+---------------------+--------------+|v
+------------------------------------+
|  4. 輸出結果                     |
|  - 打印每個謎題的解答              |
+------------------------------------+

問題背景

在這個項目中,我們需要通過模型檢查來判斷一些關于“騎士和小人”的邏輯謎題。

規則:
  1. 騎士總是說真話。
  2. 小人總是說假話。
  3. 我們通過每個人的陳述,來推斷他們是騎士還是小人。

項目目標

根據每個謎題中的條件(人物的陳述),我們需要通過自動推理來判斷每個人的身份(騎士或小人)。這就需要通過模型檢查算法來自動推理。


什么是模型檢查算法?

模型檢查是通過列舉所有可能的情況(模型)來驗證一個邏輯公式是否成立。就好像你在做一個選擇題時,通過列舉所有可能的答案,逐個驗證哪個答案是正確的。

在這個項目中,算法會列舉出所有符號(比如“某個人是騎士”或“某個人是小人”)的所有可能組合,然后檢查這些組合是否滿足謎題中的條件。

算法怎么工作?

1. 符號化每個角色

首先,我們需要把每個角色的身份轉換為符號。比如:

  • AKnight: 表示A是騎士
  • AKnave: 表示A是小人
  • BKnight: 表示B是騎士
  • BKnave: 表示B是小人
  • 以此類推……

然后,我們根據謎題中的陳述,構建一個邏輯公式。這些公式描述了謎題中所有的陳述和規則。我們將這些公式和符號放在一起,用來推理每個角色的身份。

2. 列舉所有可能的真值組合

假設我們有3個角色(A, B, C),每個角色可能是騎士或小人。那么我們就有如下可能的情況:

  • A是騎士,B是騎士,C是騎士
  • A是騎士,B是騎士,C是小人
  • A是騎士,B是小人,C是騎士
  • A是騎士,B是小人,C是小人
  • A是小人,B是騎士,C是騎士
  • A是小人,B是騎士,C是小人
  • A是小人,B是小人,C是騎士
  • A是小人,B是小人,C是小人

這就是我們說的符號的真值組合,總共有8種可能。

3. 驗證每一種組合是否滿足謎題的條件

接下來,模型檢查會遞歸地檢查每種符號組合。在每種組合下,檢查所有已知的陳述是否成立。如果某個組合中的陳述成立,那么模型檢查就會判斷這個組合是否符合謎題的規則。

舉個例子:

假設A說:“我既是騎士又是小人”。根據邏輯:

  • 如果A是騎士,那么他講的是真的,那就意味著A是同時是騎士又是小人,這顯然不可能。所以A一定不是騎士,他必須是小人。
  • 如果A是小人,他講的就一定是假的。所以A就不能是騎士和小人,而是只可能是小人。

模型檢查會通過這個推理,自動判斷A是小人。

4. 模型檢查的核心操作

模型檢查的核心就是檢查所有這些符號組合,遞歸地判斷在每個組合下,謎題中所有的陳述是否成立。

具體來說,模型檢查會:

  1. 列出所有可能的符號組合(比如A是騎士還是小人,B是騎士還是小人等)。
  2. 在每種組合下,評估所有陳述是否符合規則(比如“如果A是騎士,那么B是小人”是否成立)。
  3. 如果某個組合中的所有陳述都成立,算法就會認為這個組合是可行的,進而推斷出每個人的身份。

模型檢查算法的代碼大致流程

  1. 符號化陳述

    • 比如“我說我是騎士”就被轉換成 AKnight,表示A是騎士,或者AKnave表示A是小人。
  2. 生成所有可能的符號賦值(真值組合)

    • 比如A可能是騎士也可能是小人,B也可能是騎士也可能是小人。
  3. 遞歸檢查每個組合是否滿足知識庫中的陳述

    • 對每個組合,檢查所有的邏輯條件是否成立。
  4. 得出結論

    • 如果一個組合成立,說明這個組合符合謎題的規則,可以推斷出A、B、C等的身份。

舉個例子:Puzzle 0

Puzzle 0:A說:“我既是騎士又是小人。”
  1. 符號化

    • 我們有兩個符號:AKnightAKnaveAKnight表示A是騎士,AKnave表示A是小人。
  2. 列舉所有組合

    • 可能的符號組合是:
      • A是騎士,B是騎士,C是騎士
      • A是騎士,B是騎士,C是小人
      • 等等……
  3. 檢查每種組合

    • 假設我們選中“A是騎士,B是小人,C是騎士”,那么我們檢查A說的這句話是否成立:A是騎士的話,他講的應該是真的。但他講的是“我既是騎士又是小人”,這是不可能的,所以這個組合是不成立的。
  4. 得出結論

    • 通過這個檢查,我們知道A一定不是騎士,而是小人。

總結

模型檢查的算法通過列舉出所有可能的符號賦值(真值組合),然后遞歸檢查每個組合是否滿足所有的邏輯條件,最終得出謎題的答案。在這個項目中,我們通過模型檢查自動推導出每個人的身份(騎士或小人)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/72090.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72090.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/72090.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

每日學習Java之一萬個為什么?[MySQL面試篇]

分析SQL語句執行流程中遇到的問題 前言1 MySQL是怎么在一臺服務器上啟動的2 MySQL主庫和從庫是同時啟動保持Alive的嗎&#xff1f;3 如果不是主從怎么在啟動的時候保證數據一致性4 ACID原則在MySQL上的體現5 數據在MySQL是通過什么DTO實現的6 客戶端怎么與MySQL Server建立連接…

詳細解析d3dx9_27.dll丟失怎么辦?如何快速修復d3dx9_27.dll

運行程序時提示“d3dx9_27.dll文件缺失”&#xff0c;通常由DirectX組件損壞或文件丟失引起。此問題可通過系統化修復方法解決&#xff0c;無需重裝系統或軟件。下文將詳細說明具體步驟及注意事項。 一.d3dx9_27.dll缺失問題的本質解析 當系統提示“d3dx9_27.dll丟失”時&…

IP----訪問服務器流程

這只是IP的其中一塊內容-訪問服務器流程&#xff0c;IP還有更多內容可以查看IP專欄&#xff0c;前一段學習內容為IA內容&#xff0c;還有更多內容可以查看IA專欄&#xff0c;可通過以下路徑查看IA-----配置NAT-CSDN博客CSDN,歡迎指正 1.訪問服務器流程 1.分層 1.更利于標準化…

Linux報 “device or resource busy” 異常的原因以及解決辦法

首先&#xff0c;Linux報"device or resource busy"的原因是因為某個進程正在占用該設備或資源&#xff0c;導致其他進程無法訪問該設備或資源。 解決該問題的辦法有以下幾種&#xff1a; 查找占用該設備或資源的進程&#xff0c;然后將其停止或結束。可以使用以下…

和鯨科技推出人工智能通識課程解決方案,助力AI人才培養

2025年2月&#xff0c;教育部副部長吳巖應港澳特區政府邀請&#xff0c;率團赴港澳宣講《教育強國建設規劃綱要 (2024—2035 年)》。在港澳期間&#xff0c;吳巖闡釋了教育強國目標的任務&#xff0c;并與特區政府官員交流推進人工智能人才培養的辦法。這一系列行動體現出人工智…

java springboot 中調用 C++ 方法

以下是一個完整的 Spring Boot 調用 C 方法的 Demo&#xff0c;采用 JNI (Java Native Interface) 方式實現&#xff0c;包含詳細步驟說明&#xff1a; 1. 項目結構 demo-project/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/example/…

JSX基礎 —— 識別JS表達式

在JSX中可以通過 大括號語法 { } 識別JS中的表達式&#xff0c;比如常見的變量、函數調用、方法調用等等 1、使用引號傳遞字符串 2、使用JavaScript變量 3、函數調用和方法調用 (函數和方法本質沒有區別&#xff0c;這里默認&#xff1a; 函數是自己定義的&#xff0c;方法是…

git從零學起

從事了多年java開發&#xff0c;一直在用svn進行版本控制&#xff0c;如今更換了公司&#xff0c;使用的是git進行版本控制&#xff0c;所以打算記錄一下git學習的點滴&#xff0c;和大家一起分享。 百度百科&#xff1a; Git&#xff08;讀音為/g?t/&#xff09;是一個開源…

關于對async和await的初步理解

async 包裹著的函數中進程是堵塞的 &#xff0c;是同步化的&#xff0c; await等待的是個promise對象&#xff0c;否則"await" 對此表達式的類型沒有影響 例1 async getDataDD(){await this.fun1()await this.fun2()// await Promise.all([this.fun1(),this.fun…

MySQL—Keepalived+MySQL雙主復制實現MySQL高可用

Keepalived原理&#xff1a; Keepalived 的原理主要基于虛擬路由冗余協議&#xff08;VRRP&#xff0c;Virtual Router Redundancy Protocol&#xff09;、健康檢查機制和負載均衡機制&#xff0c;以下為你詳細介紹&#xff1a; VRRP 協議實現高可用&#xff1a;VRRP 是 Keep…

SpringBoot AOP 源碼解析

文章目錄 一、AOP 代碼示例1. 準備注解和目標類2. 定義 Aspect3. 結論 二、源碼1. AOP 實現核心類2. 代理類的創建流程2.1 核心類 AbstractAutoProxyCreator2.2 AbstractAutoProxyCreator#postProcessBeforeInstantiation2.3 AspectJAwareAdvisorAutoProxyCreator#shouldSkip2.…

Linux:Shell環境變量與命令行參數

目錄 Shell的變量功能 什么是變量 變數的可變性與方便性 影響bash環境操作的變量 腳本程序設計&#xff08;shell script&#xff09;的好幫手 變量的使用&#xff1a;echo 變量的使用&#xff1a;HOME 環境變量相關命令 獲取環境變量 環境變量和本地變量 命令行…

MySQL數據庫入門到大蛇尚硅谷宋紅康老師筆記 高級篇 part 5

第05章_存儲引擎 為了管理方便&#xff0c;人們把連接管理、查詢緩存、語法解析、查詢優化這些并不涉及真實數據存儲的功能劃分為MySQLserver的功能&#xff0c;把真實存取數據的功能劃分為存儲引擎的功能。所t以在MySQLserver完成了查詢優化后&#xff0c;只需按照生成的執行…

JAVA面試_進階部分_23種設計模式總結

1. 單例模式&#xff1a;確保某一個類只有一個實例&#xff0c;而且自行實例化并向整個系統提供這 個實例。 &#xff08;1&#xff09;懶漢式 public class Singleton { /* 持有私有靜態實例&#xff0c;防止被引用&#xff0c;此處賦值為null&#xff0c;目的是實現延遲加載…

滲透測試(WAF過濾information_schema庫的繞過,sqllib-46關,海洋cms9版本的注入)

1.sqlin-lib 46關 打開網站配置文件發現 此網站的對ID進行了排序&#xff0c;我們可以知道&#xff0c;order by接不了union &#xff0c;那我們可以通過測試sort&#xff0c;rond等函數&#xff0c;觀察網頁的反饋來判斷我們的盲注是否正確 我們發現 當參數有sort來排序時&…

AORO M6北斗短報文終端:將“太空黑科技”轉化為安全保障

在衛星導航領域&#xff0c;北斗系統作為我國自主研發的全球衛星導航系統&#xff0c;正以其獨特的短報文通信功能引發全球范圍內的廣泛關注。這一突破性技術不僅使北斗系統在全球四大導航系統中獨樹一幟&#xff0c;具備了雙向通信能力&#xff0c;更通過遨游通訊推出的AORO M…

ARCGIS國土超級工具集1.4更新說明

ARCGIS國土超級工具集V1.4版本&#xff0c;功能已增加至54 個。本次更新在V1.3版本的基礎上&#xff0c;新增了“拓撲問題修復工具”并同時調整了數據處理工具欄的布局、工具操作界面的選擇圖層下拉框新增可選擇位于圖層組內的要素圖層功能、數據保存路徑新增了可選擇數據庫內的…

Element Plus中el-select選擇器的下拉選項列表的樣式設置

el-select選擇器&#xff0c;默認樣式效果&#xff1a; 通過 * { margin: 0; padding: 0; } 去掉內外邊距后的樣式效果&#xff08;樣式變丑了&#xff09;&#xff1a; 通過 popper-class 自定義類名修改下拉選項列表樣式 el-select 標簽設置 popper-class"custom-se…

基于Linux系統的物聯網智能終端

背景 產品研發和項目研發有什么區別&#xff1f;一個令人發指的問題&#xff0c;剛開始工作時項目開發居多&#xff0c;認為項目開發和產品開發區別不大&#xff0c;待后來隨著自身能力的提升&#xff0c;逐步感到要開發一個好產品還是比較難的&#xff0c;我認為項目開發的目的…

java excel xlsx 增加數據驗證

隱藏表下拉框 // 創建隱藏工作表存儲下拉框數據String hiddenSheetName "HiddenSheet"System.currentTimeMillis();Sheet hiddenSheet workbook.createSheet(hiddenSheetName);//設置隱藏sheetworkbook.setSheetHidden(workbook.getSheetIndex(hiddenSheetName), …