Chad Perrin: SOB

28 March 2008

10 steps to 99 bottles: simple program dev 101

Filed under: Geek — Tags: , , , — apotheon @ 12:07

Thinking back, one of the most difficult things for me to really get the hang of at first when I initially started learning to program was how to get off to a good, orderly start when writing a simple program. I’m reminded of this by someone who popped up on the ruby-talk mailing list asking for help with a programming problem presented in Chris Pine’s Learn to Program online tutorial. (Note that page also gives you somewhere to go to buy the book Pine wrote as an “improved, expanded” version of the same idea.)

I figured I should share some of what I’ve learned since then about how to do exactly that — how to start writing a simple program. I’ll use the same programming problem that came up on ruby-talk: something that prints out the lyrics for 99 Bottles of Beer. It probably won’t be the most elegant implementation possible, but it should make the point about how to start writing software, and it’ll stay away from concepts that might be considered “advanced” or are idiomatic of a particular programming language. It will, however, assume that you know some very basic programming syntax.

So, here it is, a step-by-step example of how to start writing a simple program, using Ruby as the example language.

  1. Create the framework of the file. It should look something like this:

      #!/usr/bin/env ruby
    

  2. Come up with your flow control structure. Idiomatic Ruby would probably involve an iterator like each or downto, but we’ll stick with something common to most languages used by beginners — the while loop. There’ll also probably have to be a variable involved:

      #!/usr/bin/env ruby
    
      bottles = 99
    
      while bottles > 0
      end
    

  3. Next, make sure you haven’t broken anything already. Of course, you need some way to indicate that things are working, if only very vaguely. As such, we’ll just make sure that the while loop terminates based on use of the variable, so you know you haven’t written an infinite loop. The following program should just run and end quickly without any output, indicating that your loop is behaving as expected:

      #!/usr/bin/env ruby
    
      bottles = 99
    
      while bottles > 0
        bottles -= 1
      end
    

  4. Now you need to make it actually do something useful. Stick a puts statement in there to print out the first line of each stanza of the song. It should print out “n bottles of beer on the wall,” over and over, where n is a number counting down from 99 to 1.

      #!/usr/bin/env ruby
    
      bottles = 99
    
      while bottles > 0
        puts "#{bottles} bottles of beer on the wall,"
        bottles -= 1
      end
    

  5. Of course, there’s something wrong with saying “1 bottles of beer on the wall,” since “1” doesn’t really conjure up an idea of plurality. We’ll solve the problem of how to generate the correct behavior later, but for now we can at least eliminate the incorrect behavior by having it stop at 2 instead of 1.

      #!/usr/bin/env ruby
    
      bottles = 99
    
      while bottles > 1
        puts "#{bottles} bottles of beer on the wall,"
        bottles -= 1
      end
    

  6. Let’s finish off that while loop so that it does everything we need it to do — print out the rest of each stanza of the song:

      #!/usr/bin/env ruby
    
      bottles = 99
    
      while bottles > 1
        puts "#{bottles} bottles of beer on the wall,"
        puts "#{bottles} bottles of beer,"
        puts "Take one down, pass it around,"
        bottles -= 1
        puts "#{bottles} bottles of beer on the wall!"
      end
    

  7. The last edit to the program reintroduced the singular/plural mismatch, because the last line generated says “1 bottles of beer on the wall!” Let’s just take that last stanza out of the mix, and deal with it separately. Increment your test value by one, again:

      #!/usr/bin/env ruby
    
      bottles = 99
    
      while bottles > 2
        puts "#{bottles} bottles of beer on the wall,"
        puts "#{bottles} bottles of beer,"
        puts "Take one down, pass it around,"
        bottles -= 1
        puts "#{bottles} bottles of beer on the wall!"
      end
    

  8. Unfortunately, the song isn’t quite done. We still need to deal with the special cases we cut out of the while loop. Write something to deal with the last two stanzas:

      #!/usr/bin/env ruby
    
      bottles = 99
    
      while bottles > 2
        puts "#{bottles} bottles of beer on the wall,"
        puts "#{bottles} bottles of beer,"
        puts "Take one down, pass it around,"
        bottles -= 1
        puts "#{bottles} bottles of beer on the wall!"
      end
    
      puts "2 bottles of beer on the wall,"
      puts "2 bottles of beer,"
      puts "Take one down, pass it around,"
      puts "1 more bottle of beer on the wall!"
    
      puts "1 bottle of beer on the awall,"
      puts "Only 1 bottle of beer,"
      puts "Take it down, pass it around,"
      puts "No more bottles of beer on the wall!"
    

  9. Looking at the output, it could be prettier. Add some empty puts statements in there to space out the stanzas:

      #!/usr/bin/env ruby
    
      bottles = 99
    
      while bottles > 2
        puts "#{bottles} bottles of beer on the wall,"
        puts "#{bottles} bottles of beer,"
        puts "Take one down, pass it around,"
        bottles -= 1
        puts "#{bottles} bottles of beer on the wall!"
        puts
      end
    
      puts "2 bottles of beer on the wall,"
      puts "2 bottles of beer,"
      puts "Take one down, pass it around,"
      puts "1 more bottle of beer on the wall!"
    
      puts
    
      puts "1 bottle of beer on the awall,"
      puts "Only 1 bottle of beer,"
      puts "Take it down, pass it around,"
      puts "No more bottles of beer on the wall!"
    

  10. Now that everything works, all we need to do is make a better program out of it. If you learn some programming techniques that can help make the program more easily understood and maintained, or somehow more efficient, they might be useful. Some idiomatic Ruby techniques such as the aforementioned downto iteration method, conditional handling of singularity vs. plurality, and other changes might make for a more elegant solution.
  11. Refactoring your program isn’t necessarily a big deal for a trivial programming problem like this, but this is a great time to practice those techniques so you’ll have a handle on them when you start needing them for more complex problems.

