Monkey Business
This page details the cDMN implementation of the Monkey Business challenge, as listed on https://dmcommunity.org/challenge/challenge-nov-2015/. The challenge is as follows:
Monkey Business
Mrs. Robinson’s 4th grade class took a field trip to the local zoo. The day was sunny and warm — a perfect day to spend at the zoo. The kids had a great time and the monkeys were voted the class favorite animal. The zoo had four monkeys — two males, and two females. It was lunchtime for the monkeys and as the kids watched, each one ate a different fruit in their favorite resting place:
Sam, who doesn’t like bananas, likes sitting on the grass.
The monkey who sat on the rock ate the apple. The monkey who ate the pear didn’t sit on the tree branch.
Anna sat by the stream but she didn’t eat the pear.
Harriet didn’t sit on the tree branch. Mike doesn’t like oranges.
Question: Can you determine the name of each monkey, what kind of fruit each monkey ate, and where their favorite resting place was?
The first thing we should do, is create the glossary. We have three types: one for the monkeys, one for the places, and one for the fruits.
Type | ||
---|---|---|
Name | Type | Values |
Monkey | string | Anna, Sam, Harriet, Mike |
Place | string | Grass, Rock, Branch, Stream |
Fruit | string | Apple, Pear, Banana, Orange |
Now we need a way to assign a fruit and a place to each monkey.
Since every monkey needs exactly one fruit, and exactly one resting place, functions are perfectly suited for this task.
A function is a mapping of a set of arguments to a return value.
For instance, the function Place of Monkey
will map each monkey on exactly one place.
Function | |
---|---|
Name | Type |
Place of Monkey | Place |
Fruit of Monkey | Fruit |
That’s it! Our glossary is fully done. We can now focus on the logic aspect.
In the challenge description, there were two main pieces of info:
The hints of which monkey ate what fruit where.
The fact that no monkeys can have the same place or the same fruit.
Both of these are easily turned into constraint tables. For instance, we can state that “For every monkey m1 and m2 (different from m1) must hold that they have a different Place and a different Fruit.”
Different fruit and places | ||||
---|---|---|---|---|
E* | Monkey called m1 | Monkey called m2 | Place of m1 | Fruit of m1 |
1 | - | not(m1) | not(Place of m2) | not(Fruit of m2) |
Creating a table for the other piece of info is a bit more work, but is still fairly simple. The full table containing all snippets of information looks like this:
Monkey information | |||||
---|---|---|---|---|---|
E* | Monkey | Place of Monkey | Fruit of Monkey | Place of Monkey | Fruit of Monkey |
1 | Sam | - | - | Grass | not(Banana) |
2 | - | Rock | - | - | Apple |
3 | - | - | Pear | not(Branch) | - |
4 | Anna | - | - | Stream | not(Pear) |
5 | Harriet | - | - | not(Branch) | - |
6 | Mike | - | - | - | not(Orange) |
Rule 1 states that Sam sat on the Grass, and didn’t eat the Banana. Similarly, rule 2 states that the monkey who sat on the rock, ate the Apple. Every row in this constraint table represents a snippet of information.
And that’s it! Using two glossary tables, and two constraint tables, we were able to solve the challenge. Running the cDMN solver gives us the following output:
Model 1
==========
place_of_Monkey := {Anna->Stream, Sam->Grass, Harriet->Rock, Mike->Branch}.
fruit_of_Monkey := {Anna->Orange, Sam->Pear, Harriet->Apple, Mike->Banana}.
Elapsed time:
0.872