Skip to content

Alf - Spruce #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5cb7505
generates the board and solution for checkForWinners
spitsfire Dec 13, 2021
c487dca
pulls updated eslintrc file
spitsfire Dec 13, 2021
5c65394
fixes semicolon warnings
spitsfire Dec 14, 2021
7e58837
adds list of features that differ from original project
spitsfire Dec 14, 2021
2cb6cfd
changes const variable casing to match test
spitsfire Dec 14, 2021
90b2bda
removes jest from eslinter
spitsfire Dec 15, 2021
b801f04
added two methods to app, 'isX' that updates the game state to reflec…
asliathman Jan 4, 2022
55b5361
added wrapper function to square component to pass the id of the clic…
asliathman Jan 4, 2022
b760be7
trying to debugg why onclickcallback() is not working
asliathman Jan 4, 2022
7f21315
changed the logic of isX and current player in app
asliathman Jan 4, 2022
340c966
fixed bug LOL git add .git add . on line 42 of app.js i wrote col == …
asliathman Jan 4, 2022
d1d6eaf
finished wave 2 and added reset game logic, and onClick to the reset …
asliathman Jan 4, 2022
4ca200c
implemented the check for winner function to change the winner messag…
asliathman Jan 4, 2022
bf935fe
added a variable 'headerMessage' that dispalys a different header mes…
asliathman Jan 4, 2022
76d8f2d
fixed spacing
asliathman Jan 4, 2022
58a2142
changed capitalization of 'x' to see if it would affect test results
asliathman Jan 4, 2022
08f20c1
changed capitalization of 'o' to see if it would affect test results
asliathman Jan 4, 2022
8c165b3
changed wording of win message for tests
asliathman Jan 4, 2022
7bfb57d
changed wording of win message for tests
asliathman Jan 4, 2022
b89c029
added colorful hovers for the squares
asliathman Jan 4, 2022
51857d7
?
asliathman Jan 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"plugin:react/recommended",
"plugin:jsx-a11y/recommended",
"plugin:react-hooks/recommended",
"plugin:jest/recommended",
"plugin:testing-library/react"
],
"parserOptions": {
Expand Down
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# React Tic-Tac-Toe

## Please Read First!

The digital campus' version of Tic-Tac-Toe differs from the original in the following ways:
- We will *not* be using `main` branch. Follow step 6 in the **One-Time Project Setup** to change branches.
- Wave 1 has been completed for you; however, it would help you understand the flow of data by reviewing the code written for Wave 1.
- Wave 3's `checkForWinner` function has been created for you; however, read through Wave 3 instructions to figure out how and where to use it.

## Skills Assessed

- Following directions and reading comprehension
Expand Down Expand Up @@ -81,9 +88,15 @@ We can run `yarn install` multiple times safely, but we only need to do this onc

The file `package.json` contains details about our project, the scripts available, and the dependencies needed. We can inspect this file when we are curious about the details of our dependencies.

6. Follow the directions in the "Getting Started" section.
6. We will not being using `main` branch. Make sure you are working from `digital-starter` by running:

```bash
$ git checkout digital-starter
```

7. Follow the directions in the "Getting Started" section.

7. Follow the directions in the "Project Requirements" section.
8. Follow the directions in the "Project Requirements" section.

## Project Development Workflow

Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
"react-app"
]
},
"browserslist": {
Expand Down
23 changes: 17 additions & 6 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,25 @@
}

.App-header {
background-color: #282c34;
min-height: 10vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
margin-bottom: 2em;
justify-content: space-evenly;
margin: 20px 0;
padding: 10px 0;
}

h1 {
font-size: 3rem;
color: black;
font-family: Arial, Helvetica, sans-serif;
font-style: bold;
margin: 5px 0px;
}

h2 {
font-size: 1.25em;
margin: 5px 0px;
padding-bottom: 7px;
}

92 changes: 70 additions & 22 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import './App.css';

import Board from './components/Board';

