So we reflect
the selection of fields here
to the user on the screen.
But as mentioned, I also want to store my data
in my code so that we can run
some check for winner logic there.
And that brings up one question.
How should we store the data?
How should we check for a winner?
Well, there will be multiple ways
of storing this, but in the end,
the best approach probably
is to use a two dimensional array.
And that's actually also a new concept,
though it's not really new.
It's just an array with other arrays as values.
And I'll show you what I mean here in app.js.
Here, we already store data
about our active players and so on.
I now also want to add a brand new constant here,
which I'll name gameData.
And this will be an array.
Now in this array, I want to have
three other arrays
and every child array in there,
so every array in that array,
should have three values
so that they kind of replicate
the three columns and three rows
here in this array.
And initially I'll set these three values,
which I want to have in every child array, to zero.
This should signal that this field
has not been selected by any player.
So now you see this kind of replicates
what we see on the screen here.
We have nine fields here,
initially all empty,
without any selection.
Now I want to set the different field values
whenever a field was selected.
And for this, in game.js here,
in selectGameField,
besides updating what we see on the screen,
before we switch the player,
I now want to update the field
that was selected
in my gameData array of arrays.
Now how could we make this work?
Well, for this, we can again use this data- attribute,
which we learned about before.
We can attach extra data to all these list items
so that once we clicked on a list item,
we can use this extra data.
And here I'll add a data field ID,
and set the first field to one, let's say,
and then simply add that to all the list items,
but increment the number by one
for every list item.
Like this.
That's what we could do.
Or we take it a step further
and we actually set this to data col
for a column,
and say this is the first column,
and add a data row,
and set this also to one
because the first list item
is in the top left corner
is the first row and the first column.
The next list item, this one here,
so with a two here is in the first row
and second column.
Let me remove this two here,
which I just added so that you can see
where this list item is positioned.
And therefore here I set this to data col,
set this equal to two because it's the second column,
but again, data row equal to one.
And the next list item here,
that's the top right one,
is in the third column,
but still first row.
So we just change col to three.
And now we repeat this for the next set of list items.
Here we start in the first column again,
but now we're in the second row,
and we're in the second row
for all these list items.
So for all the list items
I now just change the column.
And we then do that for the third set
of list items as well.
Here we set data row to three
because these are the three list items
in the bottom row here.
And we just then switch
through all the different column values.
Now the use of that is that we can now extract that data
whenever we click on one of these list items,
and we can then use that data
to dynamically access the different arrays
inside of our array here,
and then set these different values in there
to either one, if it was selected by player one,
or two, if it was selected by player two.
And if we then later check for
whether we have a winner or not,
we just have to look into this array
and find if we have adjacent ones
or twos also diagonally,
which I'll show you how to do,
to find out whether we have a winner.
That's why I'm using this approach.
So therefore now with data col
and data row added in game.js here,
we can get the selected column
by accessing event.target.
And since I'm using this over and over again,
I'll actually store it in a little helper constant
selectedField, which I now use here and here,
and then also here.
And now on that selectedField,
I will access data set
and then col to get the column,
col here because I chose col after the dash,
and then row for the row.
So I'll repeat that and get my selectedRow
by accessing dataset.row.
Now to update the gameData.
So there's array defined here in app.js.
We just want to dive into that.
And here we actually use two square brackets
after each other.
The reason for this is that
with the first set of square brackets,
we dive into the main array,
and then we select either the first
or second or third array in that array.
And with that second pair of square brackets here,
we then select an item in that inner array,
the first, second or third item in there.
That's what we do.
And therefore, with the first pair of square brackets,
we actually decide which row we want to dive in
because the rows are the main items here in this array.
And then with the second pair of square brackets,
we decide which column we want to use.
So here we could use selectedRow
and selectedColumn.
But that would be wrong since our data there
is actually not a number, but a string
and starts at one and not at zero.
And of course, for array indexes
we should start at zero.
Therefore, to update this correctly,
I'll actually deduct one
from both the column and the row.
And if we deduct one here,
we perform a mathematical operation
and that will automatically convert
the result to a number.
So we don't have to add the plus here
though we could do that.
But it's not required because of the mathematical operation,
which we are performing anyways.
And with that, selected column and row
will be numbers from zero to two each.
And with that, we access our game data field.
And now I just want to set this equal
to activePlayer plus one.
Plus one because activePlayer
by default is zero
for the first player
and one for the second player.
But in here, in this array,
I actually want to store one for the first player
and two for the second player
because zero is used for no player here.
Therefore I add plus one
to set the first player to one
and the second player to two as a value.
And now, so that we see whether that works or not,
I'll console log gameData.
I will log that array
to see what's inside there.
So if we now save everything
and open the developer tools in the console there,
if I click on the first item,
I get an array where the top left item is a one,
because player one clicked on the top left item.
If I click on the bottom right item
with player two,
then the updated array
should have the bottom right field filled out,
but instead it's the one in the middle row,
which is not correct.
So let me see why this is not working
because I forgot to update my rows here.
This should be data row three here, not two.
So once this is fixed, if we try this again,
click on the top left item with player one
and the bottom right item with player two,
then we have the behavior we want.
Now, if I click in the middle one with player one again,
we see a one here in the middle, indeed.
So that's working.
And with that, we're keeping track
of which field is selected by which player
here in the background, in our JavaScript code.
And we'll then need that for determining a winner.
Now before we move on to determining a winner, though,
let's handle one scenario that could also occur.
What if player one clicks on this field
and then player two clicks on it as well?
Even though we don't signal that it's clickable,
we can, of course, technically still click on it.
If that happens, you see,
indeed, that click was registered,
a new array is returned,
and indeed now player two owns this field.
I also did update it here.
We can switch on that field.
And that's not the goal.
Once a field has been selected by a player,
the other player should, of course, not be able
to select it as well.
And to achieve this,
we want to check whether the field
on which we clicked was clicked already,
if it already is assigned to a player.
Now how can we find out whether that's the case?
Well, it is quite straightforward.
Let's actually get the selected column and row
a little bit earlier before we update the screen
and place the players symbol there.
And then before we well, update that screen,
let's check if gameData
for that selected row and column,
so using the same access pattern as down there,
if that is greater than zero,
because it will be greater than zero
if this field has already been assigned
to a player.
Because we start with zero for every field here,
and then once a player clicked on it,
we place one for player one
and two for player two in that field.
So if it's greater than zero,
we know that this field
has already been assigned to a player.
And that's another example of why it's important
to keep track of our game data in code
and not just update the UI.
Because now here, in this if-block,
we can then return, again,
to stop function execution
and to avoid that this code executes,
and then maybe show an alert
where we say "Please select an empty field."
Like this.
And if we do that,
then if I click on the first field
and I click on the same field again thereafter,
I get the warning and the player is not switched.
I can select a different field instead.
And I can't reassign fields,
which is of course not something we'd want.
So this is now another adjustment
we should implement here.