Go Go Goban

rjbs on 2004-04-29T04:06:18

Two weeks ago, I said I was going to be brave and adopt another practise from XP: I wasn't going to carry over today's work to tomorrow. I didn't get all my tasks done, so I released my checkout and deleted the sandbox.

"It'll be easy," I thought, "since the ideas are so fresh in my mind!" Well, I'm sure that would have been the case if I had actually done work on it the next day. Or any of the following ten. Instead, I did ... heck, I don't know what I did. I didn't work on Games::Board.

I'd be honest and say that I lost all momentum, but I didn't. The day after erasing my code, it was all fresh in my mind, and I realized the simplest way to do what I wanted to do. Sure, I should have implemented it sooner, but I had a life to live. Anyway, I finally made the determination to get some work done, and so I did.

The target I'd missed was a Games::Board::Grid that I could subclass to a chessboard that used idiomatic space identifiers. I wanted to be able to call the bottom left space 'a1' and not [1,1]. In the end, the problem was me being too clever. Games::Board stores spaces in a hash, keyed to id. I wanted to make Games::Board::Grid store things in a LOL, using the two-dimensional structure to represent a two-dimensional grid. "Ho ho," I thought, "Perl is powerful because I can implement a subclass as a different reference type!"

Yeah, well, that's dandy, but stupid. I wasn't getting any benefit from having each row in its own array. I wasn't doing anything neat with the LOL. It was dumb. Then, I ended up having routines that once compared strings trying to compare arrayrefs. Then I had to not trample on passed reference values. Then I had another layer of indirection by which idiomatic identifers were being replaced with arrayrefs. That is, 'a1' had to become [0,0].

See, the thing I remembered on The Day After was that I should have looked for the simplest thing that would possibly work. Being too clever is great for cocktail parties, but not so much for coding. I just put in one layer of indirection: when needed, identifiers can be turned into a grid position. Otherwise, they're still strings. The board is still a hash. By default, the first allocated corner of a Grid board has the id '0 0' -- yeah, it's ugly, but it works fine. Writing a chess id generator was trivial, and so was go.

Inspired by my success at getting that code working, I started to refactor Games::Goban. My first mistake was to try to refactor it in place. Yanking out an internal storage mechanism and replacing it with a foreign backend while not altering the public API? It's not rocket surgery, but it's a lot harder when you're writing the foreign backend while you do it. About halfway through the operation I realized that I was digging a pit, deleted everything, and watched a movie. The next day, everything was fine.

I've built Games::Goban::Board, which will be the internal representation of the board in Games::Goban, when its overhaul is complete. The next step is to replace Goban's internal board manipulation with this class. It's only weird because Goban is both a board tracker and a game tracker. Still, it shouldn't be so complicated. It will give me a reason to implement the C and C functions from Games::Goban into the base Games::Board class.

What I really need, next, is a way to promise myself that I'll work on something at a given time and try to achieve a given goal. My lousy todo list is lousy, and I'm not sure what I want to do to make it better. Templates for better OmniOutlines are welcome.


Rocket Surgery

chaoticset on 2004-04-29T14:42:02

You do realize that hundreds of years from now, this phrase will have stuck firmly in the language of English, and no anthropologist or linguist will be able to figure out where it came from, right? They'll know it's derived from "rocket science" and "brain surgery", but tracking down why they were combined...just not going to happen.