
The Code
Written in C, you can find the code on Github here.
Code design
All apps start at the entry point. In C, this is the main function.
First, the startup code executed, which includes writing the user directions and board to the console.
After that, the board enters the main loop, and it:
- Gets user input
- Checks if the input is valid
- Moves the piece
- Draws the board
- Repeats
int main()
{
startupMessages();
renderBoard();
UserInput formattedInput;
do
{
formattedInput = getUserInput();
if (formattedInput.charCode != input_success)
continue;
movePieceReturn movePieceCode = movePiece(formattedInput.start, formattedInput.end);
renderMoveOuput(movePieceCode);
} while (formattedInput.charCode != quit);
return 0;
}
Let’s take a deeper look at one of these functions, getUserInput().
Summarizing, getUserInput()
- Allocates memory for the text input
- Gets the input and limits the size, so you don’t get what is called a buffer overflow
- Formats the string so it doesn’t call “invalid input” if you add an extra space or accidentally capitalize one letter
- Processes the input and saves the coordinates (more checks are done later in the code).
- Returns the object that includes data about:
- The result of the input (either quit, invalid input, or successful input)
- Position of the piece to be moved
- Desired end point of the piece being moved
One thing you might notice is that it didn’t check whether the move was legal. What if the user wanted to move a pawn 3 spaces forward?
Further checks are done in the movePiece function to make sure the user made a valid move.
UserInput getUserInput()
{
UserInput returnVar;
char input[INPUT_BUFFER_SIZE];
printf("%s's move:\n", activeTurn == WHITE ? "white" : "black");
fgets(input, INPUT_BUFFER_SIZE, stdin);
removeWhiteSpace(input);
tolowerstr(input);
returnVar.start.x = input[0];
returnVar.start.y = input[1];
unsigned char strSize = strlen(input);
if (strcmp(input, "resign\n") == 0)
{
printf("%s won!\n", activeTurn == BLACK ? "white" : "black");
getchar();
returnVar.charCode = quit;
}
else if (input[2] == '>' && strSize == 6)
{
returnVar.end.x = input[3];
returnVar.end.y = input[4];
returnVar.charCode = input_success;
}
else if (input[2] == 't' && input[3] == 'o' && strSize == 7)
{
returnVar.end.x = input[4];
returnVar.end.y = input[5];
returnVar.charCode = input_success;
}
else
{
printf("invalid input\n");
returnVar.charCode = input_invalidInput;
}
return returnVar;
}
Check out the Github page for this project if you want to see more of the code.
What I liked about it
I liked managing the code by creating global variables and functions that act upon those variables to control the game. I think that it is much simpler and easier to understand compared to object-oriented models that you may find used in other languages.
What I would do different
I would focus more on sectioning off parts of code to keep the job specific and clear. While I did do this by creating functions that each have their purpose, I sometimes broke this rule. For example, I checked the validity of the input in both the getUserInput() and movePiece() functions. It would be better off to put that functionality into a separate function, group it together, and put it in the getUserInput() function.