In the previous tutorial, I left the program with a bug. Sometimes it helps to revisit a bug when you are fresher and sure enough it was easy to find. You’ll find more information on the Atoms game.
The problem had been that it was complaining that I was making a move in a cell owned by the computer. It turned out to be the computer move that it was complaining about.
Every time you play a move (or the computer) it calls PlayMove.
// If move ok set it on the board and return 0. If a bad move return 1
int PlayMove(int x, int y, int owner) {
if (<strong>owner == PLAYEROWNED</strong> && playerCell[x][y] == COMPUTEROWNED && board[x][y] > 0) {
printf("You cannot play on (%d,%d) as it's computer owned!\n", x+1, y+1);
return 1;
}
Explode(x, y, owner);
if (owner == COMPUTEROWNED) {
printf("Computer plays %d,%d\n", x+1, y+1); // Computer plays 0-7 but display as 1-8
}
return 0;
}
The fix was the part of the first line in bold which is missing in the atom2.c source code. When the computer made its move on a cell that it owned because it had added one there before, it was tripping up here. I hadn’t spotted that this was the computer move which happened immediately after the player move and so I thought it was the player move to blame.
The owner parameter is set to PLAYEROWNED when the player moves and COMPUTEROWNED with a computer move so it’s easy to add that additional test in so only the player moves get checked and that fixed it.
On the way to fixing it, I used a compile directive to display extra debug information. This #define which is commented out is checked in the DrawBoard function.
//#define DEBUGPLAYER
If you uncomment it then the extra code in the DrawBoard will be compiled and next to the board, it will display PPP for player owned cells, CCC for computer and … for wmpty places.
#ifdef DEBUGPLAYER
printf("%2d", y + 1);
for (int x = 0; x < 8; x++) {
if (playerCell[x][y] == 0) {
printf("...");
}
else
{
if (playerCell[x][y] == 1)
printf("PPP");
else
printf("CCC");
}
}
#endif // DEBUGPLAYER
This is inside the DrawBoard, just three lines before the end. It prints out the PlayerCell board. I had thought that the computer player was corrupting the playerCell array and that’s wahy the error message was occurring. After playing with this enabled for a while I reallised it wasn’t and tracked the bug down.
Using #defines to include or exclude code
Prior to this I’d used #defines to give names to text strings like #define BOARDSIZE 8. Prior to compiling the program the compiler substitutes 8 everywhere it finds BOARDSIZE in the source file where the #define is.
But you can also use them like this.
#define DEBUGPLAYER
Then you can use another compiler directive #ifdef to only compile the following code (all the way up to a #endif) that that symbol, (DEBUGPLAYER) has been #defined. If it isn’t defined say because it’s commented out then none of that code will get compiled. Some text editors like Visual Studio will show code that is not compiled in a different colour. This screengrab shows an extra printf that is only compiled if the DEBUGPL:AYER symbol is defined. In this case it isn’t so the printf is greyed out.
This is the part of DrawBoard just before the #ifdef DEBUGPLAYER code from earlier.
There are other compiler directives such as #ifndef which lets code be compiled if a symbol isn’t defined. Likewise there is a #else and and a #elif. Here is a full list of C compiler directives.
Using a Diff utility
There aren’t that many differences between atoms2.c and atom3.c. One way to tell all the differences is to compare them using a diff utility. There are many utilities around, one I like is the free version from Devart Code Compare which lets you view two files and you can copy individual line or blocks between them.
The screenshot below shows some of the differences between atoms2.c on the right and atoms3.c on the left. The pink lines are new. Below that you can see where some new code has been introduced. I added a line to show how many cells are owned by the Player and the computer after each move. The blue text is edited new text between atoms2.c and atoms3.c.
The markers ion the right hand side show where in the files the changes occur or you can click the double up or down arrows to jump from change to change.
The blue text is where an edit has added it in atoms3.c.
All developers should acquire familiarity with diff utilities. If you use a VCS (Version Control System) like Git or Subversion then one may be provided. If not there are free or open source available or more expensive commercial ones.
Conclusion
This has been a fairly lightweight introduction to C programming. I haven’t gone in to too much depth. The atoms game is pretty complete and plays a reasonable game though I’m sure it could be improved. A better display would help the player distinguish between their owned cells and the computer’s cells. Improving the computer’s AI would also be a useful thing to do.
For more detailed C programming tutorial, let me point you to this page. Or just move the mouse over the tutorials link at the top. The source code for the final version is in atoms3.c on GitHub.