Max Otuteye
istream
and ostream
for read and write operations respectively with
files.namespace std – specifies the scope of the program, allowing code to use all entities
under the std namespace without having to prefix std::
.Global variablesGlobal variables are variables declared outside the scope of all functions and hence, are
available to all functions to access. They hold their values throughout the
lifetime of the program. Anything containing x and y here refers to location coordinates.width
– this variable defines the size of the playing area. Can be altered to
preference.height
– specifies the height of the playing area. Can also be altered.x
and y
– these are location coordinates for the head of the snake.fx
and fy
– f refers to ‘fruit’. These variables specify the location of the fruit.score
– You guessed it, the player's score, starts from zero.nt
– n implies number, hence number of t (tails). This indicates how many tail elements or pieces the snake has.tx[100]
and ty[100]
– these are arrays for storing the location of each individual tail
element. In this case they are given a size of 100 but this can be increased or
reduced. Choose a value based on the size of your playing field. 100 here implies
that the snake is not expected at any point within the game to have more than
100 tail elements. If it does, the game will crash so ensure the value is large enough.diff
– this represents the game difficulty.names[100]
and scores[100]
– for storing the names and respective scores of players; a
leaderboard.Direction
– an enumeration containing all possible directions for the snake: up, down, left
and right.dir
and ndir
– current direction and next/new direction.gameover
– a Boolean indicating whether the game is over or not.For simplicity and modularity of the program, all major parts of the game are
divided into functions accessible by function calls. The following are the functions:MainMenu
– This function contains code for displaying the main menu.Help
– To display the help menu.Difficulty
– Menu for changing game difficulty.SpawnF
– spawns a fruit at a random location.Setup
– Initializes a new game.DrawGame
– Perhaps the most important game function. This function draws the game borders,
the fruit, and the snake itself.CheckInput
– checks the keyboard input for the new direction of the snake.Update
– Another vital game function. Calculates the location of essentially everything after
any changes.Play
– Simplifies the calling of essential game functions.SaveScore
– Saves a user’s score after a game.GetScores
– Gets previously saved scores.DisplayScores
– Shows saved scores.main
– the main function in a C++ program: where everything happens.DrawGameThis function draws the actual game. Drawing is done based on the terminal window text
spaces, every space can be accessed using coordinates, starting from the top left. The enclosing top border is drawn first, as it is the first part of the game that can be seen
starting from the top. After drawing the top border, we can now begin drawing the
game elements based on their location.Now we’re going to run two loops, first one represents every row in the playing field,
second represents every text column of each row.If we’re in the first column of each row, we want to print a pipe to represent the border,
same if we’re in the last column. If we’re not in first or last, then we want
to perform some checks:x
and y
. For the
fruit, we compare against fx
and fy
. With the tail elements it’s a little different here: the tail elements are stored in an array hence a single comparison would not be sufficient, we would have to compare every array element with the current space. Before we begin looping through the tail array, we set a space
Boolean to true. This Boolean tells us if there should be a blank space or not (if nothing goes in the current place, then it gets filled by a blank space 🎵).After initializing space
to true, we can now begin looping through the tail array. If the current coordinate matches a tail element coordinate then we place an ‘o’. But that’s not all, we also have to set space
to false to indicate that something is here and hence no need for blank space. Now we check if a space is needed (if space
is true), and if it is, we draw a blank space. Now we can draw the end border, end the line, and move on to the next line/row.As it is a loop, on the next row, we do all the above again (that’s why we used a loop, for repeated logic based on a condition).After all this, we still need to draw one more thing: the bottom border. Now we can print the current score and pretty much any other information we want for debugging purposes. If you feel something isn’t working as should be, you can check its values by printing them out to get a better idea of what’s going on.CheckInputThis is a very straightforward function, it checks the keyboard input to determine which way
the snake should go next or if the player wants to quit the game. Input collection
is performed by the _kbhit
and _getch
functions. These are buffered
functions, in other words, any keys pressed while the process thread is asleep
will still be recorded in the input buffer. These functions are provided to us
by the conio
(Console I/O) library.The first step is to check if a key has actually been hit using _kbhit
. If that returns true it means a key has been hit, and we can move to the next step.Second step involves collecting and checking if a key meaningful to us has been hit,
and a switch
construct is used here. A switch is similar to if/else but is
the preferred option if you’re checking the different possible states of a
variable, and here we’re checking against the possible states (or cases) of the collected
keystroke.In summary, presence of a key in the input buffer is detected using _kbhit
, detected key is
collected using _getch
(and converted to uppercase: toupper
), and collected key is
checked for meaning. If it’s an ‘A’, that means the snake’s next direction
should be LEFT, ‘S’ for DOWN, ‘D’ for RIGHT and ‘W’ for UP. If the entered key
is an ‘X’, then we quit the game by setting gameover
to true.UpdateIn this function we see the introduction of some more variables: curX
, curY
, prevX
and
prevY
. curX
and curY
store the current coordinates of the first tail element,
whereas prevX
and prevY
store previous coordinates.prevX
and prevY
variables, and then set to curX
and curY
.curX
and curY
are set to prevX
and prevY
.ndir
with its current direction dir
to determine if a direction change is needed. I suggest you take some time to think about this portion of code, you might realize something interesting about it (If it isn’t coming to you, try removing it and see how the snake reacts).fx
is passed as a parameter in the SpawnF
function, don’t worry it’ll be explained later).diff
(the value of diff
is changed using the Difficulty
function, sleeping for shorter makes the game appear faster whereas sleeping for longer makes it appear slower).int mainThe main function in a C or C++ program is the function which is called when the program is run. In other words, even if there are a hundred functions in your code, unless they are called within the scope of the main function, they will have no effect when the code is run. Thus, all the code we’ve written so far will not actually be of any effect lol.New construct: do ... while
. This simply says, “do …a…, as long as …b… is true.” In
this case, as long as the ‘close’ variable is false, we want to do some things, and these are as follows:CheckInput
function, this works in a similar way but you’ll just have to make a few changes in your
new function.return 0
. The main
function has a return type of int
meaning, the function has to return an integer (a whole number from negative infinity to positive infinity). If the game exits properly we return a zero, this is a programming convention, it doesn’t have to be zero.At this point you can go ahead to compile and run the game.Leave any comments or questions down below. Thanks for reading!Mobile, Web and Desktop app developer.