Archive for December, 2005

Birthday Notes

Birthday Notes is an application with two purposes. On one hand it provides an easy way to keep track of people’s birthdays on Mac OS X. The other role it plays is to learn Cocoa programming using Python, Cocoa and PyObjC.

Why bother with yet another birthday tracking tool? Quite simply, most were too difficult to get the information that I wanted. The main aim of Birthday Notes is to provide a list of upcoming birthdays with relevant information.

For example, I rarely think of people’s birthdays in terms of their birth date (eg 1977-08-04). My brain is wired so that I remember that my birthday is on the 4th of August and that I’m currently 28 and turning 29 on my next birthday. Rather than show the birth date, Birthday Notes shows the birthday and the person’s age they turn on that day.

Birthday Notes features integration to Apple’s existing applications for storing data. This means that iSync support comes for free. The current focus is on a maintenance and reporting tool, so you can edit a person’s birthday from within Birthday Notes, but not create or delete. For additional actions, simply double click on the person’s name - they will be revealed in AddressBook.

I like to know some trivia about people’s birthdays, so Birthday Notes includes a bit of useless astrological information.

Birthday Notes is available for download. Requires OS X 10.4 or greater.

Any thoughts, suggestions, bugs or feedback should be sent to gmwils AT pseudofish.com, or posted in comments on this post.

For those interested in the code, it is available under a GPL license. To compile, Python 2.4, a recent build of PyObjC, and icalendar are needed.

Finally, my thanks to those who have been helping with alpha testing. This release marks the start of a public beta.

Target (redux)

After having spent some of last week solving the Target word problem using Haskell, I thought I might try another language.

C++ is one of those languages that retains low level control and simple machine semantics while providing high abstraction levels. The first language I learnt, it is also the one I’ve used the most. I usually skip it for attempting to understand an algorithmic problem, but once the algorithm is well understood it can make a big speed difference.

As I’ve been pondering this from a productivity point of view, the interesting bit is how I approached the problem. Fortunately, C++ includes pseudo functional constructs via the STL. This meant that I could keep a reasonable level of abstraction. Loops replaced recursion, as it is technically possible to use recursion in C++, it just doesn’t feel right.

The time spent building the C++ version was around the same time as for the Haskell version. When run against a large dictionary of words (234937), the Haskell version took around 4.5 seconds, with the C++ version taking just less than a second.

I believe there is still some optimisation space left in both programs.

Given a similar problem, I would pick Haskell to explore, even with a slower result. For some reason, it was more fun to program against.

To continue this, I’m going to pick a trickier problem and try implementation in multiple languages. In theory, there is a Cocoa to Haskell binding …

For future reference, my code looks like:


#include <iostream>
#include <iterator>
#include <fstream>
#include <vector>
#include <set>

using namespace std;

bool containsWord(char const&, string const&, string const&);
bool includesAllLetters(string const &, string const &);

int main(int argc, char** argv) {
    string from, word;
    char letter;

    if(argc < 4) {
        cout << "usage: mainChar allLetters wordListn";
        return 0;
    }

    letter = argv[1][0];
    word = argv[2];
    from = argv[3];

    ifstream is(from.c_str());
    istream_iterator<string> ii(is), eos;

    int count = 0;
    vector<string> targets;
    cout << "Words: ";
    for( ; ii != eos; ++ii)
        if(containsWord(letter, word, *ii)) {
            cout << *ii << " ";
            ++count;
            if(word.length() == (*ii).length()) targets.push_back(*ii);
        }
    cout << "n";
    cout << "Found " << count << " words.n";

    cout << "Targets: ";
    for(vector<string>::iterator p = targets.begin(); p!=targets.end(); ++p)
        cout << *p << " ";
    cout << "n";

    return !is.eof();
}

bool containsWord(char const& c, string const &word, string const &testWord) {
    if(testWord.length() < 4 || testWord.length() > word.length() || testWord.find(c) == testWord.npos) return false;

    if(includesAllLetters(word, testWord)) return true;

    return false;
}

bool includesAllLetters(string const &word, string const &testWord) {
    string letters(word);
    for(string::const_iterator p = testWord.begin(); p !=testWord.end(); ++p) {
        size_t loc = letters.find(*p);
        if(loc == letters.npos)
            return false;
        else
            letters.erase(loc, 1);
    }
    return true;
}

Paul Graham: What Languages Fix

Paul has an interesting article about describing languages:

Kevin Kelleher suggested an interesting way to compare programming languages: to describe each in terms of the problem it fixes.

