<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.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>Talk Like A Duck: Solving the Final Google Treasure Hunt Problem in Ruby</title>
    <link>http://talklikeaduck.denhaven2.com/articles/2008/06/07/solving-the-final-google-treasure-hunt-problem-in-ruby</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>In Ruby, it's not the dog, it's the tricks!</description>
    <item>
      <title>Solving the Final Google Treasure Hunt Problem in Ruby</title>
      <description>For the past four weeks, Google has been running the &lt;a href="http://treasurehunt.appspot.com/"&gt;2008 Google Treasure Hunt&lt;/a&gt;. Each Monday a new question
was asked, requiring a &amp;#8216;simple&amp;#8217; answer.  Actually, each question was parameterized, and the parameters were &amp;#8216;randomly&amp;#8217; generated for each participant.
&lt;p&gt;For each of the four questions, I wrote a Ruby program to find the answer.&lt;/p&gt;
&lt;p&gt;The final question was probably the hardest, and although it&amp;#8217;s still &amp;#8216;alive&amp;#8217;, the spoilers have already started to appear on the internets. &lt;a href="http://www.catonmat.net/blog/solving-google-treasure-hunt-prime-number-problem-four/"&gt;Peter Krumins has posted a solution using unix shell commands,&lt;/a&gt; so I figured I&amp;#8217;d show my Ruby solution&lt;/p&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;As Peter describes the problem is to find the smallest prime number which can be expressed as a sum of several different numbers of consecutive primes. Here&amp;#8217;s the question as Google posed it to me:&lt;/p&gt;
&lt;quote&gt;Find the smallest number that can be expressed as
&lt;p&gt;the sum of 3 consecutive prime numbers,&lt;/p&gt;
&lt;p&gt;the sum of 5 consecutive prime numbers,&lt;/p&gt;
&lt;p&gt;the sum of 275 consecutive prime numbers,&lt;/p&gt;
&lt;p&gt;the sum of 1167 consecutive prime numbers,&lt;/p&gt;
&lt;p&gt;and is itself a prime number.&lt;/p&gt;
&lt;p&gt;
For example, 41 is the smallest prime number that can be expressed as
the sum of 3 consecutive primes (11 + 13 + 17 = 41) and
the sum of 6 consecutive primes (2 + 3 + 5 + 7 + 11 + 13 = 41).&lt;/p&gt;&lt;/quote&gt;
&lt;p&gt;Note that I&amp;#8217;ve got a different set of four numbers of consecutive primes than Peter&amp;#8217;s&lt;/p&gt;
&lt;h2&gt;The Approach&lt;/h2&gt;
&lt;p&gt;I always try to do &amp;#8216;the simplest thing that could possibly work.&amp;#8217;  Like Peter I had no desire to write a prime number generator.  A little googling found me the same source of prime numbers.  I figured as a first guess that the answer would probably lie somewhere within the first million prime numbers, so I downloaded &lt;a href="http://primes.utm.edu/lists/small/millions/primes1.zip"&gt;that list,&lt;/a&gt; and examined the list in Textmate.&lt;/p&gt;
&lt;p&gt;As Peter notes, the file has two lines of header, and then several primes in sequence on each line.  I just deleted the header lines in Textmate and then wrote a class which would read the file and return each prime number in sequence:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;class PrimeReader
  def initialize(file)
    @file = file
    read_line
    yield self
  end

  def next
    read_line if @numbers.empty?
    @numbers.shift.to_i
  end

  def read_line
    @numbers = @file.readline.split(' ')
  end
end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This should be fairly explanatory. PrimeReader reads the file as necessary and hands out each prime number.&lt;/p&gt;
&lt;p&gt;Now that I had a source of consecutive primes it was time to write the code to search for the answer.  Here&amp;#8217;s the outer loop:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;processor&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Processor&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;

&lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;open&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{File.dirname(__FILE__)}&lt;/span&gt;/primes1.txt&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="constant"&gt;PrimeReader&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;primes&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="keyword"&gt;until&lt;/span&gt; &lt;span class="ident"&gt;processor&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;primes&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;next&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The real work is done, in the unimaginatively named Processor.  
The loop reads lines from the PrimeReader until the processor finds the desired prime or end of file generates an exception.&lt;/p&gt;
&lt;p&gt;And here&amp;#8217;s the Processor class:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;class Processor
  def initialize
    @counts = [3, 5, 275, 1167].reverse
    # @counts = [3,6]
    @sums = @counts.inject({}) { |hash, count| hash[count] = []; hash}
    @processed = []
  end

  def test(prime)
    puts &amp;quot;testing #{1+@processed.length}: #{prime} &amp;quot;
    qualifies(prime) || process(prime)
  end

  def qualifies(prime)
    @sums.each_value do | sums |
      return false unless sums.include?(prime)
    end
    report(prime)
    true
  end

  def process(prime)
    @processed &amp;lt;&amp;lt; prime
    @counts.each do |count|
      calc_sum(count)
    end
    false
  end

  def calc_sum(count)
    if @processed.length &amp;gt;= count
      @sums[count] &amp;lt;&amp;lt; @processed[-count,count].inject(0) { |sum, p| sum + p}
    end
  end

  def report(found)
    puts &amp;quot;Found #{found}&amp;quot;
    @counts.each do | count|
      report_sum(count, found)
    end
  end

  def report_sum(count, found)
    sums = @sums[count]
    sum_start = sums.index(found)
    puts &amp;quot;#{found} = #{@processed[sum_start, count].join(&amp;quot; + &amp;quot;)}&amp;quot;
  end
