Hello, and welcome.
I would like to provide a solution for the tic tac toe challenge.
Now remember, there's many solutions to a given problem.
This is just going to be my solution.
If your solution is different as long as you follow good
programming practice and you use the c programming language the
correct way, then that's fine.
I'm just providing my solution.
I'm sure it can be improved.
So let's get started.
I'm going to create a new project it's called tic-tac-toe
obviously, and we're going to start trying to modulate it.
I tried breaking it down like I did in the description of the lecture.
I'm going to create a only a few modules or I
should say a few functions.
Hopefully, this will be okay and work good for you.
I'm using camel case for all my naming conventions just what I'm used to.
We could actually even separate this into multiple source
files as well if we wanted.
So we have our main.
Let's get rid of this printf.
I am going to include an additional include.
This will allow me to basically do some clearing of our system
and a couple nice things, allow me also to I think remove a char.
So in addition to these 2 libraries, let's include conio.h.
And what I want to do and I want to attack this problem.
I want to try to module as much as I can.
I mentioned that I'm going to use a single dimensional
array, a 2-dimensional array might even work better.
But I'm going to implement this using a single dimensional
array that represents our game board, our tic-tac-toe board.
I'm going to create this as a global variable.
I'm using a global variable here because I haven't
demonstrated the concept of passing data by reference in c.
I don't want to confuse you.
I would not have to use global data here and I could pass the
data to functions, but I would need to use pass by reference.
I would have to pass around pointers, and we haven't
discussed any of that yet.
So I'm going to use global data.
Forgive me, memorize that global data is usually not a good thing to do but
because, again, we're trying to demonstrate learning, dividing conquer
and we're trying to demonstrate how to utilize functions, I need
to use global data because we haven't talked about pointers yet.
So my global data here that I'm going to use is my square that represents
my grid, my tic-tac-toe board.
This is going to be a single dimensional area of 10 elements
mainly because I don't want to use the 0 element.
I'm going to use this array to pick numbers to play the game.
It's going to also allow for me to have my coordinates.
I'm going to initialize this with just values 1 through 9.
And this is going to be a character array because I
need to put x's and o's in it.
We haven't talked about character arrays yet, but this will allow
me to put single characters.
It's just like the array concept of ints except it contains characters.
Characters, remember, have single quotes around them.
So one 2 3 9 the, 0 there the o I'm just going to skip,
I'm not even going to use, because I want to use the ones.
It makes programming a bit easier.
I can use the value that the user enters as an index, as a valid index.
I'm also going to have to create 2 global variables for
choice in the player turn.
So choice is going to be what they entered via the keyboard, either
a one through 9 depending on where they want to place their x or o.
Player is going to just represent whose player's turn
it is, player one or player 2.
I don't need any other global data.
I just need my function declarations here.
I'm going to start off with creating 3 functions.
So I'm going to have 3 function declarations.
I'm going to have one for checking for a win.
It's not going to take any data.
It's going to return an int.
I'm going to have one that doesn't return any data that, just displays
the board with the correct characters.
It also doesn't take any data.
And I'm also going to have a function that just marks the board.
This will take the user input.
And depending on what they entered, it will place an x or o in the correct
spot in the array and then display that array using display board.
So here we're just going to say mark board and that's going to
actually take a mark with an x or o.
So I can reuse this.
I can reuse this for player one or player 2.
3 function declarations so that I can place my functions anywhere in the
program, I've declared them up top.
And you'll notice that the 2 of these functions aren't returning any data
and only one is taking a parameter.
Let's implement these functions before we implement the game play.
So first, let's implement check for win.
This function is basically going to work where it's going to check the
board to see if there's any win.
So it's going to contain a lot of if statements.
I could probably improve this code quite a bit.
But I'm going to put some comments in here because we should always have
comments at the top of our function.
These are pretty simplified.
We should have the function name.
This is basically saying that the function is going to return
a game status of one if the game is over, tell you if you won,
a result of negative one if the game is in progress and 0 if the
game is over and it was a draw.
So this function check for one is returning an int.
So I'm going to go ahead and define this.
And all this is going to do is it's going to look at the array
and see if there's any spots in there, if 3x is matched.
So there's a lot of different if statements.
So how do we know if a player is one.
Well, we know if a player is one if they either match in
a row diagonal or a column.
So we have to check each one of those situations.
And we know the rows in the columns based on the array.
So if my square one is equal to square 2 and square 2 is
equal to square 3, that means we have a match in our first row.
So I'm also going to create a return value here.
At the top, I'm just going to say return value, initialize this to 0.
We'll initialize this to 0 for game over.
And if we have a match in the first row, I'm going
to return one, game's over.
We then have to have a series of other else ifs to match and
actually I don't want to return one I want to set my return value.
Because we could return but it makes the program harder to follow.
Otherwise, we're going to check all of our other rows.
So I'm going to copy and paste some code in here because
it's a lot of redundant code.
The only thing that's interesting is if we have a draw.
So let me put in all the else ifs for winners.
And then I'm also going to return different values.
Instead of having a bunch of else ifs, I could have ampersands,
but that's even harder to read.
So if we have a match in the first row.
And let's make sure our indentation is correct.
If we have a match in our second row, that's what the second one is doing.
If we have a match in our third row, return one add some new lines for
readability, don't need any brackets because they're single statements.
On line 37, it looks like we're matching one, 4 and 7.
So this looks like a diagonal match, return one.
Forty, we're matching 2 5 and 8.
That looks like a match of the center going down, so the second column.
3 6, you can see the other matches as well.
We have to basically catch all matches for rows, columns and diagonals.
And that's what we've done with all these statements looking in the array.
Now the one thing that tells us if we don't have a match or we have a draw
is we have to compare all of them and basically just make sure they're not
the numbers that were initialized.
So if we have our array square and it doesn't contain 1 2 3
1 2 3 4 5 6 8 or 9 for any of the values, that means we have a draw
because they contain a 0 or an x.
So can we can write another else if that basically says it's a draw
and we can set the return value to 0, return value equal to 0.
And again this is just basically checking this last else if,
if the numbers are the same as they were initialized.
If they're all different, then that means we can return 0.
Let's put that up one.
Otherwise, if we don't have a draw and we don't have a winner,
that means we're not done.
So a final else statement can just say return value equals a negative one.
Because remember, the function is returning negative one for game
in progress one for game is over and 0 for game with no result.
And then the last thing I want to do is I want to return the return value.
So here I'm just going to say return, return value.
And this will complete the function.
And what do you notice when we're doing this, we're
dividing and conquering.
All we're focusing on right now is checking the board
to see if there's a win.
We would work in small chunks just like this and
we would constantly test.
This allows us to focus on our design and also allows us to reduce
or isolate our errors easier.
Now that we're done with the game board, we want to go ahead
and implement the display board.
The display board is just going to show the board.
So all this really needs to do is draw the array in a specific format.
So we're going to write a function called display board.
It's not going to return any data, it's not going to take any parameters.
The reason it's a function number one is because we're going to
need to draw the board many times and also it's just better because
it's doing a specific task.
Now this one is just going to have a bunch of printf functions in it.
And it's going to have a bunch of formatting.
So I'm going to copy and paste it in.
The thing that's unique here is I'm clearing the screen each time.
But if you say system and windows and you say cls, that's
going to clear the screen.
It just makes it cleaner.
We're then going to just do a bunch of printfs.
We're going to print out the title of the game. We're going to print out the player 1 and 0.
And then we're going to print out the board.
The board is going to be nicely formatted with some parallel bars
and then we're going to print out the values of all the values in the array.
And if the value is x or 0, it's going to display.
If it's not, it's going to display a number so we can use that number to
select our option to draw and that's it, that's all this function does.
Now that we're done with displaying the board, we now
want to create our last function which is marking the board.
So mark board is going to set the array with a particular
value, and it's going to type a mark in either an x or an o.
So it's going to take a character.
What this is going to do is it's going to have a bunch
of other else if statements.
So here in our mark board, we're going to want to basically give
some comments and say that this is going to set the board with
the the correct character x or o in the correct spot in the array.
So hopefully that makes sense.
As you see the code I got to end my comments.
I want to format it nice so it's 2 lines here.
And all this is going to do is it's going to check to
see what the user entered.
So remember, we have 2 global data values for what the user entered.
We also have a value for the current player.
So choice is going to be basically what is entered via the keyboard.
We haven't implemented this yet because we're going to implement
that in the main function.
Player is going to be the current player.
We're going to need both of these to make our marks.
So what we're going to do is we're going to have a bunch of else
statements, if else statements.
We're going to check the choice, which is what's input by the user.
And if the choice is equal to 1, we want to draw something in that square.
We also want to make sure that that square is available.
So if it's equal to 1 and it's not currently equal to 1, that means that
basically somebody already put an x or an o there and we can't use it.
If it's equal to a one and they entered one, that means we can
set the array to a specific value.
We're going to set the array to what was passed in either the o the x.
And we're going to repeat to do this for each choice.
If it's choices 2 3 4 5 6 8 or 9.
So a bunch of else ifs that do the same thing.
If the user entered choice 2, we're going to make sure the indentation
is good and square 2 is available, we're going to mark square 2
with whatever we passed in here.
And depending on what player's turn it is, we're going to pass in an or an x.
Now the last thing we need to do in this function is we have to validate.
If they passed in anything other than one through 9,
then that's an invalid move.
So our last else statement here will print out a message
saying invalid move, it will mark the player down one.
Because remember players are either one or 2.
And we're going to mark the player back and then we're going to increment
it in our loop on our main function.
And then this last thing get char is just pausing the program
so that the user has to hit return after invalid move.
Otherwise, invalid move would be displayed and then it would
immediately be erased because we'd redraw the board again.
So get char pauses it.
It forces you to hit the enter button to go on to enter another value.
And these are our 3 functions.
Remember, this function doesn't return anything.
So we can keep it at the bottom.
Now we have to actually implement the game play.
The game play goes in the main function.
So for the game play, this is where we're going to ask the user to enter
a number, we're going to draw the board, we're going to check for win.
So we're going to create 2 local variables here, and we're
going to initialize our player.
Here we're going to create our integer I.
This is going to be used for our loop.
And our mark is going to be either x or o, depending on whose turn it is.
Mark is going to be x or o I believe.
Mark is going to be x or o.
And choice is going to be what the user enters via the keyboard.
So 2 local variables.
We're also going to set our player, which is a global variable.
Initially, it's just going to be player one to start the game.
Then we're going to have a loop.
We're going to have a basically a loop until we're done playing.
I'm going to use a do while loop here because I want it
to execute at least once.
I want to display the board at least once.
So I'm going to display the board and play the game until I
get a draw basically or a win.
So I'm going to do it as long as I is is equal to negative 1.
What does a negative 1 represent, it represents the game is in progress.
I is going to be the return value for checking for win.
And you'll see that in a second, but basically when I have a loop
that keeps doing the same thing over and over until the game is over.
And the game is going to be over if it's not a negative one.
So what do we have to do first.
First thing we have to do is we have to display the board.
So I can just call the function display board.
Then we have to calculate the player.
And the player starts off player one.
What we're going to do here is we're going to use a ternary
operator, and we're going to say if the player mod 2,
then the player equals 1 else is equals 2.
This is a way to determine the right player.
Each iteration of the loop it's going to change from one to 2 or 2 to one.
When it starts out as player one, it's going to say player mod 2,
one divided by 2 or the remainder of one divided by 2 is what, one.
So if it's one, you're going to be player one.
And when you go back for the next iteration, player is
going to be equal to 2 because we're going to increment it.
2 mod 2 is 0.
So if it's not equal to one, then player is going
to be equal to player 2.
It's only going to set it to player one if player mod 2 is one.
Remember, that turner operator hopefully.
The next thing I need to do is I need to get the input from the user.
So here I'm going to say, I'm going to ask the user to input a number.
I'm going to say player percent d either player 1 or 2, enter a number,
and then I'm going to put the player to print out, player one or 2.
Then I'm going to read the input from the user using scanf.
And that's going to be an integer, that's going to represent a
spot on the board one through 9.
And I'm going to store that in my choice variable.
Choice is an inch, so I have to pass in the address,
and I have to say choice.
Only if it's a string I would not pass in the address.
Then I can basically determine whether or not what the mark is.
I have to determine if the mark is an x or no based on the player.
So I'm going to use the ternary operator again.
And I'm going to assign to mark either an x or o.
If the player is equal to 1, I'm going to assign to mark the x, capital x.
Otherwise, I'm going to assign it an o, capital o.
So this ternary operator is very useful when you have to assign
variables based on a condition.
Again what this is saying is if the player is equal to 1,
mark is going to be equal to x.
Else, it's going to be equal to o.
The question mark represents if the Boolean evaluation is true,
the colon represents if it's false.
Now that I got the correct letter, I can call my function for marking
the board by just saying mark board, passing in the x or the o.
After I mark the board and they made their selection, I have
to check if there's a winner.
I have my variable I which really should probably
should be a better name.
Let's name it status check, game check how about that or game status.
And game status is going to be equal to a one negative one or 0.
Game status is going to be equal to whatever is
returned from check for win.
Because remember, this function will return a one a 0 or negative one.
A one if the game is over with the result, negative one if
the game is in progress, 0 if it's over with no result.
So now that we stored game status, we'll also want to
change the condition of the loop.
So if the game status is equal to negative one,
we'll jump out of the loop.
Otherwise, all we need to do is change the player's turn.
How do we change the player's turn, we just increment the player by one.
That way next time it will go up and it will be 2, and player will be
equal to 2 and we'll go back down.
When they make invalid attempts what happens in the invalid templates
it decrements the player count.
When you decrement the player count, you go back to the correct player.
So if it's one, you decrement it to 0, the next turn is going to be one,
it's essentially your same turn again.
That's why we increment it.
Now if it's player 2, we increment it by one.
And what happens is 2 divided 2 is 0.
So it actually sets the player back to one.
That's how that works.
But this is all the logic.
We did a lot here.
You should not write all this code and test at once.
You should have been working with the divide and conquer, constantly
testing as you're running the code.
Now I'm going to provide this solution, but let's
run it and test it.
It's going to work just like it did in the demo from the challenge lecture.
But again, study this code and make sure you understand what's going on.
The use of arrays and the dividing conquer approach, but look how
nice this main method looks.
It's very easy to know what's going on in the main method.
Display board, change player and you probably want to put in comments here.
Change turns, and then also here get input.
And then set the correct letter, set the correct
character based on player turn.
You don't even really need these comments because the
functions are so descriptive.
Mark board, set the board based on the user choice or invalid choice.
And then the game status check for win, pretty self-explanatory.
And then we jump out if the game is over.
Let's build this.
Hopefully, get no errors, no warnings, we don't, which is nice.
Now let's run it and you're going to see it works just like in our demo.
First thing it does is going to display the screen.
And it's going to allow us to print an enter.
And it has our grid, one 2 3 4 5 6 7 8 9 our array.
So it tells me player one enter something and I'm
enter something valid.
And it draws it, and it clears the screen.
So it looks like nice.
And now there's an x in 3.
Now it's player 2's turn.
I'm going to let do something invalid.
It says invalid moves, it pauses.
I hit return, I get to go again player 2.
Now I hit one, redraws with the o in the one spot.
And I continue this until we have a winner or a loser.
So let's cause a winner for o so.
Now x is going to be, 2 o is going to be 5, x is going to
be 6 and o is going to be 9.
Game over because we just drew 3 0s.
So the one thing I forgot was after the while loop to display
the congratulations you won.
And all we have to do there is we have to check the game status.
If the game status is equal to one, that means a player one and it
would be the last player that win.
So we would print out player percent d wins.
Otherwise, we're going to just print out a draw.
Because if we got out of our loop and the status was a negative
one, we know the game was over and had a result, it just might
so we have to have that last if statement to display the results.
So now let's run it again as a winner.
And now we'll actually see somebody win.
So I'm just going to put in valid numbers here, cause a quick win for
x and actually have to do it in this program because that one goes away.
There it goes, player one wins and it played another nice sound there.
So this was a long lecture.
I apologize for the long lecture.
Study this code, I'll provide it as a source file.
Hopefully, learn a lot about methods in divide and conquer.
Thank you