Postmortem: GBTTT-CLI

Awhile back, I gave myself a goal of trying to create a simple Tic-Tac-Toe game within a week. I didn’t want to just copy the ubiquitous code out of a book, though. I wanted to take a project from intial design to implementation on my own. This project was not meant to be something commercial quality, nor is it meant for public consumption. It was just a way for me to test my rusty programming skills as well as practice using some of the tools I was experimenting with before, such as Subversion.

I did it. I called it GBTTT_CLI, which stands for GBGames Tic-Tac-Toe Command Line Interface. No graphics. No sounds. Just a simple Tic-Tac-Toe game. You decide who goes first, and each player will select one of the spots to place his/her piece, either an X or an O. At the end, the game will tell you who has won. Simple. B-)

What Went Right:

  1. It was not made with just one code file.

    Tic-Tac-Toe is a very simple game. It doesn’t need to be object-oriented, nor does it need much in the way of content. Still, I wanted to separate elements, such as Players and the Board. For the most part I succeeded. I could replace the Player with an AIPlayer at a later time easily. I could probably change the implementation of the TicTacToe game class so it can be done over a network without changing much of the other code, if any.

  2. Development went along fairly quickly.

    GBTTT_CLI was the first project I have worked on while using a safety net. Revision control tools are amazing and I wish I would have known about them years ago. I used Subversion, and while I rarely needed to backtrack, especially in a small project like this one, it was useful to go through my log to see what changes I made before. There was also a time when I made a LOT of changes only to get nowhere with them. It was easy to revert all the code back to the way it was before the changes were made. It saved a LOT of time for me when I could have otherwise just been trying to make changes to get back to a stable state. With a single command, I was there.

    Another thing that helped was the ease I had with actually coding. I underestimated my coding abilities because I thought I was starting from scratch with C++. The truth was, I could program, and I just needed to learn C++’s syntax correctly. There were a few things that I got tripped up on, such as NULL instead of null as in Java, but a quick look at my reference material showed me where I was going wrong.

  3. The game got completed.

    It was a project that I was able to finish. It may not be much, but it is more than what I had before, and I am proud of that fact. It’s also shows that I have the ability to work on my own designs.

What Went Wrong:

  1. It took me too long to get here.

    My goal was to get this program done in a week, and in total programming time, I did way better than that. Unfortunately if you count the days from when I first posed this goal to myself until I finished it, it was way longer. When I started coding, I got a lot done within a few hours. Then nothing for days until I tried to work with it again. Then I got some strange error. Nothing for weeks. Then finally I finished it. So I had a few hour spurts of productivity followed by long periods of nothing. To be fair, it was not like I was just avoiding the project. I had other responsibilities in my life, such as homework. But to be brutally honest, I wasn’t making the time for this project either.

  2. I overdesigned the classes.

    It is Tic-Tac-Toe. How do you overdesign it? I did. I thought that if I created the classes first, they would be useful as tools to build the actual game. I still think that it would be good to design the project this way, but my problem was in designing in specific features. The Player class has a Record member. The Record class holds the Win/Lose/Tie records of that Player. I wrote the classes in this way because I originally envisioned a single game session letting you play multiple rounds. In the end, I decided not to implement that since it did not need to be done to accomplish my goals. So now a Round is useless in the project. I didn’t spend too much time making it, but there are other elements that were made but not used. For instance, I also thought this would be a great way to learn network programming, so I tried to anticipate it by making Boards unique. I could have saved time and effort by deciding to add such things later or in a new project.

  3. The code is ugly.

    When I originally programmed in QBasic, I had no concept of code structure and variable naming. When I learned C++, I thought it made sense to follow what C++ did: variable and function names would look_like_this. Then I learned Java. Java programming practices are clean looking. A class name looks like: ClassName. A variable looks like: variableName. When I went back to C++, I got it in my head that I probably should keep it looking like C++, where standard library naming conventions have the underscores as mentioned above. That is when I started the project.

    Then I found a C++ coding convention guideline. Apparently Java-like style has its place in C++, too. Well, I did not want to go back and rename everything, so when I continued to work on the game, I kept using the same style rather than confuse everything, me included. The end result is commented, cleanly separated, but somewhat hard to read. A sample:

    // switch to next player
    game.next_player();
    // keep asking for input until value is legal
    int move = player_current->get_move(board);
    bool is_legal_move;
    is_legal_move = board.isLegal(move);

    Huh. Well as you can see, I did not succeed in keeping the style uniform. Board::isLegal() should be changed to Board::is_legal() to accomplish that. Still, it’s hard to read because of the style.

I know there is normally 5 of each in a postmortem, but come on, it’s Tic-Tac-Toe!

What I Learned

  1. Practicing programming is important. I should treat it as such and make the time for it rather than hoping I have an opening in my schedule. There won’t be one if I leave it up to everything else.
  2. Iterative programming is useful because I can avoid overdesigning something that won’t get used
  3. Programming is still fun, just like I remember it.

Even though I am disappointed in how some things turned out, I am satisfied. It’s a completed project! I was originally going to leave it in a state of incompleteness and start working on a more attractive project idea, but I decided to be “great” rather than “good enough”. If I keep that attitude with these smaller projects, it will be a good habit to have when I tackle larger ones.

I think I will post the code at a later time. I originally did not think it would be something I would publish, but I figure it has to help someone besides me. I’ll need to add a proper README and installation/compilation instructions first.

EDIT: Hey, I delivered. B-) And in two forms:
gbttt.tar.gz
gbttt.zip

2 comments to Postmortem: GBTTT-CLI

  • I took a quick look at your code and I noticed these lines:

    // get a fresh copy of the board
    Board board = game.get_board();
    if (&board == NULL) {
    // GBGames: I can’t get the stream brackets to work in this blog
    }

    The check is completely unnecessary. The address of board can’t be NULL. Judging from your code and what you wrote above, I suspect you confuse Java’s null and C++’s NULL. null denotes a null-reference where NULL denotes a null-pointer. C++ does not have null-references; a reference can never be null. Also, NULL is exactly the same thing as 0, so you can replace every instance of NULL with 0 (and vice versa, but that would be weird).

    Just thought it’s worth pointing out.

  • You’re right. I was treating it like Java’s null. I was checking to see if the address was NULL, but it wouldn’t be NULL unless I set it myself. So I am still learning, obviously, but it’s progress, and getting comments from others certainly helps a lot in that progress.

    Also, I found that the comment didn’t get output correctly. I fixed it with the note as you can see. The blog thinks that the brackets are meant to be HTML/XML and so cuts off the rest of the comment. I had the same problem when listing my code above. I ended up getting rid of the cout lines since they weren’t necessary to make my point.

Twitter: gbgames