├── src ├── App.css ├── images │ ├── blank.png │ ├── red-candy.png │ ├── blue-candy.png │ ├── green-candy.png │ ├── orange-candy.png │ ├── purple-candy.png │ └── yellow-candy.png ├── components │ └── ScoreBoard.js ├── index.css ├── index.js └── App.js ├── public ├── favicon.ico ├── manifest.json └── index.html ├── README.md ├── .gitignore └── package.json /src/App.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muratcansahn/candycrushreact/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/images/blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muratcansahn/candycrushreact/HEAD/src/images/blank.png -------------------------------------------------------------------------------- /src/images/red-candy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muratcansahn/candycrushreact/HEAD/src/images/red-candy.png -------------------------------------------------------------------------------- /src/images/blue-candy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muratcansahn/candycrushreact/HEAD/src/images/blue-candy.png -------------------------------------------------------------------------------- /src/images/green-candy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muratcansahn/candycrushreact/HEAD/src/images/green-candy.png -------------------------------------------------------------------------------- /src/images/orange-candy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muratcansahn/candycrushreact/HEAD/src/images/orange-candy.png -------------------------------------------------------------------------------- /src/images/purple-candy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muratcansahn/candycrushreact/HEAD/src/images/purple-candy.png -------------------------------------------------------------------------------- /src/images/yellow-candy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muratcansahn/candycrushreact/HEAD/src/images/yellow-candy.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![image](https://user-images.githubusercontent.com/22106880/148688352-bbb2038b-3994-4626-baf5-362d9429fc5e.png) 3 | Demo Link : 4 | master.d3dup4qtqsqnsb.amplifyapp.com 5 | -------------------------------------------------------------------------------- /src/components/ScoreBoard.js: -------------------------------------------------------------------------------- 1 | const ScoreBoard = ({ score }) => { 2 | return ( 3 |
4 |

SCORE

5 |
6 |

{score}

7 |
8 | ); 9 | }; 10 | 11 | export default ScoreBoard; 12 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | .app { 2 | display: flex; 3 | padding: 30px; 4 | } 5 | 6 | .game { 7 | width: 560px; 8 | height: 560px; 9 | display: flex; 10 | flex-wrap: wrap; 11 | } 12 | 13 | .game img { 14 | width: 70px; 15 | height: 70px; 16 | } 17 | .score-board { 18 | margin-left: 200px; 19 | 20 | text-align: center; 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | 6 | ReactDOM.render( 7 | 8 | 9 | , 10 | document.getElementById("root") 11 | ); 12 | 13 | // If you want to start measuring performance in your app, pass a function 14 | // to log results (for example: reportWebVitals(console.log)) 15 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 16 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "candy-crush", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.1", 7 | "@testing-library/react": "^11.2.7", 8 | "@testing-library/user-event": "^12.8.3", 9 | "react": "^17.0.2", 10 | "react-dom": "^17.0.2", 11 | "react-scripts": "4.0.3", 12 | "web-vitals": "^1.1.2" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import ScoreBoard from "./components/ScoreBoard"; 3 | import blueCandy from "./images/blue-candy.png"; 4 | import greenCandy from "./images/green-candy.png"; 5 | import orangeCandy from "./images/orange-candy.png"; 6 | import purpleCandy from "./images/purple-candy.png"; 7 | import redCandy from "./images/red-candy.png"; 8 | import yellowCandy from "./images/yellow-candy.png"; 9 | import blank from "./images/blank.png"; 10 | 11 | const width = 8; ///width of out board 12 | 13 | ///define candy colors 14 | const candyColors = [ 15 | blueCandy, 16 | orangeCandy, 17 | purpleCandy, 18 | redCandy, 19 | yellowCandy, 20 | greenCandy, 21 | ]; 22 | 23 | const App = () => { 24 | const [currentColorArrangement, setCurrentColorArrangement] = useState([]); 25 | const [squareBeingDragged, setSquareBeingDragged] = useState(null); 26 | const [squareBeingReplaced, setSquareBeingReplaced] = useState(null); 27 | const [scoreDisplay, setScoreDisplay] = useState(0); 28 | 29 | ///check for matches 30 | const checkForColumnOfFour = () => { 31 | for (let i = 0; i <= 39; i++) { 32 | const columnOfFour = [i, i + width, i + width * 2, i + width * 3]; 33 | const decidedColor = currentColorArrangement[i]; 34 | const isBlank = currentColorArrangement[i] === blank; 35 | 36 | if ( 37 | columnOfFour.every( 38 | (square) => 39 | currentColorArrangement[square] === decidedColor && !isBlank 40 | ) 41 | ) { 42 | setScoreDisplay((score) => score + 4); 43 | columnOfFour.forEach( 44 | (square) => (currentColorArrangement[square] = blank) 45 | ); 46 | return true; 47 | } 48 | } 49 | }; 50 | ///check for matches 51 | 52 | const checkForRowOfFour = () => { 53 | for (let i = 0; i < 64; i++) { 54 | const rowOfFour = [i, i + 1, i + 2, i + 3]; 55 | const decidedColor = currentColorArrangement[i]; 56 | const notValid = [ 57 | 5, 6, 7, 13, 14, 15, 21, 22, 23, 29, 30, 31, 37, 38, 39, 45, 46, 47, 53, 58 | 54, 55, 62, 63, 64, 59 | ]; 60 | const isBlank = currentColorArrangement[i] === blank; 61 | 62 | if (notValid.includes(i)) continue; 63 | 64 | if ( 65 | rowOfFour.every( 66 | (square) => 67 | currentColorArrangement[square] === decidedColor && !isBlank 68 | ) 69 | ) { 70 | setScoreDisplay((score) => score + 4); 71 | rowOfFour.forEach( 72 | (square) => (currentColorArrangement[square] = blank) 73 | ); 74 | return true; 75 | } 76 | } 77 | }; 78 | ///check for matches 79 | 80 | const checkForColumnOfThree = () => { 81 | for (let i = 0; i <= 47; i++) { 82 | const columnOfThree = [i, i + width, i + width * 2]; 83 | const decidedColor = currentColorArrangement[i]; 84 | const isBlank = currentColorArrangement[i] === blank; 85 | 86 | if ( 87 | columnOfThree.every( 88 | (square) => 89 | currentColorArrangement[square] === decidedColor && !isBlank 90 | ) 91 | ) { 92 | setScoreDisplay((score) => score + 3); 93 | columnOfThree.forEach( 94 | (square) => (currentColorArrangement[square] = blank) 95 | ); 96 | return true; 97 | } 98 | } 99 | }; 100 | ///check for matches 101 | 102 | const checkForRowOfThree = () => { 103 | for (let i = 0; i < 64; i++) { 104 | const rowOfThree = [i, i + 1, i + 2]; 105 | const decidedColor = currentColorArrangement[i]; 106 | const notValid = [ 107 | 6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 63, 64, 108 | ]; 109 | const isBlank = currentColorArrangement[i] === blank; 110 | 111 | if (notValid.includes(i)) continue; 112 | 113 | if ( 114 | rowOfThree.every( 115 | (square) => 116 | currentColorArrangement[square] === decidedColor && !isBlank 117 | ) 118 | ) { 119 | setScoreDisplay((score) => score + 3); 120 | rowOfThree.forEach( 121 | (square) => (currentColorArrangement[square] = blank) 122 | ); 123 | return true; 124 | } 125 | } 126 | }; 127 | 128 | ///moving candies down after matches 129 | const moveIntoSquareBelow = () => { 130 | for (let i = 0; i <= 55; i++) { 131 | const firstRow = [0, 1, 2, 3, 4, 5, 6, 7]; 132 | const isFirstRow = firstRow.includes(i); 133 | 134 | if (isFirstRow && currentColorArrangement[i] === blank) { 135 | let randomNumber = Math.floor(Math.random() * candyColors.length); 136 | currentColorArrangement[i] = candyColors[randomNumber]; 137 | } 138 | 139 | if (currentColorArrangement[i + width] === blank) { 140 | currentColorArrangement[i + width] = currentColorArrangement[i]; 141 | currentColorArrangement[i] = blank; 142 | } 143 | } 144 | }; 145 | 146 | ///drag candies 147 | const dragStart = (e) => { 148 | setSquareBeingDragged(e.target); 149 | }; 150 | const dragDrop = (e) => { 151 | setSquareBeingReplaced(e.target); 152 | }; 153 | const dragEnd = () => { 154 | const squareBeingDraggedId = parseInt( 155 | squareBeingDragged.getAttribute("data-id") 156 | ); 157 | const squareBeingReplacedId = parseInt( 158 | squareBeingReplaced.getAttribute("data-id") 159 | ); 160 | 161 | currentColorArrangement[squareBeingReplacedId] = 162 | squareBeingDragged.getAttribute("src"); 163 | currentColorArrangement[squareBeingDraggedId] = 164 | squareBeingReplaced.getAttribute("src"); 165 | 166 | const validMoves = [ 167 | squareBeingDraggedId - 1, 168 | squareBeingDraggedId - width, 169 | squareBeingDraggedId + 1, 170 | squareBeingDraggedId + width, 171 | ]; 172 | 173 | const validMove = validMoves.includes(squareBeingReplacedId); 174 | 175 | const isAColumnOfFour = checkForColumnOfFour(); 176 | const isARowOfFour = checkForRowOfFour(); 177 | const isAColumnOfThree = checkForColumnOfThree(); 178 | const isARowOfThree = checkForRowOfThree(); 179 | 180 | if ( 181 | squareBeingReplacedId && 182 | validMove && 183 | (isARowOfThree || isARowOfFour || isAColumnOfFour || isAColumnOfThree) 184 | ) { 185 | setSquareBeingDragged(null); 186 | setSquareBeingReplaced(null); 187 | } else { 188 | currentColorArrangement[squareBeingReplacedId] = 189 | squareBeingReplaced.getAttribute("src"); 190 | currentColorArrangement[squareBeingDraggedId] = 191 | squareBeingDragged.getAttribute("src"); 192 | setCurrentColorArrangement([...currentColorArrangement]); 193 | } 194 | }; 195 | 196 | const createBoard = () => { 197 | const randomColorArrangement = []; 198 | 199 | ///fill board with random candies 200 | for (let i = 0; i < width * width; i++) { 201 | const randomColor = 202 | candyColors[Math.floor(Math.random() * candyColors.length)]; 203 | randomColorArrangement.push(randomColor); 204 | } 205 | setCurrentColorArrangement(randomColorArrangement); 206 | }; 207 | 208 | useEffect(() => { 209 | createBoard(); 210 | }, []); 211 | 212 | ///check for matches every 100 ms 213 | useEffect(() => { 214 | const timer = setInterval(() => { 215 | checkForColumnOfFour(); 216 | checkForRowOfFour(); 217 | checkForColumnOfThree(); 218 | checkForRowOfThree(); 219 | moveIntoSquareBelow(); 220 | setCurrentColorArrangement([...currentColorArrangement]); 221 | }, 100); 222 | return () => clearInterval(timer); 223 | }, [ 224 | checkForColumnOfFour, 225 | checkForRowOfFour, 226 | checkForColumnOfThree, 227 | checkForRowOfThree, 228 | moveIntoSquareBelow, 229 | currentColorArrangement, 230 | ]); 231 | 232 | return ( 233 |
234 |
235 | {currentColorArrangement.map((candyColor, index) => ( 236 | {candyColor} e.preventDefault()} 244 | onDragEnter={(e) => e.preventDefault()} 245 | onDragLeave={(e) => e.preventDefault()} 246 | onDrop={dragDrop} 247 | onDragEnd={dragEnd} 248 | /> 249 | ))} 250 |
251 | 252 |
253 | ); 254 | }; 255 | 256 | export default App; 257 | --------------------------------------------------------------------------------