Start course
Overview
Difficulty
Intermediate
Duration
2h 27m
Students
16
Ratings
5/5
starstarstarstarstar
Description

Functions in C++ are reusable named pieces of code that we can call or invoke when we need them to do something. They help us to take large problems and break them down so that they are more manageable. This course explores functions and puts them to use in a range of projects.

Intended Audience

  • Beginner coders, new to C++
  • Developers looking to upskill by adding C++ to their CV
  • College students and anyone studying C++

Prerequisites

To get the most out of this course, you should have a basic understanding of the fundamentals of C++.

Transcript

This project is going to be quite a challenge. In fact, this might be the kind of project I would give one of my beginning programming class students that I teach face-to-face, that they'd get maybe a week or at least a few days to work on because there's a lot to think about. I strongly recommend you sketch out how you might go about doing it. Before you start on it though, I will give some basic recommendations and hints to make your life a little bit easier. I'll show you some basic ideas and functions I wrote to solve the problem but you can choose to solve it a different way. For this project, you will implement the classic game Tic-Tac-Toe, also popularly called Knots and Crosses in some other places. It is a simple game to do with pencil and paper and each game itself can be finished very quickly. But it is a pretty solid challenge for programmers, especially those who are just now learning. In fact, this project is so much more challenging than the other projects we've done so far, that I'm providing a full help document that you can review while working on it. You can think of this project as a very strong checkpoint in the course to see how you're doing. Don't be discouraged if you have trouble with it or even if you get through some of it and feel like it's overwhelming. A lot of projects feel that way sometimes. I would say, take your time and don't try to rush through this project, even though it's longer and more complex. I'd strongly recommend going through it, and trying to solve it before taking a look at my full solution. Let's look at the Tic-Tac-Toe help document together, and go through it a little to see what we need to do. The document is attached to this lecture as an additional resource. You can note that I described what is tic-tac-toe in case you're not familiar with the game, it's a fairly simple game. We will see the program in action in just a moment. It's just a very popular and simple game and involves two players. Usually you just use the pencils or pens. One player uses the X symbol which is called an X or a cross, and then the other player uses an O, or it's called a nought. The players take turns placing their symbol on a three by three game board like the following, right? This is three rows horizontally and three columns vertically. When a player gets three in a row, I'm using the term loosely, column or diagonal would work. So, when I say three in a row, I don't mean you have to get them in an actual row. So, that can be a little bit confusing, so I wanted to make that clear. You can also get three in column or three on the diagonal. So, this diagonal or this diagonal, then that player will win. So, the only other possibility besides a player winning, is that the board fills up and no one wins. That's called a tie, which in tic-tac-toe is called the cat's game. Now, why it's called that, there's many stories about what that term actually means, but one of the most popular is that it's like how a cat plays with its own tail. It chases it around and has fun, but no one really wins. Hence it's called the cat's game. So, no one won, get it? The purpose of the game is simple yet two-fold. You want to get three in a row, but you also want to prevent your opponent from getting three in a row because then they would win. So, you can block your opponent to prevent them from taking a given strategy to win. Here are some game board examples. So, this would be an example in which X wins with three in a single column, right? They would have taken turns, it looks like started here, and O wasn't very good at blocking him. So, we've got X and then O took a turn, X took a turn, O took a turn, and then got three in a row. If O was smart, the second time maybe blocking would have been a good move. And here's X winning with three across. Now, usually they're not quite this simple because you really have to take advantage of the other person for you to get a board like this. So, it's just a very very simple situation. Now, the game that you're actually going to implement does not involve any AI or anything like that. We're going to assume that it alternates players, and that you have two players at the keyboard. So, they're each taking turns saying, "I want to position my character, my symbol at this location." So, don't worry about AI or anything super complicated like that, we're not getting into that. That's a whole other can of worms. So, here's another figure. This is one where X wins on the diagonal, here's another where X wins on the diagonal, but it's a different diagonal. And this is an example of the cats game. So, you notice that neither piece, it looks like they actually had a pretty good game here, neither piece had three in a row, neither symbol had three in a row. So, you have to Xs here, but it didn't quite make it, two Os there, two Os there, two Os there, two Xs there, an X and an X here, but no one ever got three, but the board's full, so you can't continue. Although you don't have to be a domain expert, who knows the ins and outs of the topic or field of study. So, even if you've never seen this game before, you will be able to implement it, it's important as a software engineer, software developer, to understand the fundamentals of how something works. For instance, you could get hired by a company that does biochemistry research. Even though you don't have to have a degree in biology, chemistry, biochem or genetics, to write the software for them it does help to understand those fundamentals. So, it's important to understand the problem that they want solved. So, this is key. Luckily for us, tic-tac-toe is fairly simple as a paper and pencil game, and it's even pretty simple to become a domain expert really quickly. So, now that you understand how the basic game works, let's take a look at design ideas for how we might go about structuring the program. So, here are my design enhance, you do not have to implement it this way, but I did try to make good use of modularization. This is where we divide the complexity of this big project into different components. So, I do actually even give you my main here, I don't show you in this document the implementation, but I give you the main part and I give you my prototypes and some other stuff, global variables; a couple of them. So, I have runGame, which is the game loop. InitializeGame is a function I wrote that sets the cells of the 2D array. So, you use a multidimensional array, which we'll talk about, set them just to spaces. printCurrentBoard will be called many many, many different times, literally after every turn, so it will show what does the board look like now. getUserInput gets the current user input and if that input is valid, it sets the game more appropriately, and if it's not, it will say, "Hey you need to pick a different cell." So, if someone tries to choose a cell that's already occupied either by them or their opponent, it will tell them you can't do that and it won't change the board. It will wait until they enter a correct answer. cellAlreadyOccupied is just a little helper function I wrote. It will return a boolean, so returns true if the given cell is already occupied, or false otherwise. So, that can help us determine, can we place a symbol there? So, this function could use that function, right? getWinner. This is going to be a fairly complex one. This one is going to search for a winner. It's going to check all the rows, check all the columns, and check the two diagonals, and determine if there are three in a row of the same kind. Or it will return a space the way I wrote it, it returns a space if there's no winner yet. isBoardFull is also Boolean, so it returns true or false. This just returns whether the board is full or not. So, this can be used in the same manner that this gets called. You can also call this and determine, hey, if there's no winner, this returns empty, but the board is also full, then that means it's the cat's game. So, that might help you. And again, you don't have to implement it exactly the way I did it here. And you don't have to think that I know all the answers or that I have a better solution than anyone on the planet. That's not what this means. This is just one solution I came up with, just sitting around thinking about the problem, sketching it out briefly, and I think my solution has about 150, 160 lines of code, or something like that. So, this is not trivial, this is not a tiny little project. We've done a lot of really small projects, some are more complicated than others, but this one is way harder. Now, if you think I'm just coming out of left field on this, I'm not. You have all the tools at your disposal to finish this and you also know how to do little searches, you know how to review the material that we did here. I showed you resources like the C++ website, right? So, you do have everything to complete this, but it is a lot more challenging, so just keep that in mind. So, my main literally just calls a run game here and you might think, well why do I even need that? The run game is basically the game loop. And what it does, is it makes use of some of the other stuff going on here, and it will allow us to interact with the user and it prints the current board and initializes the game board inside of it at the beginning, and then in a loop will print the board and keep asking for input as long as there's no winner or if the board is not full, so we can use some of this information to determine when we exit. Now, even with me giving you all this information, the solution you come up with is unlikely to be identical to mine. Even if you implement these functions, you might call them in a different way or decided to restructure it, and that's okay. Now you will notice that for the 2D arrays, even though for 1D arrays, you do not have to put the size and the brackets for a 1D array. When you pass it to a function for 2D arrays, you actually have to put the second dimension. The first dimension is optional. So, I did make these globals right here, rows and columns since they're used over and over and over again, I just did that and I made this 2D array or I'm passing the 2D array in quite consistently and you've got rows, columns, rows, columns, rows, columns. So, every one of these takes the game board and does something to it. Now you might think, wow, is that copying the whole game board and doing all this crazy stuff with it. Because isn't that passed by value, because I don't see a reference symbol. So, here's something interesting about arrays. Now, the array itself, an array represents an address, so an array kind of exit X is passed by reference even when you're not passing it by reference. So, you can actually, you can modify the elements inside the array, you just can't reassign what does the thing that a person point to or what array does it reference. That's a little more complicated. We don't need to really get into that. So, just know that whatever you do in these functions to the array will be effective in the long run. And then I won't read this all too. But it just tells you what did I do with my runGame? What did my runGame do exactly? It gives a lot of ideas. What does initializeGame do, what is the responsibility of printCurrentBoard and getUserInput, cellAlreadyOccupied, getWinner, isBoardFull etc. So, I strongly... I probably should redo that, I strongly recommend you try to write, not try to write all the functions at once. So, for example, maybe try some of the easier functions that don't depend as much on the other. So, you might want to build your program up by maybe initializeGame, just play around the printCurrentBoard, call that directly even from runGame or main just to see if you can print the board out. Get a board, that's basically one of the first steps, is can you print out an empty board with the spaces. And then can you replace certain cells that are represented by this board that's visual. Can you replace certain cells with Xs and Os and things like that? So, I hope this document does help you solve the problem. Note that what we're doing is populating the 2D array. We don't pass the array itself by reference again. So, remember you do not have to do that. So, just keep that in mind, know that it will have a persistent effect on it and that it is good with large programs to keep main as clean and minimalist as possible. So, that's why I created this and I'm calling runGame. So, this generates this so called game loop. So, we should probably look at the finished game to see what it does and see what it looks like. So, let's run this. I'm not going to show you the code. Debug, start without debugging. And here it is, it's waiting on user input. It has printed the empty board. So, that's done after the initialization and we call printCurrentBoard with nothing in it just yet. And it says it's X's turn, you can randomize it, but I just had it start with X each time. That's fine. And then you can print or you can type in the row and the column and we could just separate them by spaces. So, you can say if I want the upper left hand corner, that's index 0 0. So, I could type this, I could say and it will reprint the board with my selection. Now if it says O's turn, it's O's turn. If O tries to go at position 0 0, it will say that cell's already occupied, please enter the row then the column, it basically asks for the input again. So, let's try it again. well, still won't let me do it. So, it doesn't reprint, you don't have to reprint it. Just tell them, hey, that's occupied, you can't do that. So, what about 1? So, that's row 0, column 1, it'll be to the right of the X. And it does indeed work. So, we could keep going with this, let's say row 1, column 0. That puts two Xs in a row and then O gets 1 1, and then row 2 column 0, X wins. So, the winner is X. See, pretty straightforward, but it is a complex project. So, don't make the 2D array global. That's one thing that would be tempting to do as an alternative implementation, but it's generally considered better to pass the data you need as parameters where and when they're needed instead of using a global because when you make something global, I know I made the two constants global but no one can change them. They could just access them. But the array, since we need to be able to change it, everyone has access to it. So, if everyone has access to it, everyone, I mean every function has access to this global array, things could, it could be implemented in such a way that it could get really ugly and things could put bad data in it without you intending on it. It's just better to do it with parameters because it makes you think it through a little more and you think through more carefully what data do you actually need to solve the problem and what should this function actually do. So, it's just considered better not to use global variable. It makes your code variables as much as you can avoid it, it makes your code more reusable and just a little bit cleaner. So, here's where it goes, at very least pause the video and come back when you're done. But you could even take the document, run with it, spend a few days on it even if you want to, if you think it is going to be very challenging for you, if you're a brand new beginner to this and some of this is a little challenging for you, even the stuff prior to this, then I'd definitely say, take the document, spend at least a few hours looking at it and it could be challenging. Don't be discouraged if you don't get it. And it's a really, really big accomplishment if you do that. So, at very least pause the video, come back when you're done or when you think you might need some help. Wow, that was a big project, wasn't it? I hope you did well. For this one I suspect a lot of students would struggle because this is a large and complex project compared to others we have done. Even if you are able to get some of the parts working, I'm really proud of you. Regardless of how you did, don't give up and keep going. If you really had a hard time with this project or it looked impossible to you, that's okay. I'd recommend you keep moving through the material in the course, then maybe in a couple of sections from now swing back around and try to get and see if you do better. Experience is an important part of learning the code. So, I'm going to show you the code. I'm going to reveal the code. So, we don't have to waste a ton of time typing it and you will obviously have access to this code as well. But right here, we have all of the prototypes here and you notice I have the game loop, runGame, the game loop sets the winner to empty string. I have a Boolean that I use to determine whose turn it is each time. And then I start with row and column as 0, I have the game board that I declare. And then I call initializeGameBoard. So, you can think of this as just giving it its initial spaces everywhere, and then printCurrentBoard. So, printCurrentBoard has a lot of nuances in it. Let's look at that real briefly and then we'll release two and then we'll come back. So, initializeGameBoard is not too difficult. You'll notice that I start at zero for the rows and the columns both. And then you basically just loop through and you set each element to or each cell to the element's space. Printing the current board is also fairly simple. This one I put in a couple little handy tricks without having to do it manually. Some of you might have done it manually, that's okay. But this is a, I would say a better implementation, using control statements. So, we do loop through the rows and the columns, but you'll notice what I do is I print whatever element is in the gameBoard. Notice, I'm not putting an endl yet. And then if j is less than 2, that means if the column is less than 2, I put a divider with spaces on either side. So, what that's going to do is it's going to get the effect. Let me show you. It's going to get this effect. So, it's basically, there's the space now in the center and spaces on either side of each of these lines. But if I didn't put the stipulation where I put j less than 2, I would also get a line on the outside as well. And I didn't want it to look like that. I wanted it to look more like this. Now if you did that, that's fine, I don't care. But I wanted this to look very similar to if someone were to draw it out. You'll also notice I did the same thing with the rows because I didn't want the bottom lines to display the very bottom of the TicTacToe board, I just wanted it in-between. So, again, if I show you this real briefly, it only does it if the j is, so j is 0. At the end of that, it will do it once. j is 1 and that does it twice. And then when j is 2, even though it will still be iterating and it still prints out the elements, it does not print out a third set of these little lines here. So, you notice as far as we're concerned, this actually looks like it's printing several lines of actual data. So, we just try to mimic what's going on in the game. Now, if we go back up to the runGame here that we call from main, you notice that winner was initialized to empty and I set, this is the way I did it. Some people would not like this and that's fine. But while the winner is equal to empty, meaning we don't have a winner yet. If it is X's turn, we print out  here it's X's turn else it's O's turn and we keep track of whose turn it is. So, the X's turn does changes right here when we get ready to go for another iteration but you'll notice we get user input passing in whose turn it is. So, we know what symbol to place and we pass the game boards, we know the game board to pass it to. We put additional spacing to make it a little cleaner and then reprint the game board and then check for a winner. So, we've got get user input and then get winner. These are two others that we want to look at. So, get user input, it looks like this, it determines whose turn it is and passes in the game board. We start with invalid row and column and we have a Boolean that I have set to true that determines whether we keep asking. So, we keep asking until we get a valid answer. So, we say please enter the rows and the column. So, they enter a row and a column. And if it's in range meaning it's greater than or equal to zero, less than or equal to two, those are in range. If it's negative or it's greater than two, it's invalid. So, if it is not valid it will skip over this if statement and keep asking will have never been changed. So, that means it will be true again. So, it will keep asking again. Another thing that could make it so that we keep asking is even if it's within range, if that cell is not occupied, we said keep asking to false meaning we found a valid selection that they've made. However, otherwise we'll warn them that the cells occupied we don't change keep asking. So, it's still true. So, it will keep asking, it'll keep looping, keep asking until we get to this point. So, we have to have an in range value and besides being in range, that cell cannot be occupied. So, we have this function not main but get user input calls cell already occupied. Now, what the cell already occupied look like. Cell already occupied is very simple. It determines, if the game board at the given row and column is not equal to a space. So, this is, you have to follow this here. It is considered occupied if this thing that it returns is not a space. So, basically what we're saying is if it is not already occupied then we can place it at that row in that column. So, by the time it gets out of this while loop we have a valid row and column. And if it's X's turn we set the game board to an x and if it's o's turn we set the game board to an o. So, down here get winner is probably the most complicated one is BoardFull, we will look at that row briefly. If the board's full, this basically just goes through and it counts how many cells are filled. This is the simple way I did it, but there's other ways to do it as well. I just went through and not just determining if something is there that would be a little bit cheesy. I'm only counting them if the things that are at the index [i] [j] for any row and column is not a space. Because if it's a space then is BoardFull would return true even though no one's  ever made a move yet because it would be all spaces. So, if it's not a space, we know it's an x and o and if it's not a space, if it's an x and o we determined that, that particular cell is filled. So, we keep counting and if it goes through and all nine are filled, then we know that the board is full. So, it's pretty, pretty useful. So, let's go up here again we have the get user input print current board and get winner. And once we have a get winner here, which we'll look at that in a second. We then determine if the winner is set to empty, excuse me, meaning there was no winner yet. Then we skip over this unless the board is also full. So, if there's no winner and the board's full, we set the winner to C, which means it's the cat game, cat's game. We break out of the loop because the winner would no longer be empty. We go down here. If the winner is C, we say it's the cat's game, otherwise we say, hey, the winner is and then whoever the winner's value is. It's only because we wanted to have a different output based on if there was the cat's game. If we wanted to just say the winner is C, for cat, then we wouldn't need this if statement. I just made this really pretty and went all out to try to make it look really cool. Now, the one method we have not looked at, they're the one function we have not looked at is get winner. So, get winner. If we go down here, get winner looks like this. This is possibly the most complicated of all the functions. These tests to see if that should say test if we have a winner. Sorry about that. String get winner this tests to see if there's three in a row. Okay, so, by a row, I mean row, column or diagonal. So, we go through just the rows and again, there are many other ways to do this. There's actually a couple more sleek ways to do this, but it would make this way more complicated and way harder to understand in my opinion. So, I'm not showing you the really crazy ways to do it. But this is pretty straightforward, it says as long as the game board at we're checking I at zero, I at one and I at two. If the I at zero the cell is not empty, meaning, they are not empty but a space if it doesn't have a character at it, meaning if it does have a character at it is what not equals to means. So, if we have an x and o occupying it and if the cell and the particular row we're in and the first column zero equals what's in the 2nd column and then the second column equals the third column. Then that means we have a row. So, we return a match. We return whatever, it doesn't matter which one we do here, it will be x, y or xy, x or o. If we get to this point it'll just be whoever won. So, we return immediately. Okay, that would be one thing we could do. Checking if it gets through all the rows and it never found a winner, you can check the columns and to check the columns again, we make sure notice this is alternated. So, we have the first cell set to zero and then we checked 0,1,2 and just iterate through the columns and return it if we get a match. And then the diagonals, we're just kind of do it manually. So, we check game board, as long as it's not an empty and then if the [0] [0] is equal to [1] [1] equal to [2] [2], that's going to be the upper left. So, if I run this here, real quick, just to show you, it's checking the upper left, [0] [0] then [1] [1] and then [2] [2]. Now, the the upper, lower left to upper right diagonal checks [2] [0]. So, row [2], column [0]  [1] [1] and then [0] [2], which is this one. So, that's the diagonal going this direction. So, if we get through all of these and we never find a winner, then we just return an empty string. So, it notice it doesn't even have a space in it. So, what does that do? What does that cause us to have happened? Well, if we go up here again to run game to look at it briefly, this loop is controlled by whether winner is empty or not and if winner keeps returning empty and the board is not detected as being full. This loop is going to keep going until the game's over. So, if someone ever wins, that's going to break the loop this way and if no one wins but the board is full, we set winner to C. So, that basically it makes the cat the winner. So, that will break out to because C is not equal to the empty string. So, either way we break out and do that. So, hopefully that helps you understand this. And this was a really exciting project for me and I hope it was exciting and not too frustrating for you, but again, don't get discouraged if you didn't get it right, it's totally okay, this one was very challenging. This is something that I would sit with, this type of project I would sit with my actual face to face students, sometimes and have to explain lots of steps to them. So, don't feel bad if you didn't get it right, but this is a really good checkpoint I think for your learning. So, let's see this in action just to show that we have in fact implemented it correctly. So, let's put 0 and 1, good, that puts the x. Now, what about the o? All right, so let's see 0 0, all right, put's an o there. Now, it's x's turn. So, what about row 1, column 1. So, 1, 1. There we go, access 2. Now, what about o in the lower right corner, so 0,1, 2, 2 and 2. Good. Now, what if I go out of about 2 and 4, please enter rows and the columns so, it re asks. So, this is what we expect. It is x's turn. So, if I go to row 2, column 1, that will give me a winner. Excellent, so we've implemented it and it works great. So, in the next lecture, we're going to do the section wrap up and then go from there. I'll see you there.

 

About the Author
Students
308
Courses
20
Learning Paths
4

John has a Ph.D. in Computer Science and is a professional software engineer and consultant, as well as a computer science university professor and department chair.

Covered Topics