Adrianistán

El acertijo de la cebra

06/11/2022

Hoy vamos a resolver un acertijo bastante famoso, el de la cebra, atribuido a Einstein y a Lewis Carroll. Seguramente no haya sido inventado por ninguno de los dos, pero sigue siendo muy interesante.

El puzzle dice lo siguiente:

¿Quién tiene una cebra? ¿Quién bebe agua?

Resolviéndolo usando clpz

Usando clpz podemos resolver este acertijo de forma muy clara y concisa. El truco consista en asignar un número a cada casa, en orden, siendo el 1 la casa más a la izquierda y 5 la casa a la derecha. Sobre eso, creamos variables para cada una de las nacionalidad, profesiones, bebidas, etc que podrán adquirir un valor entre 1 y 5. Por supuesto, dentro de cada categoría, no se pueden repetir los números, porque cada uno está asignado a una casa diferente.


    Vars = [
	% nationalities
	English, Spanish, Japanese, Norwegian, Italian,
	% professiones
	Painter, Doctor, Diplomat, Violinist, Sculptor,
	% beverages
	Tea, Coffee, Juice, Milk, Water,
	% colors
	Red, Green, White, Yellow, Blue,
	% animals
	Dog, Snails, Fox, Horse, Zebra],
    Vars ins 1..5,

    all_different([English, Spanish, Japanese, Norwegian, Italian]),
    all_different([Painter, Doctor, Diplomat, Violinist, Sculptor]),
    all_different([Tea, Coffee, Juice, Milk, Water]),
    all_different([Red, Green, White, Yellow, Blue]),
    all_different([Dog, Snails, Fox, Horse, Zebra]),

A continuación codificamos las reglas. Como asignamos el valor en base a la posición de la casa, una casa a la derecha de otra es simplemente sumar 1. Decir que una casa está al lado de otra, significa que la diferencia absoluta entre 2 variables tiene que ser 1.


    English #= Red,
    Spanish #= Dog,
    Japanese #= Painter,
    Italian #= Tea,
    Norwegian #= 1,
    Green #= Coffee,
    Green #= White + 1,
    Sculptor #= Snails,
    Diplomat #= Yellow,
    Milk #= 3,
    abs(Norwegian-Blue) #= 1,
    Violinist #= Juice,
    abs(Fox-Doctor) #= 1,
    abs(Horse-Diplomat) #= 1,

Si juntamos todo, nos dará el siguiente programa, ya bonito para ver el resultado.


:- use_module(library(clpz)).
:- use_module(library(lists)).
:- use_module(library(format)).

run :-
    zebra(Vars),
    append([English,Spanish,Japanese,Norwegian,Italian|_], [Zebra], Vars),
    Nats = [English-english, Spanish-spanish, Japanese-japanese, Norwegian-norwegian, Italian-italian],
    member(Zebra-Nat, Nats),
    format("The ~a has the zebra~n", [Nat]),
    nth0(14, Vars, Water),
    member(Water-Nat1, Nats),
    format("The ~a has the water~n", [Nat1]).
    

zebra(Vars) :-
    Vars = [
	% nationalities
	English, Spanish, Japanese, Norwegian, Italian,
	% professiones
	Painter, Doctor, Diplomat, Violinist, Sculptor,
	% beverages
	Tea, Coffee, Juice, Milk, Water,
	% colors
	Red, Green, White, Yellow, Blue,
	% animals
	Dog, Snails, Fox, Horse, Zebra],
    Vars ins 1..5,

    all_different([English, Spanish, Japanese, Norwegian, Italian]),
    all_different([Painter, Doctor, Diplomat, Violinist, Sculptor]),
    all_different([Tea, Coffee, Juice, Milk, Water]),
    all_different([Red, Green, White, Yellow, Blue]),
    all_different([Dog, Snails, Fox, Horse, Zebra]),

    English #= Red,
    Spanish #= Dog,
    Japanese #= Painter,
    Italian #= Tea,
    Norwegian #= 1,
    Green #= Coffee,
    Green #= White + 1,
    Sculptor #= Snails,
    Diplomat #= Yellow,
    Milk #= 3,
    abs(Norwegian-Blue) #= 1,
    Violinist #= Juice,
    abs(Fox-Doctor) #= 1,
    abs(Horse-Diplomat) #= 1,
    
    label(Vars).

El resultado es que la cebra la tenía el japonés y el noruego es el que bebe agua.

Tags: prolog programacion puzzle tutorial acertijo clpz