Discussion:
Can I solve the 'Zebra Puzzle' in drools?
Miles Wen
2011-06-15 08:25:52 UTC
Permalink
hello everybody,
I have some trouble in solving the 'Zebra
Puzzle<http://en.wikipedia.org/wiki/Zebra_Puzzle>'
using drools5.
I defined a class named 'House' to represent the data, and the corresponding
enums as well : Color.java, Nation.java, Pet.java, Drink.java,
Cigarette.java, here are those sources:

House.java:
public class House {

// 颜色
public Color color;
// 房子从巊数的䜍眮 1-5
public int position;
public Nation nation;
public Pet pet;
public Drink drink;
public Cigarette cigarette;
......

Color.java:

public enum Color {
red, yellow, blue, green, ivory
}

Nation.java:

public enum Nation {
englishman, spaniard, norwegian, ukrainian, japanese
}

Pet.java:

public enum Pet {
dog, fox, snails, horse, zebra
}

Drink.java:

public enum Drink {
orangeJuice, tea, coffee, milk, water
}

Cigarette.java:

public enum Cigarette {
kools, chesterfields, winston, luckyStrike, parliaments
}

And this is my drl file:

package com.sample

import com.sample.fh.*

rule "英囜人䜏圚红色的房子里"
when
$h1:House(nation == Nation.englishman, color != Color.red)
$h2:House(color == Color.red)
then
System.out.println("英囜人englishman䜏圚红色red的房子里");
modify($h2){setColor($h1.color)};
modify($h1){setColor(Color.red)};
end

rule "西班牙人养了䞀条狗"
when
$h1:House(nation == Nation.spaniard)
$h2:House(pet == Pet.dog, nation != Nation.spaniard)
then
System.out.println("西班牙人spaniard养了䞀条狗dog");
modify($h2){setPet($h1.pet)};
modify($h1){setPet(Pet.dog)};
end

rule "挪嚁人䜏圚巊蟹的第䞀䞪房子里"
when
$h1:House(position == 1, nation != Nation.norwegian)
$h2:House(nation == Nation.norwegian)
then
System.out.println("挪嚁人norwegian䜏圚巊蟹的第䞀䞪房子里");
modify($h2){setNation($h1.nation)};
modify($h1){setNation(Nation.norwegian)};
end

rule "黄房子里的人喜欢抜kools牌的驙烟"
when
$h1:House(color == Color.yellow, cigarette != Cigarette.kools)
$h2:House(cigarette == Cigarette.kools)
then
System.out.println("黄房子yellow里的人喜欢抜kools牌的驙烟");
modify($h2){setCigarette($h1.cigarette)};
modify($h1){setCigarette(Cigarette.kools)};
end

rule "抜chesterfields牌銙烟的人䞎养狐狞的人是邻居"
when
$h1:House(cigarette == Cigarette.chesterfields, pet != Pet.fox)
$h2:House(pet == Pet.fox)
$h3:House(eval(position - $h2.position == 1) || eval(position -
$h2.position == -1))
eval($h1.position - $h2.position != 1 && $h1.position - $h2.position
!= -1)
then
System.out.println("抜chesterfields牌銙烟的人䞎养狐狞fox的人是邻居");
int tmp = $h3.position;
modify($h3){setPosition($h1.position)};
modify($h1){setPosition(tmp)};
end
rule "抜chesterfields牌銙烟的人䞎养狐狞的人是同䞀人"
when
$h1:House(cigarette == Cigarette.chesterfields, pet == Pet.fox)
$h2:House(eval(position - $h1.position == 1) || eval(position -
$h1.position == -1))
then
System.out.println("抜chesterfields牌銙烟的人䞎养狐狞的人是同䞀人");
modify($h1){setPet($h2.pet)};
modify($h2){setPet(Pet.fox)};
end

rule "挪嚁人䜏圚蓝色的房子旁蟹"
when
$h1:House(nation == Nation.norwegian)
$h2:House(color == Color.blue)
$h3:House(eval(position - $h2.position == 1) || eval(position -
$h2.position == -1))
eval($h1.position - $h2.position != 1 && $h1.position - $h2.position
!= -1)
then
System.out.println("挪嚁人norwegian䜏圚蓝色blue的房子旁蟹");
modify($h1){setNation($h3.nation)};
modify($h3){setNation(Nation.norwegian)};
end

rule "抜winston牌銙烟的人养了䞀只蜗牛"
when
$h1:House(cigarette == Cigarette.winston)
$h2:House(pet == Pet.snails, cigarette != Cigarette.winston)
then
System.out.println("抜winston牌銙烟的人养了䞀只蜗牛Snails");
modify($h2){setPet($h1.pet)};
modify($h1){setPet(Pet.snails)};
end

rule "抜LuckyStrike牌銙烟的人喜欢喝桔子汁"
when
$h1:House(cigarette == Cigarette.luckyStrike)
$h2:House(drink == Drink.orangeJuice, cigarette !=
Cigarette.luckyStrike)
then
System.out.println("抜Lucky Strike牌銙烟的人喜欢喝桔子汁orange juice");
modify($h2){setDrink($h1.drink)};
modify($h1){setDrink(Drink.orangeJuice)};
end

rule "乌克兰人喜欢喝茶"
when
$h1:House(nation == Nation.ukrainian)
$h2:House(drink == Drink.tea, nation != Nation.ukrainian)
then
System.out.println("乌克兰人ukrainian喜欢喝茶tea");
modify($h2){setDrink($h1.drink)};
modify($h1){setDrink(Drink.tea)};
end

rule "日本人抜parliaments牌的烟"
when
$h1:House(nation == Nation.japanese)
$h2:House(cigarette == Cigarette.parliaments, nation !=
Nation.japanese)
then
System.out.println("日本人japanese抜parliaments牌的烟");
modify($h2){setCigarette($h1.cigarette)};
modify($h1){setCigarette(Cigarette.parliaments)}
end

rule "抜kools牌的銙烟的人䞎养马的人是邻居"
when
$h1:House(cigarette == Cigarette.kools)
$h2:House(pet == Pet.horse)
$h3:House(eval(position - $h2.position == 1) || eval(position -
$h2.position == -1))
eval($h1.position - $h2.position != 1 && $h1.position - $h2.position
!= -1)
then
System.out.println("抜kools牌的銙烟的人䞎养马horse的人是邻居");
modify($h1){setCigarette($h3.cigarette)};
modify($h3){setCigarette(Cigarette.kools)};
end

rule "喜欢喝咖啡的人䜏圚绿房子里"
when
$h1:House(drink == Drink.coffee)
$h2:House(color == Color.green, drink != Drink.coffee)
then
System.out.println("喜欢喝咖啡coffee的人䜏圚绿green房子里");
modify($h2){setColor($h1.color)};
modify($h1){setColor(Color.green)};
end

rule "绿房子圚象牙癜房子的右蟹"
when
$h1:House(color == Color.green, position != 1)
$h2:House(color == Color.ivory, position != 5)
$h3:House(eval(position == $h2.position + 1), color != Color.green)
then
System.out.println("绿green房子圚象牙癜ivory房子的右蟹囟䞭的右蟹");
modify($h1){setColor($h3.color)};
modify($h3){setColor(Color.green)};
end
rule "癜房子已经圚最右蟹了"
when
$h1:House(color == Color.ivory, position == 5)
$h2:House(color == Color.green, position != 1)
$h3:House(eval(position == $h2.position -1))
then
System.out.println("癜房子已经圚最右蟹了");
$h3.setPosition($h1.position);
$h1.setPosition($h2.position - 1);
update($h3);
update($h1);
end
rule "绿房子已经圚最巊蟹了"
when
$h1:House(color == Color.green, position == 1)
$h2:House(color == Color.ivory, position != 5)
$h3:House(eval(position == $h2.position + 1))
then
System.out.println("绿房子已经圚最巊蟹了");
modify($h3){setPosition($h1.position)};
modify($h1){setPosition($h2.position + 1)};
end
rule "绿房子圚最巊蟹䞔癜房子圚最右蟹"
when
$h1:House(color == Color.green, position == 1)
$h2:House(color == Color.ivory, position == 5)
$h3:House()
$h4:House(eval(position - $h3.position == 1))
then
System.out.println("绿房子圚最巊蟹䞔癜房子圚最右蟹");
modify($h2){setPosition($h3.position)};
modify($h3){setPosition(5)};
modify($h1){setPosition($h4.position)};
modify($h4){setPosition(1)};
end

rule "䞭闎那䞪房子里的人喜欢喝牛奶"
when
$h1:House(position == 3, drink != Drink.milk)
$h2:House(drink == Drink.milk)
then
System.out.println("䞭闎那䞪房子里的人喜欢喝牛奶");
modify($h2){setDrink($h1.drink))};
modify($h1){setDrink(Drink.milk)};
end

