The Strange Case of Move Number 0
I am feeling a little stupid right now. All traces of the writer’s block I first complained of when starting this blog have gone now and I am working well, with the light at the end of the tunnel starting to come into view. Yesterday I worked really hard on the program, maybe 6 hours of intensive effort, about the most I can practically manage in a single day.
The sad thing is, almost all that effort went into a couple of big internal organisation changes, and today I’ve made the decision to unwind both of them. So with the finish line almost in sight I’ve completely wasted a great burst of energy. Sigh.
I can console myself that I’ve learned some lessons and that I’ve only wasted (a little more than) one calendar day, but still.
The first change I made was to make a new type of “GameDocument” called a “GameSkeleton”. In fact I made GameSkeleton a base class and inherited from it to make a GameDocument. The idea was that GameSkeleton would represent a less than fully formed game. In particular, when reading from a .pgn file I would create a vector of GameSkeletons, holding the descriptive strings for the game (player names etc.) and the location of the moves in the file. But crucially, at the GameSkeleton stage those moves haven’t been read from the file into memory and so the facilities for storing the game and manipulating it in detail would not be included in a GameSkeleton, they would be added by extending the GameSkeleton to a GameDocument.
This is no different to what I did previously, except that previously I used GameDocuments for everything and so when editing a .pgn file I have a big vector of GameDocuments that are only using a small fraction of their capabilities.
I’ve been planning a change like this for a long time, and in principle it was a good change. I invested a couple of hours in it, but then to my horror realised that of course the user can edit a series of games from a .pgn before saving the .pgn. I rely on those games sitting, edited in the big vector of games. But they must be GameDocuments at that stage not GameSkeletons. My big vector must accomodate (some) GameDocuments amongst the (many) GameSkeletons. A classic example of focussing on forests and forgetting about trees.
Now there is a technical solution that would allow my vector to hold either type – basically the vector would hold smart pointers to either GameSkeletons or GameDocuments. But (shamefully) I have avoided using smart pointers up until now, relying heavily on the STL supplemented by a very simple memory management philosophy instead. I don’t want to introduce smart pointers now, the whole issue is one of (premature?) optimisation, so I am binning it for now and reverting.
That wasn’t so bad, but what followed really hurt, I made the same mistake again!
To understand my second mistake, consider this simple question; A variation comprises a start position plus N moves. How many elements should there be in the array (or vector) representing this variation? In this a move is a single turn, i.e. a ply in computer chess terminology or a half-move in conventional chess terminology.
Unfortunately there is no absolutely surefire best solution to this question. There are two possible answers that both have their merits. The obvious answer is N, one for each move in the variation. But an alternative is N+1, one for each position in the variation. In computer science this is called the fence-post issue. In a fence there is one more fence-post than there are gaps between fence-posts. A move is like a gap, a position is like a fence-post, the move (gap) takes us from one position (fence-post) to another.
In Tarrasch V2 I made the decision quite early to go with the obvious solution of N, one element per move. One problem with this approach is that editable comments can appear between moves, this makes the ideal solution of a comment per move impractical because the first move in a variation can have a comment before it. Okay so I have made some special provisions and coped with that problem.
However (there’s always a however), after successfully implementing demotion of variations to comments and promotion of comments to variations, I noticed that I couldn’t simply type a comment into an otherwise empty game document, and then promote it to a variation. I really want to be able to do that. Unfortunately I then made a hasty decision; Why not add a dummy move to the start of a variation?, effectively move number 0. This is the N+1 solution. This has some benefits, in particular each move has only one comment (and one position) associated to it. An empty document would have the dummy move, associated with the initial position, and optionally a comment as well.
In a burst of activity I implemented this scheme. The problem is that I have written a lot of tricky code to allow the user to navigate and edit an arbitrarily deep tree of variations. Most of this code has been unchanged for months now. It has the very fine attribute that I know it works well. Should I really make a change this fundamental to the underpinnings of the whole project at this stage ? It wasn’t too hard to get the new code working, sort of. But I kept finding and repairing things that were no longer working well. And as I worked on fixing the problems I realised that the fake move that’s not really a move is actually not more elegant than my previous arrangement.
After hours of intensive effort, the realisation slowly dawned that abandoning this change was not only the pragmatic thing to do (don’t fiddle with the foundations near a project milestone), but it is also the right thing to do (my modified code was less elegant and easy to understand than my unmodified code).
It’s been a painful little period, but actually writing about it like this has actually been quite cathartic.