• general 31.01.2007 1 Comment

    To dive right in… I’ve known for a long time that it is a good idea to write unit-tests before starting to code. In the AbT Linux project my buddy Eric has defined a lot of tests for the framework. Somehow I never gotten around to doing things the proper way… i.e., I never bothered to learn how to write these tests myself. Bad boy.

    Today I started hacking at a little tool to generate Bridge hands. Not a big deal. My first worry was how to get a list of all cards that are available in the deck. My first thought was: let’s make a list of suits, a list of cards and then compute the carthesian product. Something like this:

    [ruby]
    suits = %w{clubs diamonds hearts spades}
    vals = %w{A K Q J T 9 8 7 6 5 4 3 2}
    suits.each{ |suit|
    vals.each{ |val|
    puts suit + ” ” + val
    }
    }
    [/ruby]

    This kind of works, but is hardly elegant. A co-worker pointed out that it is bad design… and I agreed. Anyway, a little lesson on OO-design followed. I should really brush up on my OO :-) He also offered to help me get started with unit-testing… The funny thing is that he’s kind of new to Ruby but, having years of Smalltalk experience helps in this case. Big time!

    Anyway, we defined some basic tests and did some initial coding. We worked on this for about an hour or so… Part of the test-file looks like this (I expanded it a bit later on, but this gives a clear idea of how I got started)

    [ruby]
    # test whether a new hand has 0 cards
    def test_new_hand
    h = Hand.new()
    assert_equal(0, h.cards.size, ‘zero cards in a new hand’)
    end

    # test whether:
    # – a new deck has 52 cards
    # – a new deck has 4 suits
    # – each suit has 13 cards
    def test_new_deck
    d = Deck.new()
    assert_equal(4, d.suits.size, ‘a new deck has 4 suits’)
    assert_equal(52, d.cards.size, ‘a new deck has 4×13=52 cards’)
    d.suits.each{ |s|
    assert_equal(13, s.cards.size, ‘a new deck has 13 cards per suit’)
    }
    end
    [/ruby]

    When I first ran the testsuite I got a bunch of errors and failed assertions. The point is to just start hacking until they’re all gone :-) It took me a couple of hours but it seems to work for now. Here’s part of the code:

    [ruby]
    # =class Deck
    #
    # A deck of cards has 52 cards divіded over 4 suits. When setting up a new
    # instance of this class the 4 suits are initialized after which the 13 cards
    # are added to each suit. Methods for getting an list of cards, the suits
    # (holding cards) or getting a random card are provided for. Finally the +deal+
    # method is used to generate a bridge deal (note: may have to refactor this
    # when catering for other types of games)
    class Deck

    # setup the four suits and add 13 cards to each suit
    def initialize()
    @suits = [Suit.new("clubs"), Suit.new("diamonds"), Suit.new("hearts"),
    Suit.new("spades")]

    @suits.each{ |suit|
    %w{A K Q J T 9 8 7 6 5 4 3 2}.each{ |value|
    suit << Card.new(suit.name, value)
    }
    }
    end

    # return all cards presently in the deck
    def cards
    return @suits.inject([]) { |list,suit| list += suit.cards }
    end

    # return all suits (which hold cards) presently in the deck
    def suits
    return @suits
    end

    # generate a bridge deal, consisting of 4 hands which contain cards
    # consisting of 13 randomly selected cards from the deck. This only works if
    # no cards have been removed from the deck yet.
    def deal
    if cards.size != 52
    raise "not enough cards in the deck to create a deal"
    exit
    end

    @hands = [Hand.new(), Hand.new(), Hand.new(), Hand.new()]
    @hands.each{ |hand|
    13.times{
    hand << self.getRandomCard
    }
    }

    return @hands
    end

    # get and remove a random card (if any) from the deck
    def getRandomCard
    cards = self.cards
    card = cards.slice( rand( cards.size) )
    self.removeCard(card)
    return card
    end

    # remove a card from the deck
    def removeCard(card)
    suit = @suits.select{ |s| s.name == card.suit}[0]
    suit.removeCard(card)
    end
    end
    [/ruby]

    The code needs some refactoring since 'suits' and 'hands' are both essentially collections of cards... I'll worry about that some other time. My first priority was to get 0 failsures:


    bas@Librarian { ~/Work/bridgehands }$ ruby bridgeTests.rb
    Loaded suite bridgeTests
    Started
    ...
    Finished in 0.005609 seconds.

    3 tests, 9 assertions, 0 failures, 0 errors

    Since I started doing things in a more professional manner I decided to also include RDoc comments and put the entire thing in a subversion repository. Must say that (a) I’ve learned a lot today and (b) that I’m kind of proud :-)

  • general 28.01.2007 No Comments

    Today we (finally) did some work on the attic again. It had been a while since we did that… Either way, things went pretty smoothly. It seems that we are getting the hang of it: fewer mistakes, better results. We managed to finish the ceiling today, it’s now completely covered in sheetrock. Hopefully we can start working on the walls soon…. and hopefully my buddy Ton can help us fix the electricity soon too :-)

    More news next time.

  • comp 26.01.2007 No Comments

    A while ago I posted a model for requirements terminology. I’m actually going to present this at work shortly and I’m also considering to develop the model further to also include such things as non functional requirements. More on that topic another time.

    Recently I started reading the blog of Roger Cauvin, a product manager from Austin, Texas, USA. He has recently given a web seminar on requirements terminology. The presentation (Flash) can be found here. I definitely like Roger’s approach (even though we seem to disagree here ‘n there) and the presentation is great. I’m not too big a fan of the UML models, though, but that’s a matter of style.

    Interestingly, Tyner Blain also posted a good story. This one is on 5 cmmi levels for requirements. I can learn a lot from this article (and the ones that it references), if only that I ought to read Software Requirements, 2nd edition by Karl E. Wiegers!