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
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.