Post details: Solving the Missionaries and Cannibals puzzle

10 January, 2006

Permalink 17:21 UTC, by Fernando J. Pereda, 317 words, 7086 views   English (US)
Categories: Gentoo

Solving the Missionaries and Cannibals puzzle

There is a traditional puzzle where 3 missionaries and 3 cannibals have to cross a river using a small canoe. Rules are:

* You cannot have more cannibals than missionaries in either bank because cannibals will eat missionaries.
* The canoe can be run by either one or two persons. Both cannibals and missionaries know how to run it.

This puzzle is really easy to solve either by hand or programming. However, hacking a script to solve it is always more challenging than solving it by hand. Juanjo proposes a solution using Ruby in Misioneros y caníbales (in Spanish). I thought I could try solving it in Haskell.

It's been really easy to solve it in Haskell given the nature of the language. The proposed solution is a specific application of a computation over graphs:

The goal is finding every possible route between two nodes of a network graph, and then choose the shortest one. Once you define the possible succesors of a given state problem, finding routes between two states is straightforward. One particular oddity of this problem is the fact that the network graph has loops, so the algorithm has to check for them.

The recursion step (with implicit backtracking) is not difficult at all. It will take an initial state as first argument, and a list of visited states as a second argument. Returns a list of solutions, each solution represented by a list of states (nodes in the graph).

solveStep :: ProbSt -> [ProbSt] -> [[ProbSt]]
solveStep prob probs = if problemSolved prob
                       then [prob:probs]
                       else concat [ solveStep p' (prob:probs) | p' <- nextStates prob
                                                               , p' `notElem` probs ]

Where nextStates gives a list of succesors for a given problem, and problemSolved checks if we solved the problem. Now the function to really solve the problem can be defined easily in terms of solveStep:

solveProblem :: [[ProbSt]]
solveProblem = solveStep ((3,3),(0,0),Start) []

Ok, stop talking, here is the code: MisCan.hs.

Cheers,
Ferdy

Comments:

Comment from: Kim [Visitor]
Seen any solutions in other languages?
ie. bash, perl, C, C++
PermalinkPermalink 10 January, 2006 @ 20:43
Comment from: Fernando J. Pereda [Member]
In the post I linked there is a solution in Ruby, and two links to solutions in Prolog and Lisp:

Missionaries and Cannibals in Prolog
Missionaries and Cannibals in Lisp

It shouldn't be too hard to do it in C (thus in C++ and Objective-C). Perl, Java, Python and other imperative languages should also be 'easy'. Bash will be a bit tricker though.

Cheers,
Ferdy
PermalinkPermalink 10 January, 2006 @ 20:53

Leave a comment:

Your email address will not be displayed on this site.
Your URL will be displayed.

Allowed XHTML tags: <p, ul, ol, li, dl, dt, dd, address, blockquote, ins, del, span, bdo, br, em, strong, dfn, code, samp, kdb, var, cite, abbr, acronym, q, sub, sup, tt, i, b, big, small>
(Line breaks become <br />)
(Set cookies for name, email and url)
(Allow users to contact you through a message form (your email will NOT be displayed.))

Fernando J. Pereda

Here you will find stories about Gentoo net-mail development from Fernando J. Pereda (ferdy).

July 2008
Mon Tue Wed Thu Fri Sat Sun
<< <     
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Search

Categories

Misc

XML Feeds

What is RSS?

Who's Online?

  • Guest Users: 40

powered by
b2evolution