rule "output"
when
$h1:House(position == 1)
$h2:House(position == 2)
$h3:House(position == 3)
$h4:House(position == 4)
$h5:House(position == 5)

House(nation == Nation.englishman, color == Color.red)

House(nation == Nation.spaniard, pet == Pet.dog)

House(position == 1, nation == Nation.norwegian)

House(color == Color.yellow, cigarette == Cigarette.kools)

$h6:House(cigarette == Cigarette.chesterfields)
$h7:House(pet == Pet.fox)
eval($h6.position - $h7.position == 1 || $h6.position - $h7.position
== -1)

$h8:House(nation == Nation.norwegian)
$h9:House(color == Color.blue)
eval($h8.position - $h9.position == 1 || $h8.position - $h9.position
== -1)

House(cigarette == Cigarette.winston, pet == Pet.snails)

House(cigarette == Cigarette.luckyStrike, drink ==
Drink.orangeJuice)

House(nation == Nation.ukrainian, drink == Drink.tea)

House(cigarette == Cigarette.parliaments, nation == Nation.japanese)

$h10:House(cigarette == Cigarette.kools)
$h11:House(pet == Pet.horse)
eval($h10.position - $h11.position == 1 || $h10.position -
$h11.position == -1)

House(drink == Drink.coffee, color == Color.green)

