So let's not add a functionality
for showing this game-over article here,
which then also prompts players to start a new game
if they want to.
Now, for this, we already have this article,
but at the moment, thanks to our styling,
since it has the id game-over it's hidden.
If we look forward the game-over id selector,
we have display: none.
As soon as we changed this to display: block,
this will show up and then we just need to make sure
that we set the player name correctly here.
Alternatively, we simply replace the entire text content
off this h2 element.
To achieve all of that, I'll go back into game.js,
and then maybe at the bottom,
I'll add another new function endGame
where I expect to get the winnerId as a parameter value.
So that should be passed in by the place
where we determined that the game is over.
And then in here,
I wanna show this gameOverElement.
For this, I'll, first of all,
get access to that element here in app.js.
There where I also get access to other elements,
I'll get access to the gameOverElement
by using document.getElementById game-over
because game-over, this id here, is the id
I assign here to this article.
So with that, we have to gameOverElement here.
And in game.js, we can now use this gameOverElement
to change its style
and their display style to block, like this.
This will now show the gameOverElement if the game is over.
Now, that's not all of course though.
I also instead want to output the player name.
And for this, I wanna use this span
which I have here in my h2 element.
And there are various ways of getting access.
We could of course get it by id,
but I actually will use gameOverElement.
And then the firstElementChild,
which will be this h2 element
since that's the first element
inside of the gameOverElement.
And then I'm interested in the firstElementChild
inside of that h2 element, which will be this span.
So I will now access firstElementChild here
on this firstElementChild to get access to the span
in the h2 element in the gameOverElement.
And then I'll set the text content of that
to the name of the player who won.
Now, for that, of course,
we need to find out which name that is.
And for this, we can utilize this winnerId.
This will be one or two based on which player it is.
And now it's important to keep in mind that in app.js,
we had this players array where the first item
is player one and the second item is player two.
So we can use that winnerId,
which is one or two and deduct one,
so that we get zero or one to access the data
for the player who won.
And that's what I'll do here.
I'll get my winnerName by accessing players
and then winnerId minus one,
since winnerId is one or two.
And we need zero or one to access the items in array.
And then .name.
And then it's this winnerName,
which I wanna insert here in this span.
Now, of course, we could also have a draw though.
And in that case, we won't have a winnerName.
For this scenario,
I'll check if winnerId is greater than zero,
which means we won't have a draw
because a draw is signaled by returning minus one.
And I'll then only I'll put the winnerName
if we are having a winner.
So if winnerId is greater than zero,
else if it effectively is minus one,
since this is the only option we'll have in this place.
I instead wanna basically output it's a draw.
And for this I'll then use the firstElementChild
of the gameOverElement, which is this h2 element
and replace the entire text content in there,
including that span with another text
where I say it's a draw.
So I'll say textContent equals It\'s a draw.
This backward slash single quote here, by the way,
is required to escape that single quote in that string,
which is needed to output the single quote
as a character here, instead of telling JavaScript
that the string should end here, because it shouldn't.
Without the backward slash,
this single quote would be interpreted
as the end of the string,
and hence this here would be invalid code,
and that's not what I want.
Hence, with the backward slash in front of it,
that's a special syntax that signals JavaScript
that this single quote is not there to end the string,
but instead we just wanna have the single quote character
in that string.
With that I'm outputting, it's a draw here.
And now with that,
the endGame function should work correctly.
Now, we wanna execute this function
whenever we do have a winner.
So in selectGameField where we are executing
checkForGameOver, I now wanna execute endGame
if we do have a winner.
Now, when do we have a winner?
Whenever winnerId is anything but zero.
Because in checkForGameOver, we are returning zero
if we have neither a draw nor a winner.
So in all our cases, where this does not return zero,
we have a winner or a draw.
So here, after calling checkForGameOver,
we can check if winnerId is not equal to zero.
So it's different from zero, and in that case,
I then wanna call endGame and simply forward winnerId
as a value to endGame.
Because the endGame function wants a winnerId parameter.
And hence, I forward the winnerId value that I got here.
Of course, that it's called winnerId
in both places as a parameter in endGame
and in the place where we call endGame is a coincidence,
you don't have to use winnerId inside and outside
of the function.
These are two independent names,
but of course it's the same value that we use.
And hence, using the same name,
kind of makes sense to describe that value correctly.
So with that, we're calling endGame
if we have a winner or draw,
and hence, I now wanna test this.
For that, I will actually assign player names here
so that I can verify whether the correct player name
is being output in the game over screen.
And then here I'll click on Start New Game.
So that it's my turn, Max.
And now I simply start winning here.
And let's say, as Max,
I now win by occupying the entire first column.
Indeed, I get You won, Max, thereafter.
Now, if I reload and I quickly try this again,
and this time I let Manu win
by, let's say, giving him this diagonal here,
we get You won, Manu.
Now, let's also check for a draw real quick here.
Again, I'll do my best to not win here.
Yeah, then we get It's a draw!
So that's not all the working as expected.
And with that, I now just wanna make sure
that this Start New Game button
then also does start a new game
and does reset that field, appropriately.
Now, for that, to reset that field,
I'll add a new function
and I could add it here at the very bottom,
but I'll actually add it here at the very top,
since this logically belongs to startNewGame.
For me, and hence, it makes more sense to place it
close to startNewGame, not because it's required.
Technically, but because that can make it easier
to find those related functions.
And I'll name this function resetGameStatus.
Because we'll have to do some resetting,
if we had a game in the past
and we now wanna start a new game.
It's not required when we start a new game
for the first time, but if we had a game already,
we, of course, wanna remove that game over box,
we wanna clear that field here,
and we also wanna reset all the data
like the currentRound, and this internal game field,
which we are managing.
And they offer indeed, that's what I'll do here.
I will, for example, sets the activePlayer,
which initially is zero here,
but which changes whenever we switched to player
back to the initial value of zero.
I will also set the currentRound back to one
if we reset the game.
I will also go to the gameOverElement.
And there, I wanna set the firstElementChild.
So this h2 element, back to the starting content here,
which includes a HTML element.
And therefor, I will actually do this
by using the innerHTML property
you learned about before in this course, like this.
By doing that, we don't just set some text content,
but instead we can set some rich content
that also may include HTML elements
that will be treated as such.
And I need that, I need that span here again,
so that later, if a second game is over and it ends,
we can find this span here with this code,
where we rely on that span in that h2 element
to set the winnerName.
So that's why I reset it like this.
And of course, then I also wanna hide the overall
gameOverElement by setting style.displayed back to none.
Of course, I also wanna reset this game field
and get rid of all the symbols and selections here.
And I also wanna reset my gameData here,
and we can combine that.
And for this, we can write a nested for loop here
where we loop through all the rows and columns
of our gameData.
And we have a regular for loop here as we had it before,
but now a for loop with a for loop inside of it,
which can be very useful if you have arrays
inside of an array and you wanna go through all the items
in all the arrays inside off that outer array.
For that, we'll need two helper variables.
And you typically name your first helper variable i,
and then the second helper variable j.
It's not a must do, it's just a convention
which you'll often see.
And hence, I'll use it here as well.
And now with that, we're looping through all the items
here in gameData.
And now that, we can reset gameData, which is useful.
And we can then also reset what we see on the screen.
So the real gameData that is shown here.
Now, let me start with the virtual gameData.
For that, here we can then access
the different fields with i and j
so that we access all the elements in there,
in all the nested arrays.
And I set it back to zero, so that the overall field
is set back to the initial state we had here.
And then of course, I also wanna reset that real field
that we have here.
And we have access to that real game board
through that gameBoardElement here in app.js,
where we select the element with id game-board,
which is this ordered list here.
And in there, we have all those list items.
And we can utilize this and use that gameBoardElement
to get access to all its children,
whoops, children, which will also be an array.
And it will be an array full of all those list items
in that order list.
However, that's not an array of arrays,
but only a single array with nine items.
So i and j don't help us here.
Instead, what I'll do is I'll add a helper variable
gameBoardIndex, which starts at zero.
And I'll use that to access the different list items here
with that gameBoardIndex,
and we'll change these items then see one.
And I'll then increment gameboardIndex by one
after every iteration of that inner loop.
And it is worth pointing out by the way,
that we first will execute the inner loop entirely,
before we move on to the second iteration of the outer loop.
And then we'll again, execute the inner loop three times
before we move on to the last iteration of the outer loop.
So that's how nested loops work.
Now, we get access to all these list items
of the order list as well.
And there, I wanna change my text content
and set it to an empty string.
And I wanna get rid of that disabled CSS class,
which we also add to all of these selected fields
when we select the field.
So here, I will actually store that gameBoardItem,
gameBoardItemElement in a separate constant,
since I'll use it for both setting the text content.
And then for getting access to the class list
and for removing the disabled class like this.
And now with that,
we should also clear what's visible on the screen.
And now with that, I'm resetting that gameBoard.
Now, I also wanna go back to game.css now
and set the display to none here
for this active-game selector.
So that initially, this gameBoard
is now not showing up anymore.
That is the default behavior
I wanna have at the start anyways,
I just changed this so that testing was a bit easier.
But now that we're finishing up everything,
I'll change this as well.
And the resetting logic should now also be done.
Let's quickly check app.js and our helper variables.
That's all looking good though.
Now, one side note, the editedPlayer,
and also our overall players with the names that were chosen
are simply not reset because we can continue
with the player names that were chosen before.
Hence, I'm not resetting those player names
or anything like that.
I really just wanna reset the gameBoard.
And therefor, now with all that implemented,
the last step is to call resetGameStatus.
And when I called that, whenever we start a new game.
So here, before I changed the activePlayer name
that's displayed, I wanna call resetGameStatus.
And this should hopefully do the trick.
If we now save all of that and go back here,
if I reload and try starting a new game
without picking player names, I get a warning as expected.
Now, I will pick my names here, Max and Manu, let's say.
And if I now start a new game this works,
and I can now play this game just as before
and now I got a winner.
And if I now click on Start New Game again,
that's looking good.
It's now my turn, Max, still have my symbol here.
And now I wanna make sure that Manu wins,
and hence, I get You won, Manu.
And if I start a new game, that's all looking good.
And therefor, this is working.
As a side note, what is possible
is that you change your player name
whilst you are playing, but that's no problem.
You could, of course, prevent this behavior somehow.
You could add logic that locks editing
whilst you are playing a game,
but I'm fine with this behavior.
Why wouldn't you change your name?
Now, let's also check whether resetting after a draw
works correctly.
And for this, I'll do my very best
to force another draw here.
Yeah, if I now start a new game,
still looks like everything is working.
And if we now have a winner again, that also works.
And we've got no errors here in the console,
and I didn't find any errors, any bugs
while playing here either.
Now, one thing I just noticed here
is that there is actually a little bug or issue.
We can still select fields after the game is over.
That's something I wanna change
and we can't easily make sure
that this is not possible anymore
by going to selectGameField.
And here, we return if we did click on anything
that's not a list item.
I also wanna return and not select a field
if the game is over.
Now, when is our game over?
Well, as soon as we have a winner.
And to find out whether we have a winner or not
in this place here,
I'll add another little helper variable here,
gameIsOver and set this to false initially.
And I'll set this to true if the game is over.
So if we did end the game, so in that endGame function,
which we have here, there, I will set gameIsOver to true.
And I'll set it back to false if we reset the game.
So here in resetGameStatus,
I'll set gameIsOver back to false
because we're starting a new game.
And now with that gameIsOver a helper variable added
in selectGameField, I can now check
if we are either not clicking on the list item
or if game is over as true.
And for that, we could check if it's equal to true,
but since gameIsOver already stores true or false
as a value, just checking for game is over like this
is enough since that already is true or false.
And if this is true, we'll also make it in there
and we'll not be able to select another field.
That would be one way of solving this little issue,
this little bug here.
And with that, if I quickly give this another try,
if I add my two players here,
and I then quickly make sure we have a winner,
indeed, thereafter clicking
doesn't do anything anymore.
If I start a new game, I can, of course, click again.
So now this bug is also fixed.
And therefor, that should now be the finished game
with all that logic that we need to implement that game.