-
-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add tic-tac-toe React prototype (#665)
* add prototype * remove old folders * update prototype and user stories * format code * update user stories Co-authored-by: Jessica Wilkins <[email protected]> * update code * remove extra stories * Update fullstack-cert/react-projects/tic-tac-toe/user-stories.md --------- Co-authored-by: Jessica Wilkins <[email protected]>
- Loading branch information
Showing
4 changed files
with
156 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Tic-Tac-Toe</title> | ||
<script src="https://unpkg.com/react@18/umd/react.development.js"></script> | ||
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> | ||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> | ||
<script data-plugins="transform-modules-umd" type="text/babel" src="index.jsx"></script> | ||
<link rel="stylesheet" href="styles.css" /> | ||
</head> | ||
|
||
<body> | ||
<div id="root"></div> | ||
<script data-plugins="transform-modules-umd" type="text/babel" data-presets="react" data-type="module"> | ||
import { Board } from './index.jsx'; | ||
ReactDOM.createRoot(document.getElementById('root')).render(<Board />); | ||
</script> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
const Square = ({ value, onClick }) => { | ||
return ( | ||
<button className="square" onClick={onClick}> | ||
{value} | ||
</button> | ||
); | ||
}; | ||
|
||
const calculateWinner = (squares) => { | ||
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; | ||
}; | ||
|
||
const Board = () => { | ||
const [squares, setSquares] = React.useState(Array(9).fill(null)); | ||
const [isXNext, setIsXNext] = React.useState(true); | ||
const winner = calculateWinner(squares); | ||
const isDraw = squares.every(square => square !== null) && !winner; | ||
|
||
const handleClick = (index) => { | ||
if (squares[index] || winner || isDraw) return; | ||
const nextSquares = squares.slice(); | ||
nextSquares[index] = isXNext ? 'X' : 'O'; | ||
setSquares(nextSquares); | ||
setIsXNext(!isXNext); | ||
}; | ||
|
||
const resetGame = () => { | ||
setSquares(Array(9).fill(null)); | ||
setIsXNext(true); | ||
}; | ||
|
||
const renderSquare = (index) => { | ||
return <Square value={squares[index]} onClick={() => handleClick(index)} />; | ||
}; | ||
|
||
return ( | ||
<div className="board"> | ||
<h1>Tic-Tac-Toe</h1> | ||
<div className="status"> | ||
{winner ? `Winner: ${winner}` : isDraw ? "It's a Draw!" : `Next Player: ${isXNext ? 'X' : 'O'}`} | ||
</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> | ||
<button className="reset-button" onClick={resetGame}>Reset Game</button> | ||
</div> | ||
); | ||
}; | ||
|
||
export { Board }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
* { | ||
font-family: "Secular One", sans-serif; | ||
font-weight: 400; | ||
font-style: normal; | ||
} | ||
.App { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
height: 100vh; | ||
} | ||
|
||
.board { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
} | ||
|
||
.status { | ||
margin: 10px; | ||
font-size: 1.2em; | ||
} | ||
|
||
.board-row { | ||
display: flex; | ||
} | ||
|
||
.square { | ||
width: 60px; | ||
height: 60px; | ||
font-size: 1.5em; | ||
margin: 5px; | ||
background: #fff; | ||
border: 1px solid #999; | ||
cursor: pointer; | ||
border-radius: 5px; | ||
} | ||
|
||
.square:focus { | ||
outline: none; | ||
} | ||
|
||
.reset-button { | ||
margin-top: 20px; | ||
padding: 10px 20px; | ||
font-size: 1em; | ||
cursor: pointer; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
1. You should create a `Square` component that accepts two props: `value` and `onClick`. | ||
2. Your `Square` component should return a `button` element with the class `square`. | ||
3. The `button` element should display the `value` prop inside it. | ||
4. The `Square` component should trigger the `onClick` function when the button is clicked. | ||
5. You should create a `calculateWinner` function that accepts an array `squares` as a parameter and returns the winner if there is one. | ||
6. Your `calculateWinner` function should check for winning lines using an array of indices for rows, columns, and diagonals, and return the value of the winner (`X` or `O`) if there is a match. | ||
7. You should create and export a `Board` component. | ||
8. Your `Board` component should use React's `useState` hook to keep track of the game state, including the `squares` array and whether it is player `X` or `O` turn. | ||
9. Your `Board` component should call the `calculateWinner` function to check if there's a winner after each move. | ||
10. Your `Board` component should render a status message that shows the current player or the winner, or indicate if there is a draw. | ||
11. Your `Board` component should render a grid of `Square` components for the 3x3 Tic-Tac-Toe board. | ||
12. You should create a `resetGame` function that resets the game state to its initial values when triggered. |