<?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: Solving the Google Code Jam "countPaths" problem in Perl</title>
    <link>http://blog.moertel.com/articles/2006/08/17/solving-the-google-code-jam-countpaths-problem-in-perl</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Quality rants on programming theory and stuff geeks like</description>
    <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 "countPaths" problem in Perl" by Tom Moertel</title>
      <description>&lt;p&gt;Anonymous, I just tried the new, faster Python implementation, and it averaged slightly faster than my Perl code in a ten-run trial, about 1.47 seconds to 1.57 seconds.  Note, however, that those timings are crude: I made them from the command line via &lt;code&gt;/usr/bin/time&lt;/code&gt;; thus the timings incorporate the setup and teardown for the language runtimes, which may swamp the real differences between the implementations.&lt;/p&gt;


	&lt;p&gt;In any case, the new Python version isn&amp;#8217;t &amp;#8220;isomorphic&amp;#8221; to the Perl version anymore because it handles the initial, outermost iteration as a special case and thereby can eliminate a test from the innermost loop of all subsequent iterations.  As such, it&amp;#8217;s probably not a good idea to draw conclusions about the respective languages&amp;#8217; speeds from these comparisons.&lt;/p&gt;</description>
      <pubDate>Fri, 18 Aug 2006 12:37:11 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:a7e4c480-9879-41e0-b308-99a7f4516d88</guid>
      <link>http://blog.moertel.com/articles/2006/08/17/solving-the-google-code-jam-countpaths-problem-in-perl#comment-162</link>
    </item>
    <item>
      <title>"Solving the Google Code Jam "countPaths" problem in Perl" by Anonymous</title>
      <description>&lt;p&gt;&amp;#8220;besting the other scripting languages&amp;#8221;&lt;/p&gt;


	&lt;p&gt;Are you sure you&amp;#8217;re using the &lt;strong&gt;fastest&lt;/strong&gt; one on Ivan&amp;#8217;s page (see the comments), and not his original one?&lt;/p&gt;</description>
      <pubDate>Fri, 18 Aug 2006 03:24:02 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:cb7f62c1-67c5-4b57-9f3c-dbfb20682b17</guid>
      <link>http://blog.moertel.com/articles/2006/08/17/solving-the-google-code-jam-countpaths-problem-in-perl#comment-161</link>
    </item>
  </channel>
</rss>