$h12:House(color == Color.green)
$h13:House(color == Color.ivory)
eval($h12.position - $h13.position == 1)

House(position == 3, drink == Drink.milk)
then
System.out.println("从巊到右:");

System.out.println("第䞀闎房子是"+$h1.color+"色的;䜏着"+$h1.nation+"人;养"+$h1.pet+"宠物;抜"+$h1.cigarette+"牌驙烟;喝"+$h1.drink+"饮料;");

System.out.println("第二闎房子是"+$h2.color+"色的;䜏着"+$h2.nation+"人;养"+$h2.pet+"宠物;抜"+$h2.cigarette+"牌驙烟;喝"+$h2.drink+"饮料;");

System.out.println("第䞉闎房子是"+$h3.color+"色的;䜏着"+$h3.nation+"人;养"+$h3.pet+"宠物;抜"+$h3.cigarette+"牌驙烟;喝"+$h3.drink+"饮料;");

System.out.println("第四闎房子是"+$h4.color+"色的;䜏着"+$h4.nation+"人;养"+$h4.pet+"宠物;抜"+$h4.cigarette+"牌驙烟;喝"+$h4.drink+"饮料;");

System.out.println("第五闎房子是"+$h5.color+"色的;䜏着"+$h5.nation+"人;养"+$h5.pet+"宠物;抜"+$h5.cigarette+"牌驙烟;喝"+$h5.drink+"饮料;");
end

There's some unicode character in the file.But it shouldn't bother the
compilation>...<
The rule named 'output' describes when the computation should stop. The
other rules are absorbed from the original 'Zebra puzzle' problem and each
making a little change to the working memory in order to 'approach' the
solution...(I don't know if I'm doing this wrong..)

No matter how I modify this program, it always result in an infinite loop...
For example, the console prints these messages repeatedly:

癜房子已经圚最右蟹了
抜chesterfields牌銙烟的人䞎养狐狞的人是同䞀人
抜kools牌的銙烟的人䞎养马horse的人是邻居
黄房子yellow里的人喜欢抜kools牌的驙烟
抜kools牌的銙烟的人䞎养马horse的人是邻居
黄房子yellow里的人喜欢抜kools牌的驙烟
抜kools牌的銙烟的人䞎养马horse的人是邻居
黄房子yellow里的人喜欢抜kools牌的驙烟
抜kools牌的銙烟的人䞎养马horse的人是邻居
黄房子yellow里的人喜欢抜kools牌的驙烟
抜kools牌的銙烟的人䞎养马horse的人是邻居
黄房子yellow里的人喜欢抜kools牌的驙烟
......................

