Course: Section

Episode: Title

## S03・V15:Calculating the Winner

Date Created: July 17th, 2019
Last Updated: 27 days ago

Objectives
1. We will create a function to calculate if a combination of moves has resulted in a win or not.
2. We will show the result of a winning combination in the status text.
Watch Video
Duration: 4m 49s

### Calculating the Winner

Next, we will show when the game has been won. We will create a helper function to calculate which player is the winner. At the end of the file, let’s create a function using the function expression syntax. This will ensure the function is hoisted to the top, and accessible to our components.

We will call our function `calculateWinner`. It will take our `squares` array as its input parameter.

``````function calculateWinner(squares) {

}``````

It will return either `X`, or `O`, or `null`. To help us write which combinations are winning ones, let’s add the indexes of the squares in comments.

``````function calculateWinner(squares) {
/*  0 1 2  3 4 5  6 7 8  */}``````

A player wins if they have a line of `X`s or `O`s. So, we will put our winning combinations in an array that we will call `lines`. The first winning combination is the first row of our board. That is, the row of indices: `[0, 1, 2]`. The second and third rows are also winners: `[3, 4, 5]` and `[6, 7, 8]`. The columns are winning combinations: `[0, 3, 6]`, `1, 4, 7]`, and `[2, 5, 8]`. The diagonal from top left to bottom right will also win the game: `[0, 4, 8]`. And the final winning combination is the diagonal from top right to bottom left: `[2, 4, 6]`.

``````function calculateWinner(squares) {
/*
0 1 2
3 4 5
6 7 8
*/
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];

}``````

Now, let’s iterate over each combination in this winning lines array. If the values at each index within a combination are either all `X`s or all `O`s, then the player has won.

We will loop over the `lines` array: `for (let line of lines) {...}`. We will use “destructuring assignment syntax” on each line to unpack each individual index within it: `const [a, b, c] = line`. If the value at index `a` is non-null: `squares[a]`, and if it is equal to the value at index `b`: `squares[a] === squares[b]`, and if the value at index `a` is also the same as the value at index `c`: `squares[a] === squares[c]` then we know that all values in a winning line are all the same and not null. In this case, we can return the winning value, which is either an `X` or an `O`: `return squares[a]`. If this is not the case, let’s return `null` from the function to indicate that there is no winner: `return null`.

``````function calculateWinner(squares) {
/*
0 1 2
3 4 5
6 7 8
*/
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];

for (let line of lines) {    const [a, b, c] = line;    if (      squares[a] &&      squares[a] === squares[b] &&      squares[a] === squares[c]    ) {      return squares[a];    }  }  return null;}``````

### Update Status with Winner

We will call the `calculateWinner` function in the `Board` component to check if a player has won. If a player has won, we can display it in the `status` text. We will update the `status` depending on whether there is a winner or not.

``````  const winner = calculateWinner(squares);
const status = winner ?
`Winner: \${winner}` :
`Next player: \${xIsNext ? 'X' : 'O'}`;``````

Now, we can test it in the browser. Click on index `0` first. The game now correctly shows that the next player is `O`. Then click for player `O` on index `1`. Click for player `X` on index `4`, in the center. Click for player `O` on index `2`. Finally, click for player `X` on index `8`. The game correctly shows the winner is player `X`.

### Code Snapshot

src/index.js
``````import React, { useState } from 'react';
import ReactDOM from 'react-dom';

import './index.css';

const Square = props => {
return (
<button
className="square"
onClick={props.onClickEvent}
>
{props.value}
</button>
);
};

const Board = () => {
const initialSquares = Array(9).fill(null);
const [squares, setSquares] = useState(initialSquares);
const [xIsNext, setXIsNext] = useState(true);

const handleClickEvent = i => {
const newSquares = [...squares];
newSquares[i] = xIsNext ? 'X' : 'O';
setSquares(newSquares);
setXIsNext(!xIsNext);
};

const winner = calculateWinner(squares);
const status = winner ?
`Winner: \${winner}` :
`Next player: \${xIsNext ? 'X' : 'O'}`;

const renderSquare = i => {
return (
<Square
value={squares[i]}
onClickEvent={() => handleClickEvent(i)}
/>
);
};

return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{renderSquare(0)}
{renderSquare(1)}
{renderSquare(2)}
</div>
<div className="board-row">
{renderSquare(3)}
{renderSquare(4)}
{renderSquare(5)}
</div>
<div className="board-row">
{renderSquare(6)}
{renderSquare(7)}
{renderSquare(8)}
</div>
</div>
);
};

const Game = () => {
return (
<div className="game">
<Board />
</div>
);
};

ReactDOM.render(
<Game />,
document.getElementById('root')
);

function calculateWinner(squares) {
/*
0 1 2
3 4 5
6 7 8
*/
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];

for (let line of lines) {
const [a, b, c] = line;
if (
squares[a] &&
squares[a] === squares[b] &&
squares[a] === squares[c]
) {
return squares[a];
}
}

return null;
}``````

### Summary

We created a helper function to calculate if there was a winner. The calculation ran on each re-render of the status text, and showed the result.

### Next Up…

In the next video, we will prevent setting the value of a square if someone has already won or if a square already has a value.

Previous Video
Next Video