Thursday, January 19, 2012

Learning Rails

This week, I've dedicated a good chunk of time to stumbling my way through Rails. I expect to be confused for at least a few more days, but I'm thankful for the abundance of great tutorials and training materials out there for learning the basics of building Rails apps. I'm also glad that I know something about Ruby, Javascript, HTML, and CSS before jumping into Rails—it makes the learning process much easier.

I was surprised by how easy it was to set up a database and create a basic blog using Rails scaffolding. I was also surprised by how much information comes prepackaged in Rails -- jQuery, default stylesheets, etc. I spent some time just reading through the individual files and trying to figure out how all of the pieces work together. While it's nice that it only takes a couple of minutes to create a blog in Rails, I can't say that I fully understand the process, or have the ability to make meaningful modifications (yet).

I'm beginning to learn Rails by working on a Task Queue application concept that I thought of a couple of months ago. Right now, it's just an exercise, but if things go well then it could evolve into a useful application.

As a total beginner, so far this is my favorite Rails resource that I've found.

Monday, January 16, 2012

Divisible by 1 - 20

I learned quite a bit by finding the solution to this Project Euler problem:

2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder. What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?

At first, I attacked the problem with the goal of writing an algorithm that could solve it. I wrote some code that went through a giant array of numbers and checked to see if each one was evenly divisible by each of the numbers 1 - 20. This taught me a lesson in writing fast applications, since my process was using brute force rather than intelligent processes to solve the problem. I happen to be working on a beautiful, vintage 2004 iBook that runs at least some Ruby applications seven times slower than Doug's machine. This means that my brute force method wasn't going to cut it.

I re-wrote my code to eliminate items from the giant array if they weren't evenly divisible by just one of the numbers from 1 - 20, thus saving my computer the trouble of figuring out the remainder of 3, 4, 5, 6... if 31 isn't divisible by 2, anyway. This step alone brought down the speed of figuring out the smallest number divisible by numbers 1 - 10 from 19 seconds to 3.2 seconds. Wow.

Still, this wasn't good enough. The calculation speed was growing exponentially with each additional divisor, and I'm a very impatient person who doesn't like to wait.

I decided that I could also reduce the number of divisors that it was checking. I wrote some code to eliminate unnecessary divisors from a divisor array. Why check to see if it's divisible by 2, 4, or 8 when you already know that it's divisible by 16? Adding in this functionality reduced the time of finding the smallest number divisible by numbers 1 - 10 down from 3.2 seconds to .8 seconds. Progress.

Still, my code was checking too many numbers. Since the final number must be divisible by 20, why not build an array that only contains multiples of 20? Using the step method, I cut down the time to find the smallest number divisible by 1 - 15 from 21 seconds down to 1.98 seconds. Even better.

During lunch, I decided to just let the program run and find the answer for the smallest number divisible by numbers 1 - 20. It took seven minutes. Who knows how long it would have taken to find the answer with my original algorithm. I didn't have the time or patience to find out.

Then, Wai Lee came up to me and said, "Hey, I think I know a way to solve the problem without any code."

This morning, I tested Wai Lee's method with a pen and paper by listing out the multiples of each number 1 - 20, eliminating duplicates, and then multiplying the list of numbers: 5*7*9*11*13*16*17*19.

The result? I was able to come up with the same solution in about three minutes—that's 57% faster than my iBook could solve the problem with my "vastly improved" Ruby algorithm. Go figure.

This whole process taught me that there's a big difference between solving the problem and developing an elegant solution. I'm working on the latter.

If you're curious about what I did, check my spec on Github.

Tuesday, January 10, 2012

Unlocking the Grid

Today I spent more time solving Project Euler problems. I cranked through a number of problems, leaving a couple of them solvable but unsolved. It takes forever to run larger calculations on my iBook G4, especially if you're writing double for-loops to do millions of calculations. Maybe this means that I should use a different machine, but I think it's more likely that I need to think of a clever way to rewrite my code to avoid duplicate calculations.

For example:

# The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
# Find the sum of all the primes below two million.

def prime_array
  numbers = (2..7).to_a
  divisor = 2
  while divisor<10
    numbers.each do |x|
      numbers.delete(x) if x%divisor == 0 && x != divisor
    end
    divisor += 1
  end
  return numbers
end

def sum_of_primes
  sum = 0
  prime_array.each do |x|
    sum += x
  end
  return sum
end
 
puts sum_of_primes

# This takes forever to calculate


I put this problem aside for awhile and kept cranking through the problem set until I hit big one: The Grid Problem.

This is a fun one. I've run into a few stumbling blocks, but I'm hoping to finish it tomorrow.

Friday, January 6, 2012

Project Euler

I'm ridiculously excited to have discovered Project Euler, a collection a math problems that are perfectly suited for programmers. I stumbled across the site in search of a new kata, and since then, I've been a happy camper.

Not only did the site help me to take a step back from my confusion and tackle some fresh problems, but it is also giving me a ton of exercises that I can use to learn how to write acceptance tests. Just when I was about ready to give up on RSpec, Project Euler came to the rescue. The exercises are also a ton of fun.

You can check out my problems and answers on GitHub.

Tuesday, January 3, 2012

2011 who?

I had a great week. I stayed warm for the holidays, I played Settlers with friends, I drank hot cocoa, I worked on my grad school applications, and I jumped in the lake on New Year's Day to celebrate the arrival of 2012 with a wee bit of hypothermia.

But I didn't work on any Ruby projects. After a week off, I'm now scratching my head and trying to figure out what I thought I knew. Back to the basics.

I'm still reading through the RSpec book, and I'm now into the Cucumber section. I spent some time today looking back on the code that I wrote in 2011 and trying to write acceptance tests for it. I quickly realized that I need a basic Ruby refresher, so I spent some time re-writing my code and looking over documentation for the parts that still confuse me. With Ruby, everyday I'm moving two steps forward and one step back.

I've also identified a goal. In the next two months, I would like to publish at least one Ruby file to GitHub that helps others in some small way. I'd like to write a piece of code that solves a simple problem that Ruby developers face.

I'm open to suggestions.