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.mzph.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), …