const PLAYER_1 = 'X';
const PLAYER_2 = 'O';
const player1 = 'X';
const player2 = 'O';
Comment on lines +6 to +7

Choose a reason for hiding this comment

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

Annoyingly enough, our tests look for lowercase 'x' and 'o', which was our fault in not updating our tests.

This was the reason why it appeared you failed tests, despite your project working as expected.


const generateSquares = () => {
const squares = [];
Expand All @@ -30,36 +30,84 @@ const App = () => {
// empty value and unique ids.
const [squares, setSquares] = useState(generateSquares());

// 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 [isX, setIsX] = useState(false);

const currentPlayer = !isX ? player1 : player2;

Choose a reason for hiding this comment

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

Nice ternary!


const updateSquare = (id) => {
let newSquares = [];

for (let row = 0; row < 3; row += 1) {
newSquares.push([]);
for (let col = 0; col < 3; col += 1) {
if (id === squares[row][col].id) {
if (!squares[row][col].value) {
squares[row][col].value = currentPlayer;
setIsX(!isX);
}
}
newSquares[row].push(squares[row][col]);
}
}
setSquares(newSquares);
};
Comment on lines +38 to +53

Choose a reason for hiding this comment

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

Great job in making a copy of the squares data! Here's a reminder on why we need to make the copy:

To trigger the update stage for this component, React needs to notice a change in state data. We could mutate state directly, however, this doesn't scale well and doesn't follow React best practices.

Instead, we should pass in a copy of our state data to the setState function setSquares() which will have React compare the object references between the copy and the old state data. If the object references are different, React will then trigger the update stage.

Choose a reason for hiding this comment

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

Rather than creating an empty list and pushing values into it with every iteration, we can make a shallow copy with the ... spread operator:

Suggested change
let newSquares = [];
for (let row = 0; row < 3; row += 1) {
newSquares.push([]);
for (let col = 0; col < 3; col += 1) {
if (id === squares[row][col].id) {
if (!squares[row][col].value) {
squares[row][col].value = currentPlayer;
setIsX(!isX);
}
}
newSquares[row].push(squares[row][col]);
}
}
setSquares(newSquares);
};
let newSquares = [...squares];
for (let row = 0; row < 3; row += 1) {
for (let col = 0; col < 3; col += 1) {
if (id === squares[row][col].id && !squares[row][col].value) {
squares[row][col].value = currentPlayer;
setIsX(!isX);
}
}
}
setSquares(newSquares);
};

Choose a reason for hiding this comment

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

I've also combined the conditional to reduce how nested this section of code looks.


const checkForWinner = () => {
// Complete in Wave 3
// You will need to:
// 1. Go accross each row to see if
// 3 squares in the same row match
// i.e. same value
// 2. Go down each column to see if
// 3 squares in each column match
// 3. Go across each diagonal to see if
// all three squares have the same value.
let i = 0;

// Check all the rows and columns for a winner
while (i < 3) {
if (
squares[i][0].value === squares[i][1].value &&
squares[i][2].value === squares[i][1].value &&
squares[i][0].value !== ''
) {
return squares[i][0].value;
} else if (
squares[0][i].value === squares[1][i].value &&
squares[2][i].value === squares[1][i].value &&
squares[0][i].value !== ''
) {
return squares[0][i].value;
}
i += 1;
}
// Check Top-Left to bottom-right diagonal
if (
squares[0][0].value === squares[1][1].value &&
squares[2][2].value === squares[1][1].value &&
squares[1][1].value !== ''
) {
return squares[0][0].value;
}

// Check Top-right to bottom-left diagonal
if (
squares[0][2].value === squares[1][1].value &&
squares[2][0].value === squares[1][1].value &&
squares[1][1].value !== ''
) {
return squares[0][2].value;
}

return null;
};

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

const headerMessage = checkForWinner() ? `The winner is ${checkForWinner()}!!!` : `Current player: ${currentPlayer}`;

Choose a reason for hiding this comment

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

Great ternary!


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>
<div className='App'>
<header className='App-header'>
<h1>TIC-TAC-TOE</h1>
<h2>{headerMessage}</h2>
<button onClick={resetGame}>reset</button>
</header>
<main>
<Board squares={squares} />
<Board squares={squares} onClickCallback={checkForWinner() ? () => {} : updateSquare} />

Choose a reason for hiding this comment

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

Clever use of a ternary operator to change the functionality of the click.

</main>
</div>
);
Expand Down
8 changes: 4 additions & 4 deletions src/components/Board.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
div.grid {
width: 600px;
height: 600px;
width: 500px;
height: 500px;
margin: 0 auto;
background-color: #34495e;
background-color: rgb(219, 219, 219);
color: #fff;
border: 6px solid #2c3e50;
border: 3px solid black;
border-radius: 10px;
display: grid;
grid-template: repeat(3, 1fr) / repeat(3, 1fr);
Expand Down
28 changes: 16 additions & 12 deletions src/components/Board.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,33 @@ import './Board.css';
import Square from './Square';
import PropTypes from 'prop-types';


// This turns the 2D array into a 1D array
const generateSquareComponents = (squares, onClickCallback) => {
// Complete this for Wave 1
// squares is a 2D Array, but
// you need to return a 1D array
// of square components

}
const singleArraySquares = [].concat(...squares);
return singleArraySquares.map((square) => {
return (
<Square
value={square.value}
id={square.id}
onClickCallback={onClickCallback}
key={square.id}
/>
);
});
};

const Board = ({ squares, onClickCallback }) => {
const squareList = generateSquareComponents(squares, onClickCallback);
console.log(squareList);

Choose a reason for hiding this comment

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

Generally, we should remove all console logs and print statements when submitting code for review. And our team should definitely take that advice as well, I believe this was meant to be removed before shipping to y'all.

Suggested change
console.log(squareList);

return <div className="grid" >
{squareList}
</div>
}
return <div className='grid'>{squareList}</div>;
};

Board.propTypes = {
squares: PropTypes.arrayOf(
PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
value: PropTypes.string.isRequired
value: PropTypes.string.isRequired,
})
)
),
Expand Down
29 changes: 25 additions & 4 deletions src/components/Square.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
.square
{
border: 4px solid #2c3e50;
border: 3px solid black;

Choose a reason for hiding this comment

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

LOVE the css hover effects! The overall color palette is super cute and portfolio ready ✨

border-radius: 2px;
font-family: Helvetica;
font-weight: bold;
font-size: 8em;
font-size: 5em;
display: flex;
justify-content: center;
align-items: center;
margin: 2px;
}
margin: 3px;
color: black;
}

#blue:hover {
background-color: rgb(186, 240, 253);
}

#pink:hover {
background-color: rgb(255, 196, 250);
}

#yellow:hover {
background-color: rgb(246, 255, 166);
}

#green:hover {
background-color: rgb(150, 248, 188);
}

#orange:hover {
background-color: rgb(255, 150, 112);
}
30 changes: 20 additions & 10 deletions src/components/Square.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';

import './Square.css'
import './Square.css';

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

if (props.id === 0 || props.id === 5) {
color = 'blue';
} else if (props.id === 1 || props.id === 6) {
color = 'yellow';
} else if (props.id === 2 || props.id === 7) {
color = 'green';
} else if (props.id === 3 || props.id === 8) {
color = 'pink';
} else if (props.id === 4) {
color = 'orange';
}
Comment on lines +9 to +19

Choose a reason for hiding this comment

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

Great use of the || or operator to determine the color of the hover effects!


return <button
className="square"
>
{props.value}
</button>
}
const selectedSquare = () => {
props.onClickCallback(props.id);
};

return <button className='square' id={color} onClick={selectedSquare}>{props.value}</button>;
};

Square.propTypes = {
value: PropTypes.string.isRequired,
Expand Down
Loading