Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

viernes, 10 de septiembre de 2021

Resolviendo el proyecto Knights del curso "CS50’s Introduction to Artificial Intelligence with Python"

El curso es accesible libremente en este link: https://cs50.harvard.edu/ai/2020/

El proyecto está en este link: https://cs50.harvard.edu/ai/2020/projects/1/knights/

En resumen, el proyecto trata de personajes que pueden ser Caballeros (Knights) o Truhanes (Knaves) pero no ambos a la vez. Los Caballeros siempre dicen la verdad, y los Truhanes siempre mienten. El objetivo es, dada cierta información, averiguar si los personajes son Caballeros o Truhanes.

El primer problema dice:

# Puzzle 0
# A says "I am both a knight and a knave."

Mi solución en este caso es:

knowledge0 = And(
    Or(AKnightAKnave),
    Not(And(AKnightAKnave)),
    Implication(Not(And(AKnightAKnave)), AKnave)
)

La afirmación de lo que dice A es falsa ("Soy ambos, Caballero y Truhán"). Como es falsa, implica que A es un Truhán.

El segundo problema es:

# Puzzle 1
# A says "We are both knaves."
# B says nothing.

Luego de analizar las condiciones del problema, hallé dos bicondicionales: Si un personaje miente, es un Truhán, y si es un Truhán, entonces miente. Si un personaje dice la verdad ,es un Caballero, y si es un Caballero, debe decir la verdad.

Mi solución:

knowledge1 = And(
    Or(AKnightAKnave),
    Not(And(AKnightAKnave)),
    Or(BKnightBKnave),
    Not(And(BKnightBKnave)),
    Implication(Not(And(AKnaveBKnave)), AKnave),
    Biconditional(And(Or(AKnaveBKnave), Not(And(AKnaveBKnave))), AKnave)
)

La implicación significa que A y B no pueden ser Truhanes, porque en este caso A estaría diciendo la verdad y sería un Caballero. Tampoco A puede ser un Caballero, porque estaría mintiendo.

El bicondicional indica que uno de los dos es un Truhán, pero no pueden serlo ambos, sí y sólo si A es Truhán.

El tercer problema es:

# Puzzle 2
# A says "We are the same kind."
# B says "We are of different kinds."

Mi solución:

knowledge2 = And(
    Or(AKnightAKnave),
    Not(And(AKnightAKnave)),
    Or(BKnightBKnave),
    Not(And(BKnightBKnave)),
    Biconditional(And(AKnightBKnight), AKnight),
    Biconditional(And(AKnaveBKnight), AKnave),
    Biconditional(And(AKnightBKnight), BKnave),
    Biconditional(And(AKnaveBKnight), BKnight)
)

Aquí agoto las cuatro opciones, todas como bicondicionales. Si ambos son caballeros, A dice la verdad y viceversa. En este caso B estaría mintiendo y sería un Truhán, y viceversa. Si A es un Caballero, B es necesariamente un Truhán.

El último problema es:

# Puzzle 3
# A says either "I am a knight." or "I am a knave.", but you don't know which.
# B says "A said 'I am a knave'."
# B says "C is a knave."
# C says "A is a knight."

Aquí recibí un poco de ayuda de: https://cs50.stackexchange.com/questions/41635/help-with-cs50ai-project-1-knights-puzzle-3

Mi solución es:

knowledge3 = And(
    Or(AKnightAKnave),
    Not(And(AKnightAKnave)),
    Or(BKnightBKnave),
    Not(And(BKnightBKnave)),
    Or(CKnightCKnave),
    Not(And(CKnightCKnave)),
    Biconditional(Or(AKnightAKnave), AKnight),
    Biconditional(CKnaveBKnight),
    Biconditional(CKnightBKnave),
    Biconditional(AKnightCKnight),
    Biconditional(AKnaveCKnave)

Lo que podría decir A está en el primer bicondicional. La última bicondicional codifica lo que sería A en caso de que C sea un Truhán, la penúltima codifica loq ue será A si C fuera un Caballero. Las otras dos bicondicionales codifican lo que sería C según lo que dice B en caso de ser Caballero o Truhán.

Para resolver este problema tuve que hacer una tabla de verdad con lo que pueden ser A, B, C (Caballero y Truhán) y lo que están diciendo, y también verificar que mi respuesta era la correcta.

Encontré este otro código https://github.com/iron8kid/Knights/blob/main/puzzle.py donde el autor no usa el bicondicional, haciendo que sus soluciones sean mucho más complejas que las mías.

Los archivos del proyecto con mis soluciones, una copia de las soluciones de iron8kid (en el archivo puzzle2.py) y los ejemplos dados en el curso (subcarpeta src) se pueden descargar de aquí.

IDE: Visual Studio Code 1.60 con Python 3.8