I worked quite much time on this problem till now, and I referenced another
solution which is programmed in prolog, but still I didn't figured out the
drools solution to this problem.
Could somebody give a hint? Any help is appreciated,
Thanks!
--
Regards.
Miles. Wen
FrankVhh
2011-06-15 12:47:39 UTC
Permalink
Hi,

This is a puzzling one... but then again, I believe that is the idea.

I should have a very close look at it, but a loop always suggests that there
are rules that re-activate themselves or eachother.

For example:

rule "抽kools牌的香烟的人与养马的人是邻居"
when
$h1:House(cigarette == Cigarette.kools)
$h2:House(pet == Pet.horse)
$h3:House(eval(position - $h2.position == 1) || eval(position -
$h2.position == -1))
eval($h1.position - $h2.position != 1 && $h1.position - $h2.position
!= -1)
then
System.out.println("抽kools牌的香烟的人与养马(horse)的人是邻居");
modify($h1){setCigarette($h3.cigarette)};
modify($h3){setCigarette(Cigarette.kools)};
end

In this rule, $h3 and $h1 might be the same house OR $h1 and $h2 might be
the same house. I think you need to add extra constraints to make sure that
all 3 houses are different.

But still, I haven't had a thorough look at all the rules neither did I
refresh my knowledge of the zebrapuzzle, so I am not sure whether this is a
complete answer (if any).

Please let us know.

Regards,
Frank


--
View this message in context: http://drools.46999.n3.nabble.com/rules-users-Can-I-solve-the-Zebra-Puzzle-in-drools-tp3066485p3067138.html
Sent from the Drools: User forum mailing list archive at Nabble.com.
Wolfgang Laun
2011-06-15 14:48:03 UTC
Permalink
This puzzle can be solved using forward chaining, i.e., by using Drools or
any similar RBS, but it isn't possible by implementing the givens as rules,
expecting that an increase in the filled-in values will result in a (the)
solution. Certainly, it is possible to write a rule such as

rule EnglishRed
when
$h: House( nationality == null && colour == Colour.RED ||
nationality == Nationality.ENGLISHMAN && colour == null )
then
modify( $h ){
setNationality( Nationality.ENGLISHMAN ),
setColour( Colour.RED )
}
end

which adds "red" or "Englishman" to a House as soon as the other property is
present. But this approach comes to a standstill as soon as more
sophisticated mental processes are required in the manual solution
technique.

One approach I've tried successfully is to generate all permutations of
animals, colours, drinks, nationalities and smokes (120 each), insert them
as facts, and to write one big rule according to the givens. A similar
approach uses facts consisting of an attribute indication (animal,...
smoke), a value and a reference to a House, again starting with all possible
associations and using one rule to select the attribute combinations
satisfying the givens.

I'm not quite sure how the rules presented by Miles should work, but I don't
think that swapping values between House facts is going to work, even when
more defensive strategies against looping are employed.

-W
Post by FrankVhh
Hi,
This is a puzzling one... but then again, I believe that is the idea.
I should have a very close look at it, but a loop always suggests that there
are rules that re-activate themselves or eachother.
rule "³ékoolsÅÆµÄÏãÑ̵ÄÈËÓëÑøÂíµÄÈËÊÇÁÚŸÓ"
when
$h1:House(cigarette == Cigarette.kools)
$h2:House(pet == Pet.horse)
$h3:House(eval(position - $h2.position == 1) || eval(position -
$h2.position == -1))
eval($h1.position - $h2.position != 1 && $h1.position - $h2.position
!= -1)
then
System.out.println("³ékoolsÅÆµÄÏãÑ̵ÄÈËÓëÑøÂí£šhorse£©µÄÈËÊÇÁÚŸÓ");
modify($h1){setCigarette($h3.cigarette)};
modify($h3){setCigarette(Cigarette.kools)};
end
In this rule, $h3 and $h1 might be the same house OR $h1 and $h2 might be
the same house. I think you need to add extra constraints to make sure that
all 3 houses are different.
But still, I haven't had a thorough look at all the rules neither did I
refresh my knowledge of the zebrapuzzle, so I am not sure whether this is a
complete answer (if any).
Please let us know.
Regards,
Frank
--
http://drools.46999.n3.nabble.com/rules-users-Can-I-solve-the-Zebra-Puzzle-in-drools-tp3066485p3067138.html
Sent from the Drools: User forum mailing list archive at Nabble.com.
_______________________________________________
rules-users mailing list
https://lists.jboss.org/mailman/listinfo/rules-users
FrankVhh
2011-06-15 15:00:27 UTC
Permalink
Hi,

