<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Tom Moertel's Weblog: Tag puzzles</title>
    <link>http://blog.moertel.com/articles/tag/puzzles?tag=puzzles</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Quality rants on programming theory and stuff geeks like</description>
    <item>
      <title>ClusterBy: a handy little function for the toolbox</title>
      <description>&lt;p&gt;Via Reddit I found &lt;a href="http://marknelson.us/2007/04/01/puzzling/"&gt;Mark Nelson&amp;#8217;s post about a recent word puzzle&lt;/a&gt; from &lt;span class="caps"&gt;NPR&lt;/span&gt;&amp;#8217;s
Weekend Edition:&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Take the names of two U.S. States, mix them all together, then rearrange the letters to form the names of two other U.S. States. What states are these?&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;The puzzle is fairly straightforward to solve by hand (think about
it), but let&amp;#8217;s write a program to solve it. That will give us a convenient
excuse to discuss a super-handy function I use all the time:
&lt;em&gt;clusterBy&lt;/em&gt;.  In Haskell, it looks like this:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='conid'&gt;Control&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;Arrow&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varop'&gt;&amp;amp;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='varid'&gt;qualified&lt;/span&gt; &lt;span class='conid'&gt;Data&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;Map&lt;/span&gt; &lt;span class='keyword'&gt;as&lt;/span&gt; &lt;span class='conid'&gt;M&lt;/span&gt;

&lt;span class='varid'&gt;clusterBy&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Ord&lt;/span&gt; &lt;span class='varid'&gt;b&lt;/span&gt; &lt;span class='keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;a&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;b&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='varid'&gt;a&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='varid'&gt;a&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='varid'&gt;clusterBy&lt;/span&gt; &lt;span class='varid'&gt;f&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;M&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='varid'&gt;elems&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='conid'&gt;M&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='varid'&gt;reverse&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='conid'&gt;M&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='varid'&gt;fromListWith&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varop'&gt;++&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
            &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;f&lt;/span&gt; &lt;span class='varop'&gt;&amp;amp;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='varid'&gt;return&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;What &lt;em&gt;clusterBy&lt;/em&gt; does is group a list of values by their signatures,
as computed by a given signature function &lt;em&gt;f&lt;/em&gt;, and returns
the groups in order of ascending signature.  For example, we
can cluster the words &amp;#8220;the tan ant gets some fat&amp;#8221; by length, by
first letter, or by last letter just by changing the
signature function we give to &lt;em&gt;clusterBy&lt;/em&gt;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;*&lt;/span&gt;&lt;span class='conid'&gt;Main&lt;/span&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='keyword'&gt;let&lt;/span&gt; &lt;span class='varid'&gt;antwords&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;words&lt;/span&gt; &lt;span class='str'&gt;"the tan ant gets some fat"&lt;/span&gt;

&lt;span class='varop'&gt;*&lt;/span&gt;&lt;span class='conid'&gt;Main&lt;/span&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;clusterBy&lt;/span&gt; &lt;span class='varid'&gt;length&lt;/span&gt; &lt;span class='varid'&gt;antwords&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"the"&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='str'&gt;"tan"&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='str'&gt;"ant"&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='str'&gt;"fat"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"gets"&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='str'&gt;"some"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;

&lt;span class='varop'&gt;*&lt;/span&gt;&lt;span class='conid'&gt;Main&lt;/span&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;clusterBy&lt;/span&gt; &lt;span class='varid'&gt;head&lt;/span&gt; &lt;span class='varid'&gt;antwords&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"ant"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"fat"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"gets"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"some"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"the"&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='str'&gt;"tan"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;

&lt;span class='varop'&gt;*&lt;/span&gt;&lt;span class='conid'&gt;Main&lt;/span&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;clusterBy&lt;/span&gt; &lt;span class='varid'&gt;last&lt;/span&gt; &lt;span class='varid'&gt;antwords&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"the"&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='str'&gt;"some"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"tan"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"gets"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"ant"&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='str'&gt;"fat"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;If we use &lt;em&gt;sort&lt;/em&gt; as the signature function, we can find anagrams:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;*&lt;/span&gt;&lt;span class='conid'&gt;Main&lt;/span&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;clusterBy&lt;/span&gt; &lt;span class='varid'&gt;sort&lt;/span&gt; &lt;span class='varid'&gt;antwords&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"fat"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"tan"&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='str'&gt;"ant"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"gets"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"the"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"some"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;And that brings us back to the original puzzle.  To find the solution,
we must consider each unique pair of state names to form a &amp;#8220;word&amp;#8221; and
find the anagrams among a list of such &amp;#8220;words.&amp;#8221;&lt;/p&gt;


	&lt;p&gt;Assuming we are given
