Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of the water jugs problem #26

Open
versae opened this issue Feb 19, 2021 · 0 comments
Open

Implementation of the water jugs problem #26

versae opened this issue Feb 19, 2021 · 0 comments

Comments

@versae
Copy link

versae commented Feb 19, 2021

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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant