Design and Implement Checkers Game Using Oops Concept
Creating a Board Game (Checkers) With JavaScript
One of the best ways to learn web development is by creating a game. With the basic tools of javascript, you can get started. As a beginner it can be daunting. It's easy to get caught it "tutorial hell" because you think that you need to keep learning before you can begin creating. I will prove to you that is not the case by walking through how to create the board game checkers.
I am only covering HTML, JavaScript (including the DOM) and very small amounts of CSS, so I will assume that you know how to use the basics of those.You should also know how to play checkers of course…
If you would like to see the finished code, you can visit the GitHub repository here: https://github.com/RyanBranco/Checkers
First is the HTML.
To draw the board for the user, I use a <table>
. A checkers board can be easily created by using a table, because thats exactly what a checkers board is; an 8x8 table. In-between the opening and closing <table>
tags, we need 8 <tr>
(table row). The<tr>
doesn't actually create the cells in the rows, it only defines a new row for you to enter the cells; so inside of each of the 8 <tr>
that you just created, there needs to be 8 <td>
(table data) which is going to create the actual cells for the board.
Here is what the skeleton should look like:
You wont see anything displayed on the webpage yet because there is no data inside the table. That is going to be the next step.
Now is the HTML that each <td>
should have.
There are cells on the board that will never have pieces, I give those a class="noPieceHere"
. This is important for the javascript logic (covered later) and the CSS (so they have a different color). The very first <td>
should have the noPieceHere
class, and should be alternated throughout the board (creating the checker board effect). Here is what one row will look like:
Now this needs to be duplicated for all of the other 7 rows, and remember that this needs to be alternated. Which means that the next <tr>
is going to start with a <td>
that does not have the noPieceHere
class.
Now the CSS for the cells.
Each <td>
has a background-color: #BA7A3A
, Width
& Height
of 65px
(so each cell looks like a square), and text-align: center
(to center each piece). Then the .noPieceHere
overwrites the color of the <td>
to #F0D2B4
(so it can look like a checker board).
*The cells can be customized how you wish*
Once Completed, you should have an empty checker board! Now let's populate the board with pieces.
In each <td>
that does not have a class="noPieceHere"
, is where the pieces are going to lay. I use empty <p>
tags for red pieces, and empty <span>
tags for black pieces; this isn't absolutely necessary, but I think that it makes it easier to iterate over the pieces once we move to JavaScript.
Red pieces have a class="red-piece"
and black pieces have a class="black-piece"
, and each piece should have its unique id
.
Each color has 12 pieces on opposite ends, and there should be 2 rows left open in the middle.
Here is an example of one row on each end:
In JavaScript we will need to give pieces a class="king"
once a piece reaches the opposite end of the board, so we need to define the .king
in the CSS for when it does get appended by JS.
Here is the CSS for the pieces and the king class:
*The pieces can be customized how you wish*
If you want the player to know who's turn it is, you can add some HTML underneath the checker board that will change color depending on who's turn it is.
Text color is going to be changed with JavaScript, but here is the static HTML:
Don't forget to add the classes to each <div>
, because we will need to reference these in JavaScript so we can change the style depending on the player turn.
You can style these how you wish, but I start off with giving .black-turn-text
a color of grey to make it look faded out (so the user know's that the game starts on reds turn).
The final result of the HTML and CSS should look similar to this:
Nice! The HTML and CSS is complete! Now the real fun begins… JavaScript!
There is going to be three major events in the JavaScript logic:
- When a piece is clicked
- when a cell is clicked
- Data that is changed after a the cell is clicked
But before we step into the logic, we need to initialize game state data, and declare variables that reference items in the DOM. Let's jump in!
First, we need to create a representation of the board, on the back end. This can be done with a 64 item array (each item representing a cell).
The numbers that you see hardcoded are the id's of the pieces on the board, and positioned where they should be on the board. This easily allows our code to "see" where the pieces are. Later on we will be manipulating this array to change based on where the pieces are moved.
Next, we need to establish variables that we will use to reference things (in the DOM and player properties).
First by using the DOM, we grab all of the cells
(line 23), all of the pieces on each side (line 24 and 25), the turn text for each side so the user can see who's turn it is (line 26 and 27), then the divider
(line 28). Don't worry about the divider if you don't have one, all I am going do is change the display: none
to make is disappear when a winner is displayed.
Now we need to save user variables to keep track of the game state.
I use the turn
variable to represent the current players turn (true
=== reds turn & false
=== blacks turn [line 31]). Once a player has 0 pieces, the opposite player wins, so we need to keep track each players "score" (line 32 and 33). Finally is the playerPieces
variable. This variable allows us to dynamically hold all of the current players pieces. The benefit with this, is that we don't have to be writing code twice (for reds turn and blacks turn). We will dynamically change what player pieces are being referenced so we only have to write code once.
If the playerPieces
variable is a little confusing don't worry, I will be going over it shortly.
Now comes the object that will hold the properties of the pieces.
When a piece is clicked, the selectedPiece
object will dynamically change based on the properties of the piece that the user clicked. We will program Javascript to analyze the possible moves around it and change the true / false values based on the possible moves. I will show how this is done later. It involves the board
array that was created earlier.
When a piece is clicked we need to grab a few things: the specific id
for the piece (line 38), the index of the board piece that the piece is on (line 39), if its a king (line 40), and all of the possible moves that are available (lines 41–48).
Before we get into the actual functionality of the game, I will explain my design choice on the way movement is done.
Pieces on the board can only go in opposite directions originally, but once it reaches the opposite end of the board it becomes a "king" and then has full directional movement. I have discovered that having a "backwards" way of designing the movement for the pieces involves less code. So first we will analyze all available squares that the piece is available to jump (regardless of the piece color, or if its a king or not), then restrict movement based on the players turn.
If it is not done this way, three functions will have to be written that look almost identical; one for the red pieces, one for the black pieces, and one for the kings. Duplicating code is not good practice because it's more prone to bugs, harder to debug, tedious to write, and a lot of unnecessary code. The way that I described only involves one function to analyze the surrounding cells available, and another one that will easily edit the selectedPiece
properties depending on the players turn. If this is a little confusing, I will show you how this will be done shortly.
Now we need to give the pieces a click
event listener. The givePiecesEventListeners()
function will give the pieces an event listener that will invoke the function getPlayerPieces
. The getPlayerPieces()
is the beginning of the chain of functions that will manipulate the selectedPiece
object that I showed earlier.
So at the very bottom of the JavaScript file, call the function that initializes the event listeners, like so: givePiecesEventListeners()
.
These next few functions might seem confusing at first because it is going to involve things that I have not covered yet in the code. They reset traits that have not been changed yet in the code. But it needs to be done first in the chain because if a user clicks a piece to move, everything is going to be analyzed and the cells around it will get "onclick
's" based on the position the pieces can move. But then, what if the user decides that they don't want to move that piece? They should be able to select another piece instead. So in order for that to happen, certain properties need to be reset in the code so that the new piece that was selected is able to move properly.
This is where the playerPieces
variable is going to be changed. Simply, if (turn)
(meaning its reds turn), set the playerPieces
variable to redsPieces
, else…
(meaning its blacks turn) set playerPieces
to blacksPieces
. Then call the function removeCellonclick()
. Then once removeCellonclick()
is finished, run resetBorders()
.
First, let's cover removeCellonclick()
.
This function loops through all the cells on the board (line 81). Then removes the onclick
attribute (line 82).
Later on I will show you why the onclick
for cells need to be attributes, but for now all that you need to know is that it's because we will need to dynamically add and remove them.
Now let's cover resetBorders()
that was called earlier.
We will be giving the selected piece a border of green later on (to show that the piece is selected to move), but if the user selects a different piece the older piece needs to reset back to default. So this function loops through all the playerPieces
(this was set earlier) and will change the pieces to have a border = " 1px solid white"
line(89). Once that is finished resetSelectedPieceProperties()
is called, then getSelectedPiece()
.
First let's cover what resetSelectedPieceProperties()
does.
This resets all of the properties of the selectedPiece
object, back to normal. This needs to happen on every cell click, because we don't know what the properties from the previous selected Piece were. Since the cells are getting onclick
based off the selectedPiece
conditions, it needs to be reset every time a piece is clicked, or else cells will have incorrect onclick
attributes.
Now moving onto getSelectedPiece()
.
We need to be able to find where the piece is located on the board. That is when getSelectedPiece()
comes into play.
When a piece is clicked it will give you the event
. We can grab the id
of the piece by typing event.target.id
. event.target.id
returns a string of the id
, and we want it to be a number so JavaScript can read it properly when we put it in relation to the board
array. So by surrounding parseInt()
(line 112), we can turn the string into a number. We also need to find where the piece is located on the board. This is where the findPiece
function comes into play.
findPiece()
takes one parameter, which is the piece's id. Once we save the parseInt()
version of the piece (line 18), we pass that into the javascript method indexOf
(line 19) and return
it. This will give you the exact index position of where the selected piece is.
Up next on the chain of functions is isPieceKing()
.
The isPieceKing()
function should be self explanatory, it finds out if the selected piece is a king or not.
By using .classList.contains("king")
on the selected piece HTML element (line 119), we can determine if its a king or not. Easy! Later on you will see how the piece is given the class of king.
Then invoke getAvailableSpaces()
getAvailableSpaces()
analyzes the surrounding cells that a piece can make without jumping another piece (next function will cover jump spaces).
If you count the cells, pieces can move either + / — 7 cells, or + / — 9 cells (plus or minus depending if the piece is red or black). Let's take a look at the first if
statement, because once one of them is understood, you understand the rest (lines 129–131).
If the selectedPiece.indexOfBoardPiece + 7 === null
(which means the spot is available) and the same cell does not have a class of noPieceHere
(line 130), the piece can move! So we set that property on selectedPiece = true
line(131).
Line 130 is important because 7 or 9 spaces to pieces on the edge, is a cell on the opposite end of the board, and obviously we can't jump to there, but those cells have a class of noPieceHere
luckily. So we need to make sure we don't have the option to jump there. Line 130 prevents that.
Now let's take a look at checkAvailableJumpSpaces()
.
checkAvailableJumpSpace()
does the same thing as checkAvailableSpaces()
except… you guessed it… for jumping the pieces.
The function is almost the same, the difference is that it's + / — 14 or + / — 18 (plus or minus depending if the piece is red or black). The extra condition inside of the if
statement is if the position being jumped is >= 12
meaning the piece is black (because black pieces have an id
greater than or equal to 12), and red pieces have an id
less than 12.
Unfortunately, this function needs to duplicate code for each side (red and black). This is because of how we have to specify the pieces id
's. There is probably a way to eliminate the duplicated code, but I am not sure how. So if someone can find a way to eliminate the need to duplicate code, feel free to post in the comments below.
Make sure after this function we call the next one, which is checkPieceConditions()
. I don't show it in the picture, but it is absolutely necessary, because we need to continue the chain.
Now that we have analyzed all of the possible moves for the piece, we need to restrict the movement based on the turn.
Since a king has full movement, and it doesn't matter what side it's on, we don't have to manipulate any properties. So we can just continue to the next function, which is givePieceBorder()
(line 199).
If it's not a king we need to remove all of the "minus" movement properties for the red pieces, and remove the normal movement properties for the black pieces. This is how we restrict the movement.
Then… we move onto the next function, givePieceBorder()
.
In order to make the piece appear it's selected, we need to give it a green highlight. So… if any of the selectedPiece
movement properties are true, we change the document.getElementById(selectedPiece.pieceId).style.border = "3px solid green"
. Then move onto the next function giveCellsClick()
(line 221).
If none of those are true, meaning that the piece does not have a possible move, do nothing (return;
)
Now we need to give the cells an onclick
attribute, based on the possible moves the selectedPiece
has.
So, if the selectedPiece.[movement property]
is true, give that cell an onclick
attribute of makeMove()
.
makeMove()
will take an argument of the number or places the piece will move. If the piece is going to move seven spaces (selectedPiece.seventhSpace
), give the cell an onclick
of makeMove(7)
, and this will be done for all of the possible moves.
Now here is the reason why wee need to give the cells an onclick
attribute instead of an event listener
: If we were to give the cells an event listener and pass a parameter, the function will instantly run, because technically it is being invoked. Using an anonymous function is out of the question because it needs to be removed, and you cannot remove anonymous event listeners.
This is the end of the function chain for when you click a piece, so we do not need to automatically invoke any more functions. The next function (makeMove()
) is what will be invoked for when a cell is clicked, AFTER a piece is selected.
Time for the function that does a lot of the heavy lifting! Its a little complicated but try and bare with me.
First we need to remove the piece on the front end, we can easily do that with .remove()
(line 259), and change the .innerHTML
of the cell to empty strings (line 260). With the combo of those two, the cell will look like nothing was ever there.
Now for the if…else
statement. if (turn)
(line 261), then… if (selectedPiece.isKing)
we want to make a new HTML element of the piece that has a class of king at the new cell that was clicked (line 263). Then reset the redPieces variable to querySelectorAll("p")
(line 264); this is very important because if it's not done the new piece that was just created will not be saved in the JavaScript memory. So when you click the new piece when the next turn comes around, nothing will happen because JavaScript will not have given it an event listener. So make sure this line is added in.
Duplicate this code for the else
statement on line 265, but without the class of king.
The code above can be duplicated for the outer else
statement (line 269), but change everything regarding the red pieces to black pieces, and don't forget to change the "p"
to a "span"
(line 272 & 275).
Now I save selectedPiece.indexOfBoardPiece
to a variable (line 279). I am not exactly sure why, but you cannot pass object properties directly into the arguments of the function, so this needs to be saved as a variable.
if
the number is a jump move (line 280), the next function that will be invoked will have the third parameter as the position of the piece that got jumped (this is needed because we will be removing the piece that got jumped from the board). else
call the next function with the two specified parameters, which is the old spot, and the new spot.
Next function we will change all of the data on the back end to reflect the board from the front end.
Here we will be manipulating everything on the back end. As well as giving the piece a class of king if necessary.
First we change the original position of the selected piece to null
(line 289), because the piece no longer exists there; then change the new piece position equal to the id
of the piece that was moved (line 290).
The if
statement on line 291 says: if its reds turn, and the selectedPiece.pieceId < 12
, and its new position is >= 51
(≥ 51 is the last row on the board), then give the piece a class of "king"
. Then do the opposite for blacks turn (line 294–296).
Now if the removePiece parameter exists (line 297), change the removed piece on the board
array to null
. Now if its reds turn (line 299), make the piece disappear on the front end and remove a score from black (line 301). Then vice versa if it's blacks turn.
Once all of that is finished invoke 3 functions: resetSelectedPieceProperties()
, removeCellonclick()
, and removeEventListeners()
. The first two we have already written so I will not cover those, but those need to be invoked so all of the data can be reset for the next turn (which is why we didn't invoke any other new functions inside of those two: so they can be reused).
Now it's time for removeEventListeners()
.
Don't worry… we are almost done.
If it is reds turn (line 315), loop through all of the redsPieces
and remove the click
event listener, then in the else
statement do the same for blacksPieces
.
Then invoke the checkForWin()
function.
If either score is 0, change the opposite turn text to .style.display = "none"
and the player that won to "RED WINS!".
You can get creative as you would like with this, as long as the player knows that they have won.
A couple side notes: if you did not have a divider, don't worry about it, and the loops that you see on line 331 and 338, is because I have multiple [player]TurnText
(one for mobile and one for desktop), So if you only have one [player]TurnText
, the loop is unnecessary.
Now the last function changePlayer()
!
If its reds turn, change the turn
variable to false, then change the color of blackTurnText
to black and redTurnText
to lightGrey (vice versa if turn was false, meaning it was blacks turn).
The same logic of the loop applies from the previous function. So if you only have one [player]TurnText
, the loop is unnecessary.
Finally, invoke the function that was from the very beginning: givePiecesEventListeners()
, to restart the entire cycle over again.
Line 365 is the very last line of the JavaScript file. This needs to be invoked at the global level, so the cycle begins once the page has loaded (how I explained it when I was reviewing the function originally).
🎉 Congratulations! You now have a working Checkers board game! 🎉
If you would like to get my code, you can grab it here: https://github.com/RyanBranco/Checkers
Now you should have understanding of how the tools of JavaScript (even most programming languages), can be utilized. I encourage you to create something on your own, because that is the best way to learn! Now you have no excuse.
Design and Implement Checkers Game Using Oops Concept
Source: https://levelup.gitconnected.com/creating-a-board-game-checkers-with-javascript-ecd562f985c2
0 Response to "Design and Implement Checkers Game Using Oops Concept"
Postar um comentário