"""Ejemplo 3 - Encadenamiento hacia atras sobre la misma base de conocimiento."""

REGLAS = [
    {"id": "R1", "si": ["no_enciende", "sin_luz_fuente"], "entonces": "problema_alimentacion"},
    {"id": "R2", "si": ["problema_alimentacion", "cable_ok"], "entonces": "fuente_danada"},
    {"id": "R3", "si": ["no_enciende", "hay_luz_fuente"], "entonces": "problema_placa"},
    {"id": "R4", "si": ["fuente_danada"], "entonces": "reemplazar_fuente"},
    {"id": "R5", "si": ["problema_placa", "pitidos"], "entonces": "revisar_memoria"},
]

HECHOS = {"no_enciende", "sin_luz_fuente", "cable_ok"}


def probar(objetivo, reglas, hechos, nivel=0, visitados=None):
    """Intenta demostrar el objetivo. Devuelve True o False."""
    if visitados is None:
        visitados = set()
    sangria = "   " * nivel
    print(f"{sangria}? {objetivo}")

    if objetivo in hechos:
        print(f"{sangria}  SI (es un hecho conocido)")
        return True

    if objetivo in visitados:                  # corta la recursion circular
        print(f"{sangria}  NO (ya en curso: evito el ciclo)")
        return False
    visitados = visitados | {objetivo}

    for r in reglas:
        if r["entonces"] != objetivo:
            continue
        print(f"{sangria}  pruebo con {r['id']}: necesito {' y '.join(r['si'])}")
        if all(probar(p, reglas, hechos, nivel + 2, visitados) for p in r["si"]):
            print(f"{sangria}  SI (por {r['id']})")
            return True

    print(f"{sangria}  NO (no hay regla ni hecho que lo sostenga)")
    return False


print("=== Consulta 1: ¿hay que reemplazar la fuente? ===")
print("Respuesta:", probar("reemplazar_fuente", REGLAS, HECHOS))

print("\n=== Consulta 2: ¿hay que revisar la memoria? ===")
print("Respuesta:", probar("revisar_memoria", REGLAS, HECHOS))