20 March 2008

This discussion will have been hilarious, when it happens.

Filed under: Geek,Humor,Writing — Tags: , , — apotheon @ 05:29

This is the best discussion I’ve read online in subjective-time years. Seriously. I mean, the page to which it links is hilarious (and reading it is useful for understanding some of the discussion), but the discussion at reddit actually manages to trump it quite handily.

There are some damned clever geeks on reddit.

Here’s a taste, including my explanation of Wikipedia edit wars:

whereverjustice

Anyone else struck by the similarity to arguments on Wikipedia discussion pages? You can’t kill Hitler, it’s NPOV!

apotheon

The time stream changed, and we can’t track down the precipitating event. It happens in 2054 now.

apotheon

Actually, most so-called “vandalism” on Wikipedia is edits made in alternate timelines that existed only for a moment because someone changed the past, then someone else came along and prevented the change. The sheer density of knowledge in Wikipedia is one of the greatest dangers to the purity of the timestream because of the fact that it is producing a significant localized increase in the gravity of the situation (pun intended), causing distorting ripples as it approaches singularity.

Luckily, the “vandalism” cover story is holding.

Hopefully that helps explain how the invention of time travel will in fact have been a side-effect of an edit to the article on rocketry (related to WWII weaponry innovations). That edit will have been the tipping-point in the density of knowledge that will have produced the temporally distorting singularity just nanoseconds before the server crashes that will have wiped out all of Wikipedia in 2055, thus producing that side-effect in the nick of time.

19 March 2008

a new Ruby Gem search tool

Filed under: Geek — Tags: , , — apotheon @ 01:59

Ruby Gem List

I just thought I’d mention it. It has only very recently been created, and we (several of us on the ruby-talk mailing list) are still discussing feature changes for it with the guy who created it (who is making changes rapidly in response to suggestions), so expect things to change.

If you have questions or comments and don’t want to join the ruby-talk mailing list yourself to discuss them, I might be persuaded to pass them on for you. By “might be persuaded”, of course, I mean that if I think a comment or suggestion warrants being passed on, I’ll surely do so.

Obviously, “Give up, the command line gem tool does all I need!” isn’t something I’m likely to consider worth being passed on. “Ruby sucks!” is even less likely to get passed on.

Older Posts »

All original content Copyright Chad Perrin: Distributed under the terms of the Open Works License