a list of state names on standard input, one state per line, we can
write the shell of our solution as follows:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;main&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;mapM_&lt;/span&gt; &lt;span class='varid'&gt;print&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;solve&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;lines&lt;/span&gt; &lt;span class='varop'&gt;=&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='varid'&gt;getContents&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The shell delegates the real work to &lt;em&gt;solve&lt;/em&gt;.  It&amp;#8217;s job is to
compute the unique, 2-state combinations from the original
list of states, and then find the anagrams among these combinations.
As before, finding the anagrams is simply a matter of calling
&lt;em&gt;clusterBy&lt;/em&gt; with the right signature function.  We also filter
out the trivial results, which are not valid solutions:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;solve&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;filter&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;length&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;clusterBy&lt;/span&gt; &lt;span class='varid'&gt;signature&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;ucombos&lt;/span&gt;
&lt;span class='varid'&gt;ucombos&lt;/span&gt; &lt;span class='varid'&gt;xs&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='varid'&gt;x&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='varid'&gt;y&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt; &lt;span class='keyglyph'&gt;|&lt;/span&gt; &lt;span class='varid'&gt;x&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;xs&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;y&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;xs&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;x&lt;/span&gt; &lt;span class='varop'&gt;&amp;lt;&lt;/span&gt; &lt;span class='varid'&gt;y&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='varid'&gt;signature&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;sort&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;filter&lt;/span&gt; &lt;span class='varid'&gt;isAlpha&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;concat&lt;/span&gt;   &lt;span class='comment'&gt;-- sort letters&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;That&amp;#8217;s it.  Now we can solve the puzzle by feeding our program a list of states:&lt;/p&gt;


&lt;div class="typedin"&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;$ runhaskell anagrams2.hs &amp;lt; states.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;[[&amp;quot;NORTH CAROLINA&amp;quot;,&amp;quot;SOUTH DAKOTA&amp;quot;],
 [&amp;quot;NORTH DAKOTA&amp;quot;,&amp;quot;SOUTH CAROLINA&amp;quot;]]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;What a handy little function, that &lt;em&gt;clusterBy&lt;/em&gt;.&lt;/p&gt;


&lt;div class="update"&gt;

	&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; made clear that &lt;em&gt;clusterBy&lt;/em&gt; returns clusters in order
of ascending signature.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update 2007-10-31:&lt;/strong&gt;  For more interesting discussion of &lt;em&gt;clusterBy&lt;/em&gt;
and the original puzzle from &lt;span class="caps"&gt;NPR&lt;/span&gt;, see Anders Pearson&amp;#8217;s blog: &lt;a href="http://thraxil.org/users/anders/posts/2007/10/30/A-Simple-Programming-Puzzle-Seen-Through-Three-Different-Lenses/"&gt;A Simple Programming Puzzle Seen Through Three Different Lenses&lt;/a&gt;.&lt;/p&gt;


&lt;/div&gt;</description>
      <pubDate>Sat, 01 Sep 2007 15:39:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:46727e92-f04a-4fab-90d8-7cefc6caee77</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2007/09/01/clusterby-a-handy-little-function-for-the-toolbox</link>
      <category>programming</category>
      <category>haskell</category>
      <category>puzzles</category>
      <category>clusterby</category>
      <category>hof</category>
      <category>functions</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/562</trackback:ping>
    </item>
    <item>
      <title>Solving the Google Code Jam &amp;quot;countPaths&amp;quot; problem in Perl</title>
      <description>&lt;p&gt;As promised, here&amp;#8217;s a Perl version of a dynamic-programming-based solver
for the Google Code Jam &amp;#8220;countPaths&amp;#8221; problem.  It is a straight
translation of my &lt;a href="http://blog.moertel.com/articles/2006/08/16/solving-the-google-code-jam-countpaths-problem-in-ruby"&gt;improved Ruby implementation&lt;/a&gt;.
As you might expect, the Perl version was pretty fast.  It proved faster than the
other scripting-language implementations I tried (in this rather unscientific benchmark, not to be taken seriously):&lt;/p&gt;


&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Implementation&lt;/th&gt;&lt;th&gt;Run time (s)&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href="http://blog.moertel.com/articles/2006/08/15/solving-the-google-code-jam-countpaths-problem-in-haskell"&gt;Haskell&lt;/a&gt;&lt;/td&gt;
    &lt;td&gt;0.9&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Perl (code below)&lt;/td&gt;
    &lt;td&gt;1.7&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href="http://my.opera.com/ipeev/blog/show.dml/409336"&gt;Python&lt;/a&gt;&lt;/td&gt;
    &lt;td&gt;2.8&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href="http://blog.moertel.com/articles/2006/08/16/solving-the-google-code-jam-countpaths-problem-in-ruby"&gt;Ruby&lt;/a&gt;&lt;/td&gt;
    &lt;td&gt;4.2&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

	&lt;p&gt;All timings were taken while solving the maximum-size, all-the-same-letter
problem on my 1.8-GHz Opteron box.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s the Perl implementation:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;#!/usr/bin/perl

# Tom Moertel &amp;lt;tom@moertel.com&amp;gt;
# 2006-08-16
#
# Perl-based solution to the Google Code Jam problem "countPaths".
# See http://www.cs.uic.edu/~hnagaraj/articles/code-jam/ for more.

use strict;
use warnings;

use List::Util 'sum';
use Math::BigInt;

