diff --git a/package-lock.json b/package-lock.json index f8b2902..5e68c7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,11 @@ "gh-pages": "^3.2.3", "react": "^18.1.0", "react-dom": "^18.1.0", - "react-scripts": "5.0.1" + "react-icons": "^4.11.0", + "react-router-dom": "^6.15.0", + "react-scripts": "5.0.1", + "sass": "^1.66.1", + "sass-loader": "^13.3.2" } }, "node_modules/@ampproject/remapping": { @@ -2867,6 +2871,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz", + "integrity": "sha512-mrfKqIHnSZRyIzBcanNJmVQELTnX+qagEDlcKO90RgRBVOZGSGvZKeDihTRfWcqoDn5N/NkUcwWTccnpN18Tfg==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -8095,6 +8107,11 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -13245,6 +13262,14 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-icons": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.11.0.tgz", + "integrity": "sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -13258,6 +13283,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.15.0.tgz", + "integrity": "sha512-NIytlzvzLwJkCQj2HLefmeakxxWHWAP+02EGqWEZy+DgfHHKQMUoBBjUQLOtFInBMhWtb3hiUy6MfFgwLjXhqg==", + "dependencies": { + "@remix-run/router": "1.8.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.15.0.tgz", + "integrity": "sha512-aR42t0fs7brintwBGAv2+mGlCtgtFQeOzK0BM1/OiqEzRejOZtpMZepvgkscpMUnKb8YO84G7s3LsHnnDNonbQ==", + "dependencies": { + "@remix-run/router": "1.8.0", + "react-router": "6.15.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -13330,6 +13385,43 @@ } } }, + "node_modules/react-scripts/node_modules/sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, "node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -13753,16 +13845,31 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, + "node_modules/sass": { + "version": "1.66.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.66.1.tgz", + "integrity": "sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/sass-loader": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", - "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", + "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", "dependencies": { - "klona": "^2.0.4", "neo-async": "^2.6.2" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 14.15.0" }, "funding": { "type": "opencollective", @@ -13770,7 +13877,7 @@ }, "peerDependencies": { "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", "sass": "^1.3.0", "sass-embedded": "*", "webpack": "^5.0.0" @@ -17978,6 +18085,11 @@ "source-map": "^0.7.3" } }, + "@remix-run/router": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz", + "integrity": "sha512-mrfKqIHnSZRyIzBcanNJmVQELTnX+qagEDlcKO90RgRBVOZGSGvZKeDihTRfWcqoDn5N/NkUcwWTccnpN18Tfg==" + }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -21798,6 +21910,11 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==" }, + "immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -25384,6 +25501,12 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "react-icons": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.11.0.tgz", + "integrity": "sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==", + "requires": {} + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -25394,6 +25517,23 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" }, + "react-router": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.15.0.tgz", + "integrity": "sha512-NIytlzvzLwJkCQj2HLefmeakxxWHWAP+02EGqWEZy+DgfHHKQMUoBBjUQLOtFInBMhWtb3hiUy6MfFgwLjXhqg==", + "requires": { + "@remix-run/router": "1.8.0" + } + }, + "react-router-dom": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.15.0.tgz", + "integrity": "sha512-aR42t0fs7brintwBGAv2+mGlCtgtFQeOzK0BM1/OiqEzRejOZtpMZepvgkscpMUnKb8YO84G7s3LsHnnDNonbQ==", + "requires": { + "@remix-run/router": "1.8.0", + "react-router": "6.15.0" + } + }, "react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -25447,6 +25587,17 @@ "webpack-dev-server": "^4.6.0", "webpack-manifest-plugin": "^4.0.2", "workbox-webpack-plugin": "^6.4.1" + }, + "dependencies": { + "sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + } } }, "readable-stream": { @@ -25750,12 +25901,21 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, + "sass": { + "version": "1.66.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.66.1.tgz", + "integrity": "sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==", + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, "sass-loader": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", - "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", + "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", "requires": { - "klona": "^2.0.4", "neo-async": "^2.6.2" } }, diff --git a/package.json b/package.json index 9e1db91..c179594 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,11 @@ "gh-pages": "^3.2.3", "react": "^18.1.0", "react-dom": "^18.1.0", - "react-scripts": "5.0.1" + "react-icons": "^4.11.0", + "react-router-dom": "^6.15.0", + "react-scripts": "5.0.1", + "sass": "^1.66.1", + "sass-loader": "^13.3.2" }, "scripts": { "predeploy": "npm run build", diff --git a/src/App.css b/src/App.css index 97b7c57..7264b01 100644 --- a/src/App.css +++ b/src/App.css @@ -14,6 +14,17 @@ flex-direction: column; align-items: center; justify-content: center; - font-size: calc(10px + 2vmin); color: white; } + +.cardDesign { + display: flex; +} + +.flex-child { + flex: 1; +} + +.flex-child:first-child { + margin-right: 20px; +} \ No newline at end of file diff --git a/src/App.js b/src/App.js index 899cefc..fa4dfd3 100644 --- a/src/App.js +++ b/src/App.js @@ -1,6 +1,7 @@ import React from "react"; import "./App.css"; import { makeShuffledDeck } from "./utils.js"; +import PlayingCard from './Components/playingCard'; class App extends React.Component { constructor(props) { @@ -11,14 +12,88 @@ class App extends React.Component { cardDeck: makeShuffledDeck(), // currCards holds the cards from the current round currCards: [], + winnerRound: null, + playerOneWins: 0, + playerTwoWins: 0, + finalWinner: null, + numRounds: 52 / 2, //is there a way not to hardcode this? + line 132 + line 112 + gameInProgress: false, + playerOneTotalWins: 0, + playerTwoTotalWins: 0 }; } dealCards = () => { // this.state.cardDeck.pop() modifies this.state.cardDeck array const newCurrCards = [this.state.cardDeck.pop(), this.state.cardDeck.pop()]; + console.log(newCurrCards); + console.log(this.state.cardDeck.length); this.setState({ currCards: newCurrCards, + numRounds: this.state.numRounds - 1, + }); + if (newCurrCards[0].rank > newCurrCards[1].rank) { + this.setState({ + winnerRound: "Player 1", + playerOneWins: this.state.playerOneWins + 1, + }); + } else { + this.setState({ + winnerRound: "Player 2", + playerTwoWins: this.state.playerTwoWins + 1, + }); + } + if (this.state.cardDeck.length === 0) { + this.determineWinner(); + } + }; + + determineWinner = () => { + console.log("hello"); + if (this.state.cardDeck.length === 0) { + if (this.state.playerOneWins > this.state.playerTwoWins) { + this.setState({ + finalWinner: "Player 1", + playerOneTotalWins: this.state.playerOneTotalWins + 1 + }); + } else if (this.state.playerOneWins < this.state.playerTwoWins) { + this.setState({ + finalWinner: "Player 2", + playerTwoTotalWins: this.state.playerTwoTotalWins + 1, + }); + } else { + this.setState({ + finalWinner: "It's a tie!", + playerOneTotalWins: this.state.playerOneTotalWins + 1, + playerTwoTotalWins: this.state.playerTwoTotalWins + 1, + }); + } + } + }; + + restart = () => { + this.setState({ + // Set default value of card deck to new shuffled deck + cardDeck: makeShuffledDeck(), + // currCards holds the cards from the current round + currCards: [], + winnerRound: null, + playerOneWins: 0, + playerTwoWins: 0, + finalWinner: null, + numRounds: 52 / 2, + }); + }; + + handleClickDeal = () => { + this.setState({ + gameInProgress: true, + }); + }; + + handleClickRestart = () => { + this.setState({ + gameInProgress: false, }); }; @@ -29,17 +104,76 @@ class App extends React.Component { const currCardElems = this.state.currCards.map(({ name, suit }) => ( // Give each list element a unique key
- {name} of {suit} +
)); + + const playerOneOverallScore = `Player 1 Overall Score: ${this.state.playerOneTotalWins}` + const playerTwoOverallScore = `Player 2 Overall Score: ${this.state.playerTwoTotalWins}`; + + const winnerMessage = this.state.winnerRound + ? `${this.state.winnerRound} has won!` + : `Game starting...`; + const playerOneScore = `Player 1 Score Count: ${this.state.playerOneWins}`; + const playerTwoScore = `Player 2 Score Count: ${this.state.playerTwoWins}`; + const finalMessage = + this.state.finalWinner && this.state.cardDeck.length === 0 && this.state.finalWinner !== "It's a tie!" + ? `${this.state.finalWinner} is the ultimate winner!` + : (this.state.finalWinner === "It's a tie!" ? "It's a tie!" : ""); + const displayButton = + this.state.cardDeck.length === 0 ? ( + + ) : ( + + ); + const numRounds = `There are ${this.state.numRounds} rounds left in this game`; + const displayText = this.state.gameInProgress ? ( +
+
+
Player 1: {currCardElems[0]}
+
Player 2: {currCardElems[1]}
+
+
+ {winnerMessage} +
+ {playerOneScore} +
+ {playerTwoScore} +
+ {numRounds} +
+
+ ) : ( + "" + ); return (

High Card 🚀

- {currCardElems} + {displayButton} +
+ {displayText} +
{finalMessage}
+
+
{playerOneOverallScore}
+
+
{playerTwoOverallScore}

-
); diff --git a/src/Components/playingCard.js b/src/Components/playingCard.js new file mode 100644 index 0000000..68419f6 --- /dev/null +++ b/src/Components/playingCard.js @@ -0,0 +1,233 @@ +// Code has been adapted from https://bernieslearnings.com/creating-a-component-in-react/ + +import { useState, useEffect, useRef } from "react"; +import { + BsFillSuitHeartFill, + BsFillSuitClubFill, + BsFillSuitSpadeFill, + BsFillSuitDiamondFill, +} from "react-icons/bs"; +import { GiCardJoker } from "react-icons/gi"; +// import CardBack from "../images/card-back.jpeg"; + +function SuitIcon({ suit, style }) { + if (suit === "Hearts") { + return ; + } else if (suit === "Diamonds") { + return ; + } else if (suit === "Spades") { + return ; + } else if (suit === "Clubs") { + return ; + } else { + // If no suit is given then we can just put out little joker faces + return ; + } +} + +function PlayingCard({ suit, value }) { + const myRef = useRef(null); + const iconSize = "40px"; + const [suitColor, setSuitColor] = useState("red"); + + function flipCard() { + if (myRef.current.style.transform) { + myRef.current.style.transform = ""; + } else { + myRef.current.style.transform = "rotateY(180deg)"; + } + } + + useEffect(() => { + suit === "Hearts" || suit === "Diamonds" + ? setSuitColor("red") + : setSuitColor("black"); + }, [suit]); + + return ( +
+
+

+ {value} +

+ + + + + + + + + +

+ {value} +

+ + + + + + + + + +
+ +
+
+ ); +} + +export default PlayingCard; diff --git a/src/images/card-back.jpeg b/src/images/card-back.jpeg new file mode 100644 index 0000000..cb03b84 Binary files /dev/null and b/src/images/card-back.jpeg differ diff --git a/src/index.css b/src/index.css index 4a1df4d..19566d8 100644 --- a/src/index.css +++ b/src/index.css @@ -11,3 +11,12 @@ code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } + +.overallScore { + color:blueviolet; +} + +.winnerMessage { + font-size: larger; + color:blue; +} \ No newline at end of file