-
Notifications
You must be signed in to change notification settings - Fork 46
Description
Hi, thanks for this interesting library!
I tried implementing a version of the water jugs problem (of which a version was seen on the Die Hard movie), but it gets stuck in loop. The problem is usually formulated as this:
Suppose we have two jugs. One jug is capable of holding 3 gallons of water. A second jug can hold up to 4 gallons of water. There are no measurement lines on either jug. Therefore we can never determine the exact amount of water in either jug. However, by looking in either jug, we can determine if the jug is empty, full, or contains some water. We can empty a jug, fill a jug, or pour water from one jug into the other.
I thought the implementation would be straightforward, but after many tries I was unable to make work. I'm sure I'm missing something.
from experta import KnowledgeEngine, Fact, Field, Rule, DefFacts, AS, MATCH, TEST, P, W, L
class Jug(Fact):
content = Field(int, default=0, mandatory=True)
class Jug3(Jug): pass
class Jug4(Jug): pass
class Jugs(KnowledgeEngine):
@DefFacts()
def init(self):
yield Jug3(content=0)
yield Jug4(content=0)
@Rule(Jug4(content=L(2)))
def goal(self):
print("Done")
self.halt()
@Rule(
AS.jug3 << Jug3(content=MATCH.content3),
AS.jug4 << Jug4(content=MATCH.content4),
TEST(lambda content3, content4: content3 < 3 and content4 > 0),
)
def pour_jug4_into_jug3(self, jug3, jug4, content3, content4):
content_to_pour = min(3 - content3, content4, 3)
jug3_content = content3 + content_to_pour
jug4_content = content4 - content_to_pour
self.modify(jug3, content=jug3_content)
self.modify(jug4, content=jug4_content)
print("Pour jug4 into jug3")
@Rule(
AS.jug3 << Jug3(content=MATCH.content3),
AS.jug4 << Jug4(content=MATCH.content4),
TEST(lambda content3, content4: content3 > 0 and content4 < 4),
)
def pour_jug3_into_jug4(self, jug3, jug4, content3, content4):
content_to_pour = min(4 - content4, content3, 4)
jug3_content = content3 - content_to_pour
jug4_content = content4 + content_to_pour
self.modify(jug3, content=jug3_content)
self.modify(jug4, content=jug4_content)
print("Pour jug3 into jug4")
@Rule(AS.jug3 << Jug3(content=P(lambda x: x > 0)))
def empty_jug3(self, jug3):
self.modify(jug3, content=0)
print("Empty jug3")
@Rule(AS.jug4 << Jug4(content=P(lambda x: x > 0)))
def empty_jug4(self, jug4):
self.modify(jug4, content=0)
print("Empty jug4")
@Rule(AS.jug3 << Jug3(content=P(lambda x: x < 3)))
def fill_jug3(self, jug3):
self.modify(jug3, content=3)
print("Fill jug3")
@Rule(AS.jug4 << Jug4(content=P(lambda x: x < 4)))
def fill_jug4(self, jug4):
self.modify(jug4, content=4)
print("Fill jug4")
engine = Jugs()
engine.reset()
engine.run()