sub count_paths {

  my ($grid, $word) = @_;

  my $rword  = reverse $word;
  my $rowmax = $#$grid;
  my $colmax = length($grid-&amp;gt;[0]);
  my ($slab, $sum);

  for my $i (0 .. length($rword) - 1) {
    my $char = substr $rword, $i, 1;
    ($slab, my $previous_slab) = ([], $slab);
    for my $r (0 .. $rowmax) {
      my ($row, $line) = ($grid-&amp;gt;[$r], $slab-&amp;gt;[$r] ||= []);
      for my $c (0 .. $colmax) {
        $line-&amp;gt;[$c] = $char ne substr($row,$c,1) ? 0 : $i == 0 ? 1 : do {
          $sum = 0;
          my $clo = $c &amp;gt; 0 ? $c - 1 : $c;
          my $chi = $c &amp;lt; $colmax ? $c + 1 : $c;
          for my $nr (($r&amp;gt;0 ? $r-1 : $r) .. ($r&amp;lt;$rowmax ? $r+1 : $r)) {
            for my $nc ($clo .. $chi) {
              $sum += $previous_slab-&amp;gt;[$nr][$nc]
                if $nr != $r || $nc != $c;
            }
          }
          $sum;
        }
      }
    }
  }

  sum map @$_, @$slab;
}

print count_paths([("A"x50)x50], "A"x50), $/;
# 3.03835410591851e+47
&lt;/code&gt;&lt;/pre&gt;

&lt;div class="update"&gt; &lt;strong&gt;Update:&lt;/strong&gt; I simplified the code a whisper by
removing an unnecessary variable &lt;code&gt;$counts&lt;/code&gt;.  Here&amp;#8217;s a diff
if you&amp;#8217;re curious about what&amp;#8217;s changed:

&lt;pre&gt;&lt;code&gt;--- countpaths.pl.orig  2006-08-18 00:16:56.000000000 -0400
+++ /countpaths.pl      2006-08-18 00:19:30.000000000 -0400
@@ -19,11 +19,11 @@
   my $rword  = reverse $word;
   my $rowmax = $#$grid;
   my $colmax = length($grid-&amp;gt;[0]);