I’d like to add to his list:

  • Haskell: Lisp doesn’t have types
  • Mercury: Prolog doesn’t have types and requires too much knowledge of the internals

There should be a nice concise summary of Objective-C, but as I’ve been avoiding it I’ve struggled to come up with one. It doesn’t solve the problem of C being too low level. The closest I could get was that it added Object Oriented programming concepts to C.

Bruce - Presentation software using PyGame

Richard Jones has posted Bruce, the presentation software he used at the recent OSDC.

Various presentation software was used during the conference along with many presentation styles. The ones that stuck out the most were the typical corporate slides in PowerPoint. Usually, as I feel asleep or played on my laptop during these. Presentation Zen needs to be read by many presenters, especially if they missed Paul’s presentation.

The presentation that had the greatest impact at showing live code was Richard’s using Bruce. With PyGame as a back end, there was no application swapping between the demo and the slides. The demos were contained within the slides!

Another interesting presentation platform was Autrijus’s. His talk was built using XUL, the scripting platform created by the Mozilla team. The slides he used are available on his site and you need to follow the link using Firefox to view them. He has even been referenced (unattributed) by a site listing their top five speakers!

s/Monad/Action/g

Autrijus gave a wonderful talk on Haskell at OSDC. One insight that must be shared:

Everywhere you see Monad, replace it with Action in your head.

Monads are conceptually quite tricky. This simple insight is an “ahha!” moment. Several years of studying (and teaching) Haskell at Uni and this clarified the concept like no other tutorial.

Target - Finding Letters in Words

Target - A simple word puzzle. The beginnings of pain. The basic problem is a grid of nine letters printed in a newspaper. One of the aims is to generate words using the central letter from the square. The sub goal is to find the nine letter word that uses all of the letter.

The rules of the game are:

  • See how many words of four letters or more can you make from the letters shown in the grids.
  • In making a word, each letter must be used once only.
  • The word must contain the centre letter and there must be at least one nine-letter word in the list.
  • No plurals or verb forms ending with “s”; no words with initial capitals and no words with a hyphen or apostrophe are permitted. The first word of a phrase is permitted (eg inkjet in inkjet printer).
  • Words come from the main body of Chambers 21st Century Dictionary as the reference source.

And an example:

R I C
U H E
R N A

Target: 15 words, good; 22 very good; 30 excellent.

As a programmer, my inclination to solve these kind of problems is quite low. Scrabble is one of my weaker games. Alas, I am also very competitive, so when this became popular at a camp I volunteer at I was motivated to improve.

The catch is that I’m a little bit lazy. The way to improve at the game is to do lots of them. That doesn’t sound like fun to me.

Last time, I used a very simple regular expression and scanned the words list. I then manually filtered out the invalid words.

Having done a bit of Cocoa programming, I want to create a GUI version of a solver for this puzzle. However, an approximate solver isn’t good enough. I need to be able to exactly solve the word puzzle.

Sitting around at the OSDC, I took the opportunity to try and write the engine part.

A few attempts in Python and I worked out that for an algorithm such as this, either the language or my understanding of it was insufficient for experimentation. For this kind of problem, I tend to think of them mentally in functional style. Fortunately, Haskell is installed on my computer.

Firstly, I needed a function to check if a letter exists in a word:


letterInWord :: Eq a => a -> [a] -> Bool
letterInWord a [] = False
letterInWord a (w:ws)
    | a == w = True
    | otherwise = letterInWord a ws

Given that a letter can only be used once in a target word, a function that removes a letter from a word was needed:


removeLetter :: Eq a => a -> [a] -> [a] -> [a]
removeLetter l [] wss = wss
removeLetter l (w:ws) wss
    | l == w    = ws ++ wss
    | otherwise = removeLetter l ws (w:wss)

The two helper functions can then be glued together to determine if a given word is contained in the letters of the second word:


lettersInWord :: Eq a => [a] -> [a] -> Bool
lettersInWord [] [] = True
lettersInWord [] (w:ws) = True
lettersInWord (l:ls) [] = False
lettersInWord (l:ls) (w:ws)
    | letterInWord l (w:ws) = lettersInWord ls (removeLetter l (w:ws) [])
    | otherwise = False

This solution came together very quickly, but iterates twice through the word. A bit more time in Hugs and the two helper functions become one:


