KEEP K.I.S.S.

tk's blog

Euler Project Problem 11 with Ruby

不多说了,题目

 

In the 20×20 grid below, four numbers along a diagonal line have been marked in red.

08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48

The product of these numbers is 26 × 63 × 78 × 14 = 1788696.

What is the greatest product of four adjacent numbers in any direction (up, down, left, right, or diagonally) in the 20×20 grid?

我的 Ruby 解法代码,

 

#!/d/ruby192/bin/ruby
#coding:utf-8

grid = %Q{
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48}

$array = grid.scan(/\d\d/)

def get_value(x, y)
  ret = $array[y*20+x]
  if ret
    ret.to_i
  else
    0
  end
end

def get_most(x,y)
  m = []
  m << get_value(x,y)*get_value(x+1,y)*get_value(x+2,y)*get_value(x+3,y) 
  m << get_value(x,y)*get_value(x,y+1)*get_value(x,y+2)*get_value(x,y+3)
  m << get_value(x,y)*get_value(x+1,y+1)*get_value(x+2,y+2)*get_value(x+3,y+3)
  m << get_value(x,y)*get_value(x+1,y-1)*get_value(x+2,y-2)*get_value(x+3,y-3)
  m.max
end
$most = 0
for x in 0...20 
  for y in 0...20
    if $most < get_most(x,y)
      $most = get_most(x,y)
    end
  end
end

puts $most
   
   

不过感觉这写的还是不够优雅。。。。

Yield in Ruby

# 这是一篇转载的文章,From http://fairleads.blogspot.com/2007/06/ruby-yield.html

Yield 是 Ruby 里面一个很独特的关键字,这篇文章可以帮助你很好的理解她。


 

TUESDAY, JUNE 5, 2007


Ruby Yield

 

 

Yield is one of the most powerful concepts implemented in the Ruby programming language. Yield lets you branch from within a method and execute some external code, then return to the original code in the first method.
 

What's so special about yield in Ruby? You could get the same branch and return flow by just executing a method call in java, or a function call in C. 
 

Heck, COBOL's PERFORM verb implements branch and return behavior. So what's up with yield?
 

Well, the behavior of what you branch to is set in stone with all those other techniques, but is undetermined until coded in RubyYield is kind of like a place holder that says "I'm going to branch off and do something here, but I don't know what I'm going to do yet".
 

Maybe some examples will help make it more clear. Here is a Ruby method with some yields coded in it, then the code to invoke the method and the block of code to invoke when the yield is encountered:

 

def block1
 puts "Start of block1..."
 yield
 yield
 puts "End of block1."
end

block1 {puts "yielding..."}

Running this code would produce the following output:

 

Start of block1...
yielding...
yielding...
End of block1.

So block1 executes it's first line and prints "Start of block1...", then it executes the yields which branch to the block of code outside block1 but associated with it at run time, then comes back and prints "End of block1."

OK that's, fine but isn't that functionally the same as the following code:

 

def block2
 puts "Start of block2..."
 put_it("in put_it called method...")
 put_it("still in put_it called method...")
 puts "End of block2."
end

def put_it(text)
 puts text
end

block2

Running this second set of code produces the following:

 

Start of block2...
in put_it called method...
still in put_it called method...
End of block2.

For the most part, these are pretty much the same. However without having to redefine any methods I could immediately execute the block1 method with a different block associated with it. The yield would branch and execute this newly associated logic:

 

block1 {require 'time' 
 puts Time.now.httpdate}

This produces the output:

 

Start of block1...
Tue, 05 Jun 2007 19:20:35 GMT
Tue, 05 Jun 2007 19:20:35 GMT
End of block1.

The hard coded function call in block2 forever ties the branching logic to the put_it function. To get different behavior you would need to either change the function call in block2 to call a different function, or change the behavior of the function put_it. This second way is brittle because it could break code elsewhere that calls put_it. The first is cumbersome and possibly brittle.

Ruby's yield is a wonderful construct.

What about when you don't want to branch, but want the other functionality in the block1 code to be executed? Can you just run the code without the associated block?

Let's see what happens. Running block1 without an attached block for the yield to associate to:

block1

This produces the result:

Start of block1...
LocalJumpError: no block given
from :3:in 'block1'
from :7
from :0

We get a 'no block given' error at line 3 in method 'block1'. Line 3 is our first yield in the block1 method. 

What to do?

We can wrap the yield in an if statement and check for the presence of a block using the block_given? conditional. It returns true if a block was given with the method call, or false if not.

For this example I'll use a slightly more idiomatic way of checking for the presence of a block in ruby:

 

def block3
 puts "Start of block3..."
 yield if block_given?
 puts "End of block3."
end

now if we run the code with a block:

 

block3 { puts "yielding" }

or without:

block3

It works both times producing:

Start of block3...
yielding...
End of block3.

and

Start of block3...
End of block3.

This will make your methods less brittle and more agile. 

Ruby's yield is worth getting to know. You can learn more here and here. Many of Ruby's built in methods contain yields that allow you to associate blocks with them producing added functionality at run time.