@@ -3,11 +3,23 @@ document.addEventListener("DOMContentLoaded", () => {
33} ) ;
44
55function candyCrushGame ( ) {
6+ // DOM Elements
67 const grid = document . querySelector ( ".grid" ) ;
78 const scoreDisplay = document . getElementById ( "score" ) ;
9+ const timerDisplay = document . getElementById ( "timer" ) ;
10+ const modeSelection = document . getElementById ( "modeSelection" ) ;
11+ const endlessButton = document . getElementById ( "endlessMode" ) ;
12+ const timedButton = document . getElementById ( "timedMode" ) ;
13+ const changeModeButton = document . getElementById ( "changeMode" ) ;
14+
15+ // Game State Variables
816 const width = 8 ;
917 const squares = [ ] ;
1018 let score = 0 ;
19+ let currentMode = null ;
20+ let timeLeft = 0 ;
21+ let gameInterval = null ;
22+ let timerInterval = null ;
1123
1224 const candyColors = [
1325 "url(https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/red-candy.png)" ,
@@ -18,8 +30,10 @@ function candyCrushGame() {
1830 "url(https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/purple-candy.png)" ,
1931 ] ;
2032
21- // Creating Game Board
33+ // Create the Game Board
2234 function createBoard ( ) {
35+ grid . innerHTML = "" ; // Clear existing grid
36+ squares . length = 0 ; // Clear squares array
2337 for ( let i = 0 ; i < width * width ; i ++ ) {
2438 const square = document . createElement ( "div" ) ;
2539 square . setAttribute ( "draggable" , true ) ;
@@ -29,32 +43,21 @@ function candyCrushGame() {
2943 grid . appendChild ( square ) ;
3044 squares . push ( square ) ;
3145 }
46+ // Add drag event listeners
47+ squares . forEach ( square => square . addEventListener ( "dragstart" , dragStart ) ) ;
48+ squares . forEach ( square => square . addEventListener ( "dragend" , dragEnd ) ) ;
49+ squares . forEach ( square => square . addEventListener ( "dragover" , dragOver ) ) ;
50+ squares . forEach ( square => square . addEventListener ( "dragenter" , dragEnter ) ) ;
51+ squares . forEach ( square => square . addEventListener ( "dragleave" , dragLeave ) ) ;
52+ squares . forEach ( square => square . addEventListener ( "drop" , dragDrop ) ) ;
3253 }
33- createBoard ( ) ;
34-
35- // Dragging the Candy
36- let colorBeingDragged ;
37- let colorBeingReplaced ;
38- let squareIdBeingDragged ;
39- let squareIdBeingReplaced ;
4054
41- squares . forEach ( ( square ) =>
42- square . addEventListener ( "dragstart" , dragStart )
43- ) ;
44- squares . forEach ( ( square ) => square . addEventListener ( "dragend" , dragEnd ) ) ;
45- squares . forEach ( ( square ) => square . addEventListener ( "dragover" , dragOver ) ) ;
46- squares . forEach ( ( square ) =>
47- square . addEventListener ( "dragenter" , dragEnter )
48- ) ;
49- squares . forEach ( ( square ) =>
50- square . addEventListener ( "drageleave" , dragLeave )
51- ) ;
52- squares . forEach ( ( square ) => square . addEventListener ( "drop" , dragDrop ) ) ;
55+ // Drag and Drop Functions
56+ let colorBeingDragged , colorBeingReplaced , squareIdBeingDragged , squareIdBeingReplaced ;
5357
5458 function dragStart ( ) {
5559 colorBeingDragged = this . style . backgroundImage ;
5660 squareIdBeingDragged = parseInt ( this . id ) ;
57- // this.style.backgroundImage = ''
5861 }
5962
6063 function dragOver ( e ) {
@@ -66,20 +69,18 @@ function candyCrushGame() {
6669 }
6770
6871 function dragLeave ( ) {
69- this . style . backgroundImage = "" ;
72+ // No action needed
7073 }
7174
7275 function dragDrop ( ) {
7376 colorBeingReplaced = this . style . backgroundImage ;
7477 squareIdBeingReplaced = parseInt ( this . id ) ;
7578 this . style . backgroundImage = colorBeingDragged ;
76- squares [
77- squareIdBeingDragged
78- ] . style . backgroundImage = colorBeingReplaced ;
79+ squares [ squareIdBeingDragged ] . style . backgroundImage = colorBeingReplaced ;
7980 }
8081
8182 function dragEnd ( ) {
82- //Defining, What is a valid move?
83+ // Define valid moves (adjacent squares: left, up, right, down)
8384 let validMoves = [
8485 squareIdBeingDragged - 1 ,
8586 squareIdBeingDragged - width ,
@@ -89,186 +90,157 @@ function candyCrushGame() {
8990 let validMove = validMoves . includes ( squareIdBeingReplaced ) ;
9091
9192 if ( squareIdBeingReplaced && validMove ) {
92- squareIdBeingReplaced = null ;
93+ squareIdBeingReplaced = null ; // Move is valid, keep the swap
9394 } else if ( squareIdBeingReplaced && ! validMove ) {
94- squares [
95- squareIdBeingReplaced
96- ] . style . backgroundImage = colorBeingReplaced ;
97- squares [
98- squareIdBeingDragged
99- ] . style . backgroundImage = colorBeingDragged ;
100- } else
101- squares [
102- squareIdBeingDragged
103- ] . style . backgroundImage = colorBeingDragged ;
95+ // Invalid move, revert the swap
96+ squares [ squareIdBeingReplaced ] . style . backgroundImage = colorBeingReplaced ;
97+ squares [ squareIdBeingDragged ] . style . backgroundImage = colorBeingDragged ;
98+ } else {
99+ // No drop occurred, revert to original
100+ squares [ squareIdBeingDragged ] . style . backgroundImage = colorBeingDragged ;
101+ }
104102 }
105103
106- //Dropping candies once some have been cleared
104+ // Move Candies Down
107105 function moveIntoSquareBelow ( ) {
108- for ( i = 0 ; i < 55 ; i ++ ) {
106+ // Fill empty squares in the first row
107+ for ( let i = 0 ; i < width ; i ++ ) {
108+ if ( squares [ i ] . style . backgroundImage === "" ) {
109+ let randomColor = Math . floor ( Math . random ( ) * candyColors . length ) ;
110+ squares [ i ] . style . backgroundImage = candyColors [ randomColor ] ;
111+ }
112+ }
113+ // Move candies down to fill gaps
114+ for ( let i = 0 ; i < width * ( width - 1 ) ; i ++ ) {
109115 if ( squares [ i + width ] . style . backgroundImage === "" ) {
110- squares [ i + width ] . style . backgroundImage =
111- squares [ i ] . style . backgroundImage ;
116+ squares [ i + width ] . style . backgroundImage = squares [ i ] . style . backgroundImage ;
112117 squares [ i ] . style . backgroundImage = "" ;
113- const firstRow = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
114- const isFirstRow = firstRow . includes ( i ) ;
115- if ( isFirstRow && squares [ i ] . style . backgroundImage === "" ) {
116- let randomColor = Math . floor (
117- Math . random ( ) * candyColors . length
118- ) ;
119- squares [ i ] . style . backgroundImage = candyColors [ randomColor ] ;
120- }
121118 }
122119 }
123120 }
124121
125- ///-> Checking for Matches <-///
126-
127- //For Row of Four
122+ // Check for Matches
128123 function checkRowForFour ( ) {
129- for ( i = 0 ; i < 60 ; i ++ ) {
124+ for ( let i = 0 ; i < 60 ; i ++ ) {
125+ if ( i % width >= width - 3 ) continue ; // Skip if not enough columns left
130126 let rowOfFour = [ i , i + 1 , i + 2 , i + 3 ] ;
131127 let decidedColor = squares [ i ] . style . backgroundImage ;
132128 const isBlank = squares [ i ] . style . backgroundImage === "" ;
133-
134- const notValid = [
135- 5 ,
136- 6 ,
137- 7 ,
138- 13 ,
139- 14 ,
140- 15 ,
141- 21 ,
142- 22 ,
143- 23 ,
144- 29 ,
145- 30 ,
146- 31 ,
147- 37 ,
148- 38 ,
149- 39 ,
150- 45 ,
151- 46 ,
152- 47 ,
153- 53 ,
154- 54 ,
155- 55
156- ] ;
157- if ( notValid . includes ( i ) ) continue ;
158-
159- if (
160- rowOfFour . every (
161- ( index ) =>
162- squares [ index ] . style . backgroundImage === decidedColor &&
163- ! isBlank
164- )
165- ) {
129+ if ( rowOfFour . every ( index => squares [ index ] . style . backgroundImage === decidedColor && ! isBlank ) ) {
166130 score += 4 ;
167131 scoreDisplay . innerHTML = score ;
168- rowOfFour . forEach ( ( index ) => {
169- squares [ index ] . style . backgroundImage = "" ;
170- } ) ;
132+ rowOfFour . forEach ( index => squares [ index ] . style . backgroundImage = "" ) ;
171133 }
172134 }
173135 }
174- checkRowForFour ( ) ;
175136
176- //For Column of Four
177137 function checkColumnForFour ( ) {
178- for ( i = 0 ; i < 39 ; i ++ ) {
179- let columnOfFour = [ i , i + width , i + width * 2 , i + width * 3 ] ;
138+ for ( let i = 0 ; i < 40 ; i ++ ) {
139+ let columnOfFour = [ i , i + width , i + 2 * width , i + 3 * width ] ;
180140 let decidedColor = squares [ i ] . style . backgroundImage ;
181141 const isBlank = squares [ i ] . style . backgroundImage === "" ;
182-
183- if (
184- columnOfFour . every (
185- ( index ) =>
186- squares [ index ] . style . backgroundImage === decidedColor &&
187- ! isBlank
188- )
189- ) {
142+ if ( columnOfFour . every ( index => squares [ index ] . style . backgroundImage === decidedColor && ! isBlank ) ) {
190143 score += 4 ;
191144 scoreDisplay . innerHTML = score ;
192- columnOfFour . forEach ( ( index ) => {
193- squares [ index ] . style . backgroundImage = "" ;
194- } ) ;
145+ columnOfFour . forEach ( index => squares [ index ] . style . backgroundImage = "" ) ;
195146 }
196147 }
197148 }
198- checkColumnForFour ( ) ;
199149
200- //For Row of Three
201150 function checkRowForThree ( ) {
202- for ( i = 0 ; i < 61 ; i ++ ) {
151+ for ( let i = 0 ; i < 62 ; i ++ ) {
152+ if ( i % width >= width - 2 ) continue ; // Skip if not enough columns left
203153 let rowOfThree = [ i , i + 1 , i + 2 ] ;
204154 let decidedColor = squares [ i ] . style . backgroundImage ;
205155 const isBlank = squares [ i ] . style . backgroundImage === "" ;
206-
207- const notValid = [
208- 6 ,
209- 7 ,
210- 14 ,
211- 15 ,
212- 22 ,
213- 23 ,
214- 30 ,
215- 31 ,
216- 38 ,
217- 39 ,
218- 46 ,
219- 47 ,
220- 54 ,
221- 55
222- ] ;
223- if ( notValid . includes ( i ) ) continue ;
224-
225- if (
226- rowOfThree . every (
227- ( index ) =>
228- squares [ index ] . style . backgroundImage === decidedColor &&
229- ! isBlank
230- )
231- ) {
156+ if ( rowOfThree . every ( index => squares [ index ] . style . backgroundImage === decidedColor && ! isBlank ) ) {
232157 score += 3 ;
233158 scoreDisplay . innerHTML = score ;
234- rowOfThree . forEach ( ( index ) => {
235- squares [ index ] . style . backgroundImage = "" ;
236- } ) ;
159+ rowOfThree . forEach ( index => squares [ index ] . style . backgroundImage = "" ) ;
237160 }
238161 }
239162 }
240- checkRowForThree ( ) ;
241163
242- //For Column of Three
243164 function checkColumnForThree ( ) {
244- for ( i = 0 ; i < 47 ; i ++ ) {
245- let columnOfThree = [ i , i + width , i + width * 2 ] ;
165+ for ( let i = 0 ; i < 48 ; i ++ ) {
166+ let columnOfThree = [ i , i + width , i + 2 * width ] ;
246167 let decidedColor = squares [ i ] . style . backgroundImage ;
247168 const isBlank = squares [ i ] . style . backgroundImage === "" ;
248-
249- if (
250- columnOfThree . every (
251- ( index ) =>
252- squares [ index ] . style . backgroundImage === decidedColor &&
253- ! isBlank
254- )
255- ) {
169+ if ( columnOfThree . every ( index => squares [ index ] . style . backgroundImage === decidedColor && ! isBlank ) ) {
256170 score += 3 ;
257171 scoreDisplay . innerHTML = score ;
258- columnOfThree . forEach ( ( index ) => {
259- squares [ index ] . style . backgroundImage = "" ;
260- } ) ;
172+ columnOfThree . forEach ( index => squares [ index ] . style . backgroundImage = "" ) ;
261173 }
262174 }
263175 }
264- checkColumnForThree ( ) ;
265-
266176
267- window . setInterval ( function ( ) {
177+ // Game Loop
178+ function gameLoop ( ) {
268179 checkRowForFour ( ) ;
269180 checkColumnForFour ( ) ;
270181 checkRowForThree ( ) ;
271182 checkColumnForThree ( ) ;
272183 moveIntoSquareBelow ( ) ;
273- } , 100 ) ;
274- }
184+ }
185+
186+ // Start the Game
187+ function startGame ( mode ) {
188+ currentMode = mode ;
189+ modeSelection . style . display = "none" ;
190+ grid . style . display = "flex" ;
191+ scoreDisplay . parentElement . style . display = "flex" ; // Show scoreboard
192+ createBoard ( ) ;
193+ score = 0 ;
194+ scoreDisplay . innerHTML = score ;
195+ gameInterval = setInterval ( gameLoop , 100 ) ;
196+
197+ if ( mode === "timed" ) {
198+ timeLeft = 120 ; // 2 minutes in seconds
199+ updateTimerDisplay ( ) ;
200+ timerInterval = setInterval ( ( ) => {
201+ timeLeft -- ;
202+ updateTimerDisplay ( ) ;
203+ if ( timeLeft <= 0 ) {
204+ clearInterval ( timerInterval ) ;
205+ endGame ( ) ;
206+ }
207+ } , 1000 ) ;
208+ } else {
209+ timerDisplay . innerHTML = "" ; // Clear timer in Endless Mode
210+ }
211+ }
212+
213+ // Update Timer Display
214+ function updateTimerDisplay ( ) {
215+ if ( currentMode === "timed" ) {
216+ let minutes = Math . floor ( timeLeft / 60 ) ;
217+ let seconds = timeLeft % 60 ;
218+ timerDisplay . innerHTML = `Time Left: ${ minutes } :${ seconds . toString ( ) . padStart ( 2 , "0" ) } ` ;
219+ } else {
220+ timerDisplay . innerHTML = "" ;
221+ }
222+ }
223+
224+ // End Game (Timed Mode)
225+ function endGame ( ) {
226+ clearInterval ( gameInterval ) ;
227+ squares . forEach ( square => square . setAttribute ( "draggable" , false ) ) ;
228+ alert ( `Time's Up! Your score is ${ score } ` ) ;
229+ }
230+
231+ // Change Mode
232+ function changeMode ( ) {
233+ clearInterval ( gameInterval ) ;
234+ if ( currentMode === "timed" ) {
235+ clearInterval ( timerInterval ) ;
236+ }
237+ grid . style . display = "none" ;
238+ scoreDisplay . parentElement . style . display = "none" ;
239+ modeSelection . style . display = "flex" ; // Show mode selection screen
240+ }
241+
242+ // Event Listeners
243+ endlessButton . addEventListener ( "click" , ( ) => startGame ( "endless" ) ) ;
244+ timedButton . addEventListener ( "click" , ( ) => startGame ( "timed" ) ) ;
245+ changeModeButton . addEventListener ( "click" , changeMode ) ;
246+ }
0 commit comments