Game over
Overview
Currently when the game is on, we display the Board
component to the players. When the game is over we want to show a different GameOver
component which we will work on. This component will show the players the status of the game (We'll see what status means in a moment) and in case there was a winner, it will also show which player won black or white
Here's a preview of what it looks like
What does Game Over mean in Chess
In chess, there are four scenarios that would lead to a game being considered over and not all this cases have a clear winner. Chess.js has methods that can help us check for this scenarios.
- When the King of the player in turn is in check and they have no legal move to escape check, they've been checkmated and lose the game
//Returns true or false if the side to move has been checkmated.chess.in_checkmate();- When the next player in turn is not in check but has no legal move they can make
//Returns true if the side to move has been stalemated otherwise false.chess.in_stalemate()- A player may claim a draw if the same position occurs three times on their turn because such a game might go on indefinitely.
//Returns true if the current board position has occurred three or more times.//Otherwise falsechess.in_threefold_repetition()- The the game is immediately declared a draw if there is no way to end the game in checkmate due to insuffient pieces. e.g k vs K
//Returns true if the game is drawn due to insufficient material otherwise falsechess.insufficient_material()- If any of the cases 2, 3 or 4 are occur, then the game ends in a draw and there is no winner. We only have a winner if the game ends in checkmate.
//Returns true if the game is drawnchess.in_draw()
getGameOverState
function
To get started, let's create a function getGameOverState
that checks through this cases to determine when the game is over, and the status.
Create a new file game-over.js
in src/functions/
and add this code.
The getGameOverState
function takes in the chess object and returns an array of two values. The first value is a boolean showing whether the game is over or not and the second value is the game over status e.g checkmate or stalemate
Export this function in src/functions/index.js
by adding this.
GAME_OVER
action
Next, we use this function in our Game
component to determine the game over status.
We can check for game over status in the useEffect
call that runs everytime a move is made (the fen is updated).
Initially we were only dispatching the event type: types.SET_TURN
, but now, we first get the game over status by calling getGameOverState(chess)
. It returns the gameOver
value and the status. If gameOver
is true, we dispatch an action of type types.GAME_OVER
, we also provide the status
and the player
in turn as part of the action.
Let's update the GameReducer function which updates our Game state. In src/context/GameReducer.js
add a new case for the types.GAME_OVER
action.
We set gameOver
to true, and set status
and turn
to what we receive from action.status
and action.player
respectively. The value of turn
will help us find out which player has been checkmated in case the game ended in a checkmate.
Let's add the gameOver
and status
value as part of our initial state in src/context/GameContext.js
GameOver
component
Let's create the GameOver
component which will be rendered when gameOver
is true.
We saw a preview of this component at the beginning of this section.
To get started, create a new folder in src/components
and save it as layout
.
In components/layout
create a new file index.jsx
where we will create a Layout
component. This component will give us the general layout we will use in the GameOver
component. It's going to be a resusable component so that we can easily reuse the same layout in our App. Let's also create the stylesheet for this component in layout/layout-styles.css
;
For the Layout component, add the following in index.jsx
The Layout
component takes two props. These props will be components. The first prop is Image
to show the image on the left and the second prop is Content
for the content of the component. The Layout component aligns the Image
and Content
components we receive in props as shown in the preview.
The styling is applied through layout-styles.css
. To keep this section short, we decided to share the CSS through a GitHub gist, you can find it here and add it to your own layout-styles.css
file.
We make use of some external fonts in layout-styles.css
. To make them available, include the following tag in public/index.html
within the head
tag. Note that public is outside of the src
folder.
Now let's use this Layout
component to easily create our GameOver
component.
In src/components
, create a new folder gameover
and in the folder add two files index.jsx
and game-over.styles.css
Let's create our GameOver
component in gameover/index.jsx
by adding the following code.
First, we get our status
and turn
from useContext
. If the status is checkmate, then the player in turn has lost and we assign our winner variable accordingly.
Next, we create a Content
component that shows the status of the game. If there is a winner, then the winner will be displayed {winner && ( <p> <mark>{winner}</mark> won </p> )}
.
We also have an image and a play again button that does nothing for now. Notice that our return statement in Content
is wrapped in <React.Fragment/>
.It's just an empty wrapper to ensure that we return a single top-level element since we can't return multiple elements, React.Fragment
doesn't get inserted in the DOM and it has no semantic meaning.
Next we create an Image component that displays the main image we want to have in our layout.
Finally we return the Layout component providing the Image
and Content
as props.
To get this images download all the assets used in this project from here.
To style this let's add some css in gameover-styles.css
. You can find the css in this Github gist
Early conditional return
When gameOver
is true, we need to render a different component other than the Board
. In our Game
component, let's get the gameOver
value from our context and return a different component if gameOver
is true.
Only change the newly added lines, the rest of the code remains unchanged. Find the complete code snippet for the Game
component here
note
Ensure that the early conditional return for gameOver is used after all your hooks have been declared.
Just make sure it's at the bottom of the component, right before the main return statement. This is because hooks should be used at the top level of your component, and before any early return statements like we have here. Read more about the rules of hooks
To test this out, temporily replace the FEN in your Game
component with the following values
The code for this section can be found in this Github branch.
In the next section, we will start working on real-time communication with websockets