Skip to content
Open
73 changes: 50 additions & 23 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,81 @@ import Board from './components/Board';

const PLAYER_1 = 'X';
const PLAYER_2 = 'O';
const WIN_CONDITIONS = [
[ [1, 2], [4, 8], [3, 6] ],
[ [0, 2], [4, 7] ],
[ [0, 1], [4, 6], [5, 8] ],
[ [0, 6], [4, 5] ],
[ [0, 8], [1, 7], [2, 6], [3, 5] ],
[ [3, 4], [2, 8] ],
[ [0, 3], [2, 4], [7, 8] ],
[ [6, 8], [1, 4] ],
[ [0, 4], [6, 7], [2, 5 ] ],
]

const generateSquares = () => {
const squares = [];

let currentId = 0;

for (let row = 0; row < 3; row += 1) {
squares.push([]);
for (let col = 0; col < 3; col += 1) {
squares[row].push({
id: currentId,
value: '',
});
currentId += 1;
}
for (let i = 0; i < 9; i++) {
squares.push({
id: i,
value: null,
isWinner: false,
})
}

return squares;
}

const App = () => {

const [winner, setWinner] = useState(null);
const [squares, setSquares] = useState(generateSquares());
const [numSquaresFilled, setNumSquaresFilled] = useState(0);

// Wave 2
// You will need to create a method to change the square
// When it is clicked on.
// Then pass it into the squares as a callback
const changeSquare = (i) => {

if (squares[i].value || winner) return; //do nothing if square is already filled

const checkForWinner = () => {
// Complete in Wave 3
setNumSquaresFilled(numSquaresFilled + 1);
let updatedSquares = [...squares];
numSquaresFilled % 2 === 0 ? updatedSquares[i].value = PLAYER_1 : updatedSquares[i].value = PLAYER_2

if (numSquaresFilled > 3) {
checkForWinner(i);
};
setSquares(updatedSquares);
}

const checkForWinner = (i) => {
let found = false;
for (let x = 0; x < WIN_CONDITIONS[i].length; x++) {
const [a, b] = WIN_CONDITIONS[i][x];
if ( squares[a].value === squares[b].value && squares[a].value === squares[i].value ) {
setWinner(squares[a].value);
found = true;
[...WIN_CONDITIONS[i][x], i].forEach( index => {
squares[index].isWinner = true;
});
}
}
if (numSquaresFilled === 8 && !found ) setWinner("nobody");
Comment on lines +52 to +64

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very concise!

}

const resetGame = () => {
// Complete in Wave 4
setWinner(null);
setSquares(generateSquares());
setNumSquaresFilled(0);
}

return (
<div className="App">
<header className="App-header">
<h1>React Tic Tac Toe</h1>
<h2>The winner is ... -- Fill in for wave 3 </h2>
<button>Reset Game</button>
<h2>{winner ? `Hooray, ${winner} won!` : `Player ${numSquaresFilled % 2 === 0 ? 'X' : 'O'} is up!`}</h2>

<button onClick={resetGame}>Reset Game</button>
</header>
<main>
<Board squares={squares} />
<Board squares={squares} onClickCallback={changeSquare} />
</main>
</div>
);
Expand Down
15 changes: 10 additions & 5 deletions src/components/Board.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ import './Board.css';
import Square from './Square';
import PropTypes from 'prop-types';


const generateSquareComponents = (squares, onClickCallback) => {
// Complete this for Wave 1

const squareComponents = squares.map(square => <Square
key={square.id}
id={square.id}
value={square.value}
isWinner ={square.isWinner}
onClickCallback={onClickCallback}/> )

return squareComponents;
}

const Board = ({ squares, onClickCallback }) => {
Expand All @@ -19,12 +25,11 @@ const Board = ({ squares, onClickCallback }) => {

Board.propTypes = {
squares: PropTypes.arrayOf(
PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
value: PropTypes.string.isRequired
value: PropTypes.string,
isWinner: PropTypes.bool.isRequired,
})
)
),
onClickCallback: PropTypes.func.isRequired,
};
Expand Down
4 changes: 4 additions & 0 deletions src/components/Square.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@
justify-content: center;
align-items: center;
margin: 2px;
}

.winner {
background-color: aquamarine;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such a fun little things to add! I love it!

}
12 changes: 4 additions & 8 deletions src/components/Square.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@ import PropTypes from 'prop-types';
import './Square.css'

const Square = (props) => {
// For Wave 1 enable this
// Component to alert a parent
// component when it's clicked on.

return <button
className="square"
>
return <button className={`square ${props.isWinner ? "winner" : ""}`} onClick={ () => {props.onClickCallback(props.id)}}>
{props.value}
</button>
</button>
}

Square.propTypes = {
value: PropTypes.string.isRequired,
value: PropTypes.string,
onClickCallback: PropTypes.func.isRequired,
id: PropTypes.number.isRequired,
isWinner: PropTypes.bool.isRequired,
};

export default Square