lettersInWord :: Eq a => [a] -> [a] -> Bool
lettersInWord [] [] = True
lettersInWord [] (w:ws) = True
lettersInWord (l:ls) [] = False
lettersInWord (l:ls) (w:ws)
    | isInWord = lettersInWord ls remainingLetters
    | otherwise = False
    where (isInWord, remainingLetters) = removeLetterInWord l (w:ws) []

removeLetterInWord :: Eq a => a -> [a] -> [a] -> (Bool, [a])
removeLetterInWord l [] wss = (False, wss)
removeLetterInWord l (w:ws) wss
    | l == w    = (True, ws ++ wss)
    | otherwise = removeLetterInWord l ws (w:wss)

This covers the basic search for words. It just misses a few of the rules. It doesn’t check if the middle letter is used and it doesn’t check word length. Something to add on a rainy day.

One question I have is whether or not I could do something like this in Python. It is possible to write Python code to do this, but the more interesting question is why I had mind block when attempting to use Python. I suspect this is because I have spent longer using Haskell for algorithms and tend to use Python as glue. Hopefully, PyGame will provide enough motivation to improve my Python coding.

Programmer efficiency aside, the next interesting question is how efficient the two languages are. Performance will matter, as the intent is to run this over a large dictionary of words. Interfacing into Python or Objective C for use in a Cocoa GUI is another question.

Of course, this is pretty close to being an anagram solver. This is a solved problem with many free ones on the Internet. Luckily, I get a kick out of solving the problem using my own program.

PyGame on Mac OS X with PyOpenGL

As a result of Richard Jones’s talk at OSDC2005, I decided to install PyGame to play around with.

The demos in the talk were slick, even to the point where PyGame was used as the presentation tool. Much more dynamic than PowerPoint.

Unfortunately, install is where a bit of trouble started. There didn’t seem to be a simple explanation as to how to get it functioning on my Mac. The presentation was great, and on a Mac…

Must be possible!

As with most of these things, the joy is in going down blind alleys, banging your head against (several) walls and making discoveries. The only way to truly learn something. Unfortunately, the pain can’t be totally avoided. Without it, there were no mistakes. No mistakes lead to no need to learn. Or so I kept telling myself.

After several rounds with the wall at the end of the alley, some libraries I built. Some refused to build. Some I later discovered binary packages for.

I’ve included a bunch of links below that point to the required packages. It should be relatively easy to grab everything and have a working PyGame installation.

  1. Python 2.4
  2. PyObjC
  3. Python Numeric
  4. Python Image Library (PIL)
  5. SDL - C library for user handling
  6. SDL_ttf - C library for TrueType fonts
  7. SDL_image - C library for image handling
  8. SDL_mixer - C library for sound
  9. SMPEG - C based Mpeg and MP3 library. (Checkout smpeg from CVS; autoconf; automake; ./configure; make; create framework. )
  10. PyGame
  11. PySDL is now in PyGame - Python binding for SDL

Optional packages:

  1. PyOpenGL - OpenGL bindings for Python
  2. FreeType - TrueType font library, listed as a dependency of SDL_ttf but I have no issues without it (yet?).

If it helps, my /Library/Frameworks looks like:


% ls -d [Ss][^t]* Python.framework
Python.framework/       SDL_mixer.framework/
SDL.framework/          SDL_ttf.framework/
SDL_image.framework/    smpeg.framework/

Useful things are now available in /Developer/Python/pygame, with /Developer/Python/pygame/Examples providing a bunch of examples to test your installation.

A very big grin spread over my face watching the cube rotate from typing:


% python /Developer/Python/pygame/Examples/glcube.py

Application behaviour on last window close

I grew up with Microsoft’s various windowing systems, and learnt the X Windows style of things while at Uni. When I first used a Mac, Apple’s approach of keeping the application alive after its windows are closed felt strange.

Now, having used OS X from early beta stages, I’m more comfortable with the approach and consider it the norm. Unfortunately, Apple is somewhat inconsistent with the behaviour.

It is seemingly on an application by application basis whether or not the application will quit when the main window is closed. System Preferences used to persist but now closes. iTunes stays open, iSync closes and AddressBook stays open!

For my own application, the decision on this has consumed much of my time. The code to make the application quit on window code is quite simple. Add the following two lines to the application delegate:


def applicationShouldTerminateAfterLastWindowClosed_(self, sender):
    return True

The Apple app that is closest to my own is AddressBook, so when in doubt I have emulated the AB behaviour. Partially for the benefit of users and partly for my own sanity.

As I start designing new applications, I end up with the same problem of which behaviour to choose. My default is to persist the application unless I get a large number of user complaints. To choose otherwise? I may as well write Windows programs.