end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The approach I took was to compute the sums and save them in arrays which in turn are the values for each count used as a key in the hash @sums. I keep each prime in the array @processed which is used to calculate the sums.&lt;/p&gt;
&lt;p&gt;I hard coded the parameters in the initialize method, note the commented out assignment to counts, by changing the commenting I could test the code against the example given and show that my code found 41
as the lowest prime expressible by both 3 and 6 consecutive primes.&lt;/p&gt;
&lt;p&gt;The test method reports the number and value of each prime it examines, purely as a &amp;#8216;progress indicator.&amp;#8217; The statment &amp;#8220;qualifies(prime) || process(prime)&amp;#8221; will return true if qualifies returns a truthy value, otherwise it will invoke process which always returns false.&lt;/p&gt;
&lt;p&gt;The qualifies method returns true only if the array for each count contains the current prime, which is the essence of what we are seeking. Otherwise it returns false.&lt;/p&gt;
&lt;p&gt;The process method first appends the new prime to @processed, then calculates the sum for each count using the calc_sum method.  This method determines if we have enough primes in @processed to calculate the particular sum, and if so calculates the sum and appends it to the array for the count.&lt;/p&gt;
&lt;p&gt;Once the answer has been found, the report method prints it and the sums which total to it.  The sums are calculated in the report_sum method.  This method takes a slice out of the @processed array, consisting of the count elements starting at the index where the answer is found in the particular sums array. A bit of reflection will reveal that this is precisely the primes which add to the answer.&lt;/p&gt;
&lt;p&gt;In the case of my parameters, the answer, in case you are wondering is 5,181,901, which was confirmed by Google when I gave my answer. This is the 360,245th prime number by the way.&lt;/p&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
&lt;p&gt;Although this might be a bit of a brute force approach, the performance was acceptable.&lt;/p&gt;
&lt;p&gt;The biggest feature of Ruby which makes this approach feasible is the copy-on-write nature of Ruby arrays.  In Ruby Array#slice (a.k.a. Array#[]) doesn&amp;#8217;t copy the elements of the array, it just creates a new Array with an offset from the beginning of the original array and the length of the result.  As long as neither Array is changed to affect one of the shared elements, nothing is copied, but when a shared element in the source or result array is changed, Ruby first does the copy to preserve the semantics.&lt;/p&gt;
&lt;p&gt;My code does a lot of slicing of the @processed array, but other than appending to the end of the @processed array, the accesses to that array and the slices are read-only, so nothing needs to be copied.&lt;/p&gt;</description>
      <pubDate>Sat, 07 Jun 2008 21:43:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:df213c29-f4d4-46f4-8a4a-a8e22fc115e4</guid>
      <author>Rick DeNatale</author>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/06/07/solving-the-final-google-treasure-hunt-problem-in-ruby</link>
      <category>ruby</category>
      <trackback:ping>http://talklikeaduck.denhaven2.com/articles/trackback/501</trackback:ping>
    </item>
    <item>
      <title>"Solving the Final Google Treasure Hunt Problem in Ruby" by Adriano</title>
      <description>&lt;p&gt;In Processor#initialize I&amp;#8217;d replace&lt;/p&gt;


	&lt;p&gt;@sums = @counts.inject({}) { |hash, count| hash[count] = []; hash}&lt;/p&gt;


	&lt;p&gt;by&lt;/p&gt;


	&lt;p&gt;@sums = Hash.new {|h,count| h[count] = [] }&lt;/p&gt;


	&lt;p&gt;for readibility.&lt;/p&gt;</description>
      <pubDate>Wed, 25 Jun 2008 04:45:29 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:d66d7d4c-5932-4ea9-87b3-60e9215414bf</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/06/07/solving-the-final-google-treasure-hunt-problem-in-ruby#comment-5367</link>
    </item>
    <item>
      <title>"Solving the Final Google Treasure Hunt Problem in Ruby" by Dan Mayer</title>
      <description>&lt;p&gt;I need to do more little exercises like this. It keeps your mind sharp and thinking in a different mindset. When you get so deep into a larger Ruby app, you start to see and think about code in a different way. Many times in large apps you are also solving less interesting problems, silly business login. Anyways, thanks for sharing your solution.&lt;/p&gt;</description>
      <pubDate>Tue, 10 Jun 2008 23:32:03 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:0ed70e23-5fcb-4d78-a330-d99420a6c4db</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/06/07/solving-the-final-google-treasure-hunt-problem-in-ruby#comment-5358</link>
    </item>
    <item>
      <title>"Solving the Final Google Treasure Hunt Problem in Ruby" by ciju</title>
      <description>&lt;p&gt;here&amp;#8217;s a better way. runs in around 0.2 seconds&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://ciju.wordpress.com/2008/06/03/google-treasure-hunt/" rel="nofollow"&gt;http://ciju.wordpress.com/2008/06/03/google-treasure-hunt/&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Tue, 10 Jun 2008 10:26:24 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:16c8e7dd-5286-4726-9bec-d62754a01b6d</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/06/07/solving-the-final-google-treasure-hunt-problem-in-ruby#comment-5354</link>
    </item>
    <item>
      <title>"Solving the Final Google Treasure Hunt Problem in Ruby" by vishal</title>
      <description>&lt;p&gt;Did any one use the information that the solution set of primes had to continuous in &amp;#8220;any other way&amp;#8221; except for a brute force search. I would love to hear that&amp;#8230;&lt;/p&gt;</description>
      <pubDate>Tue, 10 Jun 2008 02:35:15 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:116aa967-b7e1-4e30-9e7f-5faaba64b65a</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/06/07/solving-the-final-google-treasure-hunt-problem-in-ruby#comment-5351</link>
    </item>
    <item>
      <title>"Solving the Final Google Treasure Hunt Problem in Ruby" by Rick DeNatale</title>
      <description>&lt;p&gt;@Corey,&lt;/p&gt;


	&lt;p&gt;Yes it was typo in the problem spec.  I&amp;#8217;ve fixed it.&lt;/p&gt;</description>
      <pubDate>Sun, 08 Jun 2008 17:10:28 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:73168a96-dba1-4739-bd76-97b29992548c</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/06/07/solving-the-final-google-treasure-hunt-problem-in-ruby#comment-5332</link>
    </item>
    <item>
      <title>"Solving the Final Google Treasure Hunt Problem in Ruby" by Peteris Krumins</title>
      <description>&lt;p&gt;Really nice solution in Ruby. Also thanks for linking to my solution! :)&lt;/p&gt;


	&lt;p&gt;Peter&lt;/p&gt;</description>
      <pubDate>Sun, 08 Jun 2008 12:50:15 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:a8db4edd-76b1-4ccd-b6d0-191dfb5b972b</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/06/07/solving-the-final-google-treasure-hunt-problem-in-ruby#comment-5331</link>
    </item>
    <item>
      <title>"Solving the Final Google Treasure Hunt Problem in Ruby" by Corey Martella</title>
      <description>&lt;p&gt;Very slick, nice work! Not sure if its a typo in the code or problem spec but the last series length is 1161 vs 1167 in the spec vs code.&lt;/p&gt;</description>
      <pubDate>Sun, 08 Jun 2008 10:01:12 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:487a79f2-2a5b-4348-b26b-032edccf4efc</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/06/07/solving-the-final-google-treasure-hunt-problem-in-ruby#comment-5329</link>
    </item>
  </channel>
</rss>