-  my ($counts, $slab, $sum);
+  my ($slab, $sum);

   for my $i (0 .. length($rword) - 1) {
     my $char = substr $rword, $i, 1;
-    ($slab, my $previous_slab) = ($counts-&amp;gt;[$i] ||= [], $slab);
+    ($slab, my $previous_slab) = ([], $slab);
     for my $r (0 .. $rowmax) {
       my ($row, $line) = ($grid-&amp;gt;[$r], $slab-&amp;gt;[$r] ||= []);
       for my $c (0 .. $colmax) {
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;strong&gt;Update 2:&lt;/strong&gt; Augmented the introductory paragraph with a parenthetical
comment that reminds readers that these single-fuzzy-data-point-style
timings should not be taken seriously.  Also removed the word
&amp;#8220;bested,&amp;#8221; which might suggest that there is an optimization
contest in play.  Please, no wagering.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update 3:&lt;/strong&gt; Stripped another variable (&lt;code&gt;$j&lt;/code&gt;), which was
completely unused and leftover from previous implementation.  (See
why you shouldn&amp;#8217;t code late at night?)&lt;/p&gt;


&lt;/div&gt;</description>
      <pubDate>Thu, 17 Aug 2006 02:21:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:53c5a877-68a2-450b-8d93-6bdbbd5ffd59</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2006/08/17/solving-the-google-code-jam-countpaths-problem-in-perl</link>
      <category>programming</category>
      <category>perl</category>
      <category>fun stuff</category>
      <category>google</category>
      <category>code</category>
      <category>jam</category>
      <category>wordpaths</category>
      <category>countpaths</category>
      <category>puzzles</category>
      <category>perl</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/160</trackback:ping>
    </item>
    <item>
      <title>Solving the Google Code Jam &amp;quot;countPaths&amp;quot; problem in Haskell</title>
      <description>&lt;p&gt;Via the &lt;a href="http://developers.slashdot.org/article.pl?sid=06/08/14/2146220"&gt;article on this year&amp;#8217;s Google Code
Jam&lt;/a&gt; on
&lt;a href="http://slashdot.org/"&gt;Slashdot&lt;/a&gt; earlier today, I found &lt;a href="http://www.cs.uic.edu/~hnagaraj/"&gt;Hareesh Nagarajan&lt;/a&gt;&amp;#8217;s &lt;a href="http://www.cs.uic.edu/~hnagaraj/articles/code-jam/"&gt;write-up of a previous
year&amp;#8217;s Code-Jam
problem&lt;/a&gt;.  Since
Google often comes up with interesting problems, I decided to give
this one a go.&lt;/p&gt;


	&lt;h3&gt;The problem: count the ways to find a word by walking on a grid&lt;/h3&gt;


	&lt;p&gt;You are given a rectangular grid of letters and a word to find.
You must compute the number of ways to find the word within the grid
using the following rules:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;start at any cell within the grid&lt;/li&gt;
		&lt;li&gt;from there, move to any of the cell&amp;#8217;s eight neighboring cells&lt;/li&gt;
		&lt;li&gt;continue moving from that neighbor to its neighbors, and so on,
  until you have spelled out the word&lt;/li&gt;
		&lt;li&gt;you may visit cells more than once, but you cannot visit
  the same cell twice in a row (i.e., you must &lt;em&gt;move&lt;/em&gt; for each turn)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;For instance, consider the following grid, taken from the examples in
the problem statement:&lt;/p&gt;


&lt;pre&gt;ABC
FED
GAI
&lt;/pre&gt;

	&lt;p&gt;If you were asked to find the word &amp;#8220;AEA&amp;#8221; on this grid, you could do it in
four ways:&lt;/p&gt;


&lt;pre&gt;Way  --Move---
     1   2   3

1:  *BC ABC *BC
    FED F*D FED
    GAI GAI GAI

2:  *BC ABC ABC
    FED F*D FED
    GAI GAI G*I

3:  ABC ABC *BC
    FED F*D FED
    G*I GAI GAI

4:  ABC ABC ABC
    FED F*D FED
    G*I GAI G*I
&lt;/pre&gt;

	&lt;p&gt;If you were asked to find &amp;#8220;ABCD&amp;#8221;, you could do it in only one way:&lt;/p&gt;


&lt;pre&gt;Way  --Move-------- 
     1   2   3   4 

1:  *BC A*C AB* ABC
    FED FED FED FE*
    GAI GAI GAI GAI
&lt;/pre&gt;

	&lt;p&gt;If you were asked to find &amp;#8220;AAB&amp;#8221;, you could not:
there are no &amp;#8220;A&amp;#8221; cells on the grid that have other &amp;#8220;A&amp;#8221; cells
as neighbors.&lt;/p&gt;


	&lt;h3&gt;The tricksy nature of the problem&lt;/h3&gt;


	&lt;p&gt;As you might expect from Google, this puzzle was designed to see
whether your solution can scale.  A simple search will quickly bog
down because each step in the search can expand into vastly more
possibilities, as searching for &amp;#8220;AAAA&amp;#8221; on a seemingly harmless 2&amp;#xD7;2
grid of all &amp;#8220;A&amp;#8221; cells shows &amp;#8211; there are 108 solutions.&lt;/p&gt;


	&lt;p&gt;The problem statement says that the grid may be up to 50&amp;#xD7;50 in
size and the word to find may be up to 50 letters long.  Imagine,
then, that you are asked to find a word composed of 50 &amp;#8220;A&amp;#8221; letters
within a 50&amp;#xd7;50 grid of &amp;#8220;A&amp;#8221; cells.  All of the cells will be valid
starting points, and each will have, on average, slightly less than 8
valid neighbors.  Thus there will be about
50&amp;#160;&amp;#xd7;&amp;#160;50&amp;#160;&amp;#xd7;&amp;#160;8^49 = 4.5e47 ways to find
the word&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;.  Tracing them all would take forever.&lt;/p&gt;


	&lt;p&gt;The trick is figuring out a more efficient way to solve the problem.
Since that&amp;#8217;s the fun part of this problem, I won&amp;#8217;t spoil it for you
by telling you how I did it.  (If you truly want spoilers, you can study
my code.)&lt;/p&gt;


	&lt;h3&gt;My solution&lt;/h3&gt;


	&lt;p&gt;Here is what I came up with.  I&amp;#8217;ll present the code first and then
discuss how to use it.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;The code below is out of date but printed here for
continuity.  See Update 5 for the most-recent revision.&lt;/em&gt;&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;{-

Tom Moertel &amp;lt;tom@moertel.com&amp;gt;
2006-08-15

Haskell-based solution to the Google Code Jam problem "countPaths";
see http://www.cs.uic.edu/~hnagaraj/articles/code-jam/ for more.

-}

module Main (main) where

import Control.Monad
import Data.Array
import qualified Data.Map as M

main = do
    word:gridspec &amp;lt;- liftM words getContents
    print $ (countPaths word (toGridArray gridspec) :: Integer)

countPaths word@(p:_) gridArray =
    sum . M.elems $ foldl step state0 (zip word (tail word))
  where
    state0 = M.fromList [(cell, 1) | (cell, q) &amp;lt;- assocs gridArray, p == q]
    neighbors = toNeighborMap gridArray
    step state fromto = M.fromListWith (+) $ do
        steps &amp;lt;- M.lookup fromto neighbors
        (start, count) &amp;lt;- M.assocs state
        cells &amp;lt;- M.lookup start steps
        cell &amp;lt;- cells
        return (cell, count)

toGridArray gridspec@(l1:_) =
    listArray ((1,1), (length gridspec, length l1)) (concat gridspec)

toNeighborMap gridArray =
    M.fromListWith (M.unionWith (flip (++))) $ do
        (cell, p) &amp;lt;- assocs gridArray
        cell' &amp;lt;- neighbors8 cell
        guard $ inRange (bounds gridArray) cell'
        return ((p, gridArray!cell'), M.singleton cell [cell'])

neighbors8 (r,c) =
    [(r+h, c+v) | h &amp;lt;- [-1..1], v &amp;lt;- [-1..1], h /= 0 || v /= 0]

-- Local Variables:  ***
-- compile-command: "ghc -O2 -o wordpath --make WordPath.hs" ***
-- End: ***
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;My solution generalizes upon the problem statement in a few ways:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;the grid can be any size and the word any length&lt;/li&gt;
		&lt;li&gt;the grid and word can be composed of any comparable data type, not just A&amp;#8211;Z letters (if you use the stdin interface, the code will use Unicode characters)&lt;/li&gt;
		&lt;li&gt;the code will compute exact counts instead of returning -1 for counts greater than 1e9&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;You can enter problems from the command line.  Enter the word first
and then the grid, each row separated by whitespace.  For example:&lt;/p&gt;


&lt;pre&gt;$ &lt;code&gt;./wordpath
AAAAAAAAAAA

AAAAA
AAAAA
AAAAA
AAAAA
AAAAA
^D&lt;/code&gt;

2745564336
&lt;/pre&gt;

	&lt;h3&gt; Give it a try&lt;/h3&gt;


	&lt;p&gt;This was a fun problem to solve.  If you have a little spare time,
give it a try.  I would love to compare results and talk about
strategies.&lt;/p&gt;


&lt;div class="update"&gt;

	&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Fixed typo: Finding &amp;#8220;AAAA&amp;#8221; &amp;#8211; not &amp;#8220;AA&amp;#8221; &amp;#8211; on
a 2&amp;#xd7;2 grid of all &amp;#8220;A&amp;#8221; letters results in a count of 108.  Thanks to Joshua Volz for pointing out my mistake.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update 2:&lt;/strong&gt;  Here&amp;#8217;s a dynamic-programming-based implementation of &lt;em&gt;countPaths&lt;/em&gt; that is
about six times faster than my original implementation when solving the
maximum-size, all-the-same-letter problem:&lt;/p&gt;


&lt;pre&gt;&lt;code style="font-size: smaller"&gt;countPaths word gridArray =
    sum [counts ! (length word, cell) | cell &amp;lt;- cells]
  where
    counts = listArray ((1, (1, 1)), (length word, gridSize)) $
             [countFrom i cell | i &amp;lt;- [1..length word], cell &amp;lt;- cells]

    countFrom i cell
        | i == 1 &amp;#38;&amp;#38; match = 1
        | match           = sum [counts!((i-1),n) | n &amp;lt;- neighbors!cell]
        | otherwise       = 0
      where
        match = rword ! i == gridArray ! cell

    neighbors = listArray (bounds gridArray) $
        [filter (inRange (bounds gridArray)) (neighbors8 cell)
            | cell &amp;lt;- cells ]

    rword    = listArray (1, length word) (reverse word)
    cells    = indices gridArray
    gridSize = snd (bounds gridArray)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;See &lt;a href="http://programming.reddit.com/info/dni1/comments/cdp59"&gt;the thread started by &amp;#8216;psykotic&amp;#8217; on reddit.com&lt;/a&gt; for more.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update 3:&lt;/strong&gt;  &lt;a href="http://my.opera.com/ipeev/blog/"&gt;Ivan Peev&lt;/a&gt; has solved the problem in Python: &lt;a href="http://my.opera.com/ipeev/blog/show.dml/409336"&gt;Solving the Google Code Jam &amp;#8216;countPaths&amp;#8217; problem in Python&lt;/a&gt;.  Because his implementation uses the same algorithm that my implementation in Update 2 does, it makes a good vehicle for Haskell-versus-Python speed comparisons, an interesting topic in light of the warning Google provides about using Python in the Google Code Jam:&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;: All submissions have a maximum of 2 seconds of runtime
per test case. This limit is used in harder problems to
force submissions to be of a certain complexity. Because of
the inherent speed differences between Python and the other
offered languages is large, some problems may require extra
optimization or not be solvable using the Python language.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;Ivan reports that his Python implementation solves the maximum-size, all-the-same-letter problem in about 8 seconds on an old 1-GHz &lt;span class="caps"&gt;AMD&lt;/span&gt; Athlon.  The Haskell version comes in somewhat faster at 0.9 second on a 1.8-GHz &lt;span class="caps"&gt;AMD&lt;/span&gt; Opteron.  (On the same Opteron, Ivan&amp;#8217;s code clocks in at 2.8 seconds, which is impressive.)&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update 4:&lt;/strong&gt; I have added &lt;a href="http://blog.moertel.com/articles/2006/08/16/solving-the-google-code-jam-countpaths-problem-in-ruby"&gt;a Ruby implementation&lt;/a&gt; and &lt;a href="http://blog.moertel.com/articles/2006/08/17/solving-the-google-code-jam-countpaths-problem-in-perl"&gt;a Perl implementation&lt;/a&gt; and timings, too.  On the the maximum-size, all-the-same-letter problem, Ruby clocks in at 4.2 seconds; Perl in 1.7 seconds.  See the Perl implementation for a summary table of the timings.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update 5:&lt;/strong&gt; As I promised reader Kartik in a comment, here is a
further-simplified, yet 25-percent-faster, version of my
implementation in Update 2.  This version eliminates the cache in
favor of a current-state array that is folded through the successive
letters of the target word.  The result of the fold operation is the
final state array, whose elements are summed to yield the final
result.  Here&amp;#8217;s the complete code:&lt;/p&gt;


&lt;pre&gt;&lt;code style="font-size: smaller"&gt;{-

Tom Moertel &amp;lt;tom@moertel.com&amp;gt;
2006-08-15 (revised 2006-09-01)

Haskell-based solution to the Google Code Jam problem "countPaths" 
See http://www.cs.uic.edu/~hnagaraj/articles/code-jam/ for more.

This implementation is based on the dynamic-programming strategy
mentioned by reddit.com user "psykotic":
http://programming.reddit.com/info/dni1/comments/cdp59.

-}

module Main (main) where

import Control.Monad
import Data.Array

main = do
    word:gridspec &amp;lt;- liftM words getContents
    print $ (countPaths word (toGridArray gridspec) :: Integer)

countPaths word grid =
    sum . elems $ foldl move counts0 (tail (reverse word))
  where
    move counts c  = step c $ sum . map (counts!) . neighbors
    counts0        = step (last word) (const 1)
    step c f       = listArray (bounds grid) $ map (match c f) cells
    match c f cell = if c == grid!cell then f cell else 0
    neighbors cell = filter (inRange (bounds grid)) (neighbors8 cell)
    cells          = indices grid

toGridArray gridspec@(l1:_) =
    listArray ((1,1), (length gridspec, length l1)) (concat gridspec)

neighbors8 (r,c) =
    [(h, v) | h &amp;lt;- [r-1..r+1], v &amp;lt;- [c-1..c+1], h /= r || v /= c]

-- Local Variables:  ***
-- compile-command: "ghc -O2 -o wordpathdp --make WordPathDP.hs" ***
-- End: ***
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;hr /&gt;

	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt;  I believe that the exact count is
303&amp;#160;835&amp;#160;410&amp;#160;591&amp;#160;851&amp;#160;117&amp;#160;616&amp;#160;135&amp;#160;618&amp;#160;108&amp;#160;340&amp;#160;196&amp;#160;903&amp;#160;254&amp;#160;429&amp;#160;200 (approx. 3.04e47).  It takes about &lt;del&gt;six seconds&lt;/del&gt; 0.75 second to compute on a 1.8-GHz &lt;span class="caps"&gt;AMD64&lt;/span&gt; box running Linux.&lt;/p&gt;</description>
      <pubDate>Tue, 15 Aug 2006 17:01:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:2521f94c-63b3-4a99-8595-0dfa3db7a120</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2006/08/15/solving-the-google-code-jam-countpaths-problem-in-haskell</link>
      <category>programming</category>
      <category>haskell</category>
      <category>fun stuff</category>
      <category>haskell</category>
      <category>google</category>
      <category>code</category>
      <category>jam</category>
      <category>wordpaths</category>
      <category>countpaths</category>
      <category>puzzles</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/154</trackback:ping>
    </item>
    <item>
      <title>The &amp;quot;perfect shuffles&amp;quot; puzzle (solved in Haskell)</title>
      <description>&lt;p&gt;I ran across a fun programming puzzle (via
&lt;a href="http://weblog.raganwald.com/2006/03/encounter-with-programming-interview.html"&gt;Raganwald&lt;/a&gt;):&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Given a deck of &lt;em&gt;n&lt;/em&gt; unique cards, cut the deck &lt;em&gt;i&lt;/em&gt; cards from top
    and perform a perfect shuffle. A perfect shuffle begins by putting
    down the bottom card from the top portion of the deck followed by
    the bottom card from the bottom portion of the deck followed by
    the next card from the top portion, etc., alternating cards until
    one portion is used up. The remaining cards go on top. The problem
    is to find the number of perfect shuffles required to return the
    deck to its original order. Your function should be declared as:&lt;/p&gt;
    &lt;p&gt;&lt;code&gt;static long shuffles(int nCards,int iCut);&lt;/code&gt;&lt;/p&gt;
    &lt;p&gt;Please send the result of shuffles(1002,101) along with your
    program and your resume to &amp;#8216;resume&amp;#8217; at nextag.com.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;It&amp;#8217;s a fun problem, so give it a try before reading on.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Warning: small spoilers ahead&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The first thing I usually do when I encounter a new problem is explore
it until I have a feel for its essence.  For this problem, the
shuffle algorithm seemed like a good starting point:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;shuffle&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='varid'&gt;reverse&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;uncurry&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;flip&lt;/span&gt; &lt;span class='varid'&gt;interleave&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;splitAt&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;n&lt;/span&gt;&lt;span class='comment'&gt;-&lt;/span&gt;&lt;span class='varid'&gt;i&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;reverse&lt;/span&gt;

&lt;span class='varid'&gt;interleave&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;x&lt;/span&gt;&lt;span class='conop'&gt;:&lt;/span&gt;&lt;span class='varid'&gt;xs&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;y&lt;/span&gt;&lt;span class='conop'&gt;:&lt;/span&gt;&lt;span class='varid'&gt;ys&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;x&lt;/span&gt; &lt;span class='conop'&gt;:&lt;/span&gt; &lt;span class='varid'&gt;y&lt;/span&gt; &lt;span class='conop'&gt;:&lt;/span&gt; &lt;span class='varid'&gt;interleave&lt;/span&gt; &lt;span class='varid'&gt;xs&lt;/span&gt; &lt;span class='varid'&gt;ys&lt;/span&gt;
&lt;span class='varid'&gt;interleave&lt;/span&gt; &lt;span class='varid'&gt;xs&lt;/span&gt;     &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;     &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;xs&lt;/span&gt;
&lt;span class='varid'&gt;interleave&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;     &lt;span class='varid'&gt;ys&lt;/span&gt;     &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;ys&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;From within GHCi, I watched a few iterations, using a ten-card deck as
input:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;*&lt;/span&gt;&lt;span class='conid'&gt;Main&lt;/span&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;mapM_&lt;/span&gt; &lt;span class='varid'&gt;print&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;take&lt;/span&gt; &lt;span class='num'&gt;10&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;iterate&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;shuffle&lt;/span&gt; &lt;span class='num'&gt;10&lt;/span&gt; &lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='keyglyph'&gt;..&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;2&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;4&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;5&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;7&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;8&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;4&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;5&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;7&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;8&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;2&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;7&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;8&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;4&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;2&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;5&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;8&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;4&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;2&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;7&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;5&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;4&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;2&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;7&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;8&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;5&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;2&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;7&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;8&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;5&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;4&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;5&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;4&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;2&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;7&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;8&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;4&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;2&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;7&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;5&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;8&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;7&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;5&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;8&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;4&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;2&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;8&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;4&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;3&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;9&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;7&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;2&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='num'&gt;5&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;After a bit of study, a light-bulb appeared over my head, and I
realized something about the fundamental nature of the problem that I
had overlooked earlier.  (I won&amp;#8217;t spoil the fun by saying what it
was.)  From that point, the solution was easy to implement:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;module&lt;/span&gt; &lt;span class='conid'&gt;Main&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;main&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;where&lt;/span&gt;

&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='conid'&gt;Control&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;Monad&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;liftM&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='conid'&gt;Data&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;Array&lt;/span&gt;
&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='conid'&gt;Data&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;Set&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Set&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;empty&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;insert&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;member&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='keyword'&gt;import&lt;/span&gt; &lt;span class='conid'&gt;System&lt;/span&gt;&lt;span class='varop'&gt;.&lt;/span&gt;&lt;span class='conid'&gt;Environment&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;getArgs&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;main&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
    &lt;span class='varid'&gt;n&lt;/span&gt;&lt;span class='conop'&gt;:&lt;/span&gt;&lt;span class='varid'&gt;i&lt;/span&gt;&lt;span class='conop'&gt;:&lt;/span&gt;&lt;span class='keyword'&gt;_&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;liftM&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='varid'&gt;read&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;getArgs&lt;/span&gt;
    &lt;span class='varid'&gt;print&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;shuffles&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;shuffles&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Int&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;Int&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;Integer&lt;/span&gt;
&lt;span class='varid'&gt;shuffles&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='varid'&gt;foldl&lt;/span&gt; &lt;span class='varid'&gt;lcm&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='varid'&gt;toInteger&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;fst&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;foldl&lt;/span&gt; &lt;span class='varid'&gt;dfs&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;empty&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;deck'&lt;/span&gt;
  &lt;span class='keyword'&gt;where&lt;/span&gt;
    &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;deck&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;deck'&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;  &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt; &lt;span class='keyglyph'&gt;..&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt;&lt;span class='comment'&gt;-&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;shuffle&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='varid'&gt;deck&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
    &lt;span class='varid'&gt;perms&lt;/span&gt;          &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;array&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt;&lt;span class='comment'&gt;-&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;zip&lt;/span&gt; &lt;span class='varid'&gt;deck'&lt;/span&gt; &lt;span class='varid'&gt;deck&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
    &lt;span class='varid'&gt;dfs&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;ls&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;vs&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;j&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='varid'&gt;member&lt;/span&gt; &lt;span class='varid'&gt;j&lt;/span&gt; &lt;span class='varid'&gt;vs&lt;/span&gt; &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;ls&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;vs&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;l&lt;/span&gt;&lt;span class='conop'&gt;:&lt;/span&gt;&lt;span class='varid'&gt;ls&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;vs'&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
                     &lt;span class='keyword'&gt;where&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;l&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;vs'&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;follow&lt;/span&gt; &lt;span class='num'&gt;0&lt;/span&gt; &lt;span class='varid'&gt;j&lt;/span&gt; &lt;span class='varid'&gt;vs&lt;/span&gt;
    &lt;span class='varid'&gt;follow&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='varid'&gt;vs&lt;/span&gt;  &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='varid'&gt;member&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='varid'&gt;vs&lt;/span&gt; &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;n&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='varid'&gt;vs&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
                     &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='varid'&gt;follow&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;n&lt;/span&gt;&lt;span class='varop'&gt;+&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;perms&lt;/span&gt;&lt;span class='varop'&gt;!&lt;/span&gt;&lt;span class='varid'&gt;i&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;insert&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='varid'&gt;vs&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;shuffle&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='varid'&gt;reverse&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;uncurry&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;flip&lt;/span&gt; &lt;span class='varid'&gt;interleave&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;splitAt&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;n&lt;/span&gt;&lt;span class='comment'&gt;-&lt;/span&gt;&lt;span class='varid'&gt;i&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;reverse&lt;/span&gt;

&lt;span class='varid'&gt;interleave&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;x&lt;/span&gt;&lt;span class='conop'&gt;:&lt;/span&gt;&lt;span class='varid'&gt;xs&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;y&lt;/span&gt;&lt;span class='conop'&gt;:&lt;/span&gt;&lt;span class='varid'&gt;ys&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;x&lt;/span&gt; &lt;span class='conop'&gt;:&lt;/span&gt; &lt;span class='varid'&gt;y&lt;/span&gt; &lt;span class='conop'&gt;:&lt;/span&gt; &lt;span class='varid'&gt;interleave&lt;/span&gt; &lt;span class='varid'&gt;xs&lt;/span&gt; &lt;span class='varid'&gt;ys&lt;/span&gt;
&lt;span class='varid'&gt;interleave&lt;/span&gt; &lt;span class='varid'&gt;xs&lt;/span&gt;     &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;     &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;xs&lt;/span&gt;
&lt;span class='varid'&gt;interleave&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;     &lt;span class='varid'&gt;ys&lt;/span&gt;     &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;ys&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The following command compiles the program:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;$ ghc -O2 -o shuffle --make PerfectShuffle.hs
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The program computes the requested solution in about 4&amp;nbsp;ms on my
1.8-GHz box:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;$ time ./shuffle 1002 101
5812104600

real    0m0.006s
user    0m0.004s
sys     0m0.004s
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If you Google around, you can find other solutions, most of them
implemented in Java.&lt;/p&gt;


	&lt;h3&gt;Solve puzzles!  They&amp;#8217;re good for you.&lt;/h3&gt;


	&lt;p&gt;Solving programming puzzles is a fun way to exercise parts of the
brain that day-to-day coding rarely uses.  If you are looking for
some more puzzles, check out what&amp;#8217;s archived at the &lt;a href="http://community.moertel.com/ss/space/Programming+Fun+Challenge"&gt;Programming
Fun Challenge&lt;/a&gt;
page.  Some are simple but others are downright tricksy.&lt;/p&gt;


&lt;div class="update"&gt;
&lt;strong&gt;Update 2006-03-24:&lt;/strong&gt; Last night I thought of a simple optimization to
my original implementation, and this morning I revised my code.  The
optimization reduces the run time for the (1002, 101) case from about
16&amp;nbsp;ms to about 4&amp;nbsp;ms.  I have replaced the original code from
this article with the new code, which is slightly longer.  For comparison, here is the original implementation:

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;shuffles&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Int&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;Int&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;Integer&lt;/span&gt;
&lt;span class='varid'&gt;shuffles&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='varid'&gt;foldl&lt;/span&gt; &lt;span class='varid'&gt;lcm&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;fromIntegral&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;cycleLength&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;deck'&lt;/span&gt;
  &lt;span class='keyword'&gt;where&lt;/span&gt;
    &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;deck&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;deck'&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='keyglyph'&gt;..&lt;/span&gt;&lt;span class='varid'&gt;n&lt;/span&gt;&lt;span class='comment'&gt;-&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;shuffle&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='varid'&gt;deck&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
    &lt;span class='varid'&gt;perms&lt;/span&gt;         &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;array&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt;&lt;span class='comment'&gt;-&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;zip&lt;/span&gt; &lt;span class='varid'&gt;deck'&lt;/span&gt; &lt;span class='varid'&gt;deck&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
    &lt;span class='varid'&gt;cycleLength&lt;/span&gt; &lt;span class='varid'&gt;j&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;follow&lt;/span&gt; &lt;span class='varid'&gt;j&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;perms&lt;/span&gt;&lt;span class='varop'&gt;!&lt;/span&gt;&lt;span class='varid'&gt;j&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Int&lt;/span&gt;
    &lt;span class='varid'&gt;follow&lt;/span&gt; &lt;span class='varid'&gt;i0&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='varid'&gt;i&lt;/span&gt; &lt;span class='varop'&gt;==&lt;/span&gt; &lt;span class='varid'&gt;i0&lt;/span&gt; &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='varid'&gt;follow&lt;/span&gt; &lt;span class='varid'&gt;i0&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;n&lt;/span&gt;&lt;span class='varop'&gt;+&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;perms&lt;/span&gt;&lt;span class='varop'&gt;!&lt;/span&gt;&lt;span class='varid'&gt;i&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;&lt;strong&gt;Update 2006-03-25:&lt;/strong&gt; I replaced the optimized code with a slightly more idiomatic version.
I did this because I was guilt-tripped by a comment on Reddit saying that Haskell looked &amp;#8220;ugly.&amp;#8221; This code is, in fact, pretty ugly as far as Haskell goes.  (Tip: Don&amp;#8217;t judge a language based on a single sample, especially if it&amp;#8217;s this one. If you want to see more beautiful code, &lt;a href="http://community.moertel.com/~thor/acm-contest-1996/"&gt;my  Haskell solutions&lt;/a&gt; to &lt;a href="http://www.ntnu.edu.tw/acm/ProblemSetArchive/A_FINALS/1996/Finals96html/"&gt;the 1996 &lt;span class="caps"&gt;ACM&lt;/span&gt; International Collegiate Programming Contest&lt;/a&gt; are much less offensive.)&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update 2006-11-04:&lt;/strong&gt; Colorized the Haskell snippets.&lt;/p&gt;


&lt;/div&gt;</description>
      <pubDate>Thu, 23 Mar 2006 16:51:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:ce0388053c2b36cae46a6675af744f40</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2006/03/23/the-perfect-shuffles-puzzle-solved-in-haskell</link>
      <category>programming</category>
      <category>haskell</category>
      <category>fun stuff</category>
      <category>haskell</category>
      <category>puzzles</category>
      <category>shuffles</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/60</trackback:ping>
    </item>
  </channel>
</rss>