Just a last quick reply before getting stuck in a traffic jam.

As said, I haven't had a real good look at the rules, but imo they might be
able to work when you feed the engine an initial solution. I.e. insert five
house objects into working memory with a random assignment of the
"attributes". The engine could then re-arrange the objects until all
constraints are satisfied.

But again, I am not really certain about these statements, but it is an
interesting topic to think about...

Regards,
Frank
Post by Wolfgang Laun
This puzzle can be solved using forward chaining, i.e., by using Drools or
any similar RBS, but it isn't possible by implementing the givens as rules,
expecting that an increase in the filled-in values will result in a (the)
solution. Certainly, it is possible to write a rule such as
rule EnglishRed
when
$h: House( nationality == null && colour == Colour.RED ||
nationality == Nationality.ENGLISHMAN && colour == null )
then
modify( $h ){
setNationality( Nationality.ENGLISHMAN ),
setColour( Colour.RED )
}
end
which adds "red" or "Englishman" to a House as soon as the other property is
present. But this approach comes to a standstill as soon as more
sophisticated mental processes are required in the manual solution
technique.
One approach I've tried successfully is to generate all permutations of
animals, colours, drinks, nationalities and smokes (120 each), insert them
as facts, and to write one big rule according to the givens. A similar
approach uses facts consisting of an attribute indication (animal,...
smoke), a value and a reference to a House, again starting with all possible
associations and using one rule to select the attribute combinations
satisfying the givens.
I'm not quite sure how the rules presented by Miles should work, but I don't
think that swapping values between House facts is going to work, even when
more defensive strategies against looping are employed.
-W
Post by FrankVhh
Hi,
This is a puzzling one... but then again, I believe that is the idea.
I should have a very close look at it, but a loop always suggests that there
are rules that re-activate themselves or eachother.
rule "抽kools牌的香烟的人与养马的人是邻居"
when
$h1:House(cigarette == Cigarette.kools)
$h2:House(pet == Pet.horse)
$h3:House(eval(position - $h2.position == 1) || eval(position -
$h2.position == -1))
eval($h1.position - $h2.position != 1 && $h1.position - $h2.position
!= -1)
then
System.out.println("抽kools牌的香烟的人与养马(horse)的人是邻居");
modify($h1){setCigarette($h3.cigarette)};
modify($h3){setCigarette(Cigarette.kools)};
end
In this rule, $h3 and $h1 might be the same house OR $h1 and $h2 might be
the same house. I think you need to add extra constraints to make sure that
all 3 houses are different.
But still, I haven't had a thorough look at all the rules neither did I
refresh my knowledge of the zebrapuzzle, so I am not sure whether this is a
complete answer (if any).
Please let us know.
Regards,
Frank
--
http://drools.46999.n3.nabble.com/rules-users-Can-I-solve-the-Zebra-Puzzle-in-drools-tp3066485p3067138.html
Sent from the Drools: User forum mailing list archive at Nabble.com.
_______________________________________________
rules-users mailing list
https://lists.jboss.org/mailman/listinfo/rules-users
_______________________________________________
rules-users mailing list
https://lists.jboss.org/mailman/listinfo/rules-users
--
View this message in context: http://drools.46999.n3.nabble.com/rules-users-Can-I-solve-the-Zebra-Puzzle-in-drools-tp3066485p3067695.html
Sent from the Drools: User forum mailing list archive at Nabble.com.
Loading...