@@ -3,11 +3,23 @@ document.addEventListener("DOMContentLoaded", () => {
3
3
} ) ;
4
4
5
5
function candyCrushGame ( ) {
6
+ // DOM Elements
6
7
const grid = document . querySelector ( ".grid" ) ;
7
8
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
8
16
const width = 8 ;
9
17
const squares = [ ] ;
10
18
let score = 0 ;
19
+ let currentMode = null ;
20
+ let timeLeft = 0 ;
21
+ let gameInterval = null ;
22
+ let timerInterval = null ;
11
23
12
24
const candyColors = [
13
25
"url(https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/red-candy.png)" ,
@@ -18,8 +30,10 @@ function candyCrushGame() {
18
30
"url(https://raw.githubusercontent.com/arpit456jain/Amazing-Js-Projects/master/Candy%20Crush/utils/purple-candy.png)" ,
19
31
] ;
20
32
21
- // Creating Game Board
33
+ // Create the Game Board
22
34
function createBoard ( ) {
35
+ grid . innerHTML = "" ; // Clear existing grid
36
+ squares . length = 0 ; // Clear squares array
23
37
for ( let i = 0 ; i < width * width ; i ++ ) {
24
38
const square = document . createElement ( "div" ) ;
25
39
square . setAttribute ( "draggable" , true ) ;
@@ -29,32 +43,21 @@ function candyCrushGame() {
29
43
grid . appendChild ( square ) ;
30
44
squares . push ( square ) ;
31
45
}
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 ) ) ;
32
53
}
33
- createBoard ( ) ;
34
-
35
- // Dragging the Candy
36
- let colorBeingDragged ;
37
- let colorBeingReplaced ;
38
- let squareIdBeingDragged ;
39
- let squareIdBeingReplaced ;
40
54
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 ;
53
57
54
58
function dragStart ( ) {
55
59
colorBeingDragged = this . style . backgroundImage ;
56
60
squareIdBeingDragged = parseInt ( this . id ) ;
57
- // this.style.backgroundImage = ''
58
61
}
59
62
60
63
function dragOver ( e ) {
@@ -66,20 +69,18 @@ function candyCrushGame() {
66
69
}
67
70
68
71
function dragLeave ( ) {
69
- this . style . backgroundImage = "" ;
72
+ // No action needed
70
73
}
71
74
72
75
function dragDrop ( ) {
73
76
colorBeingReplaced = this . style . backgroundImage ;
74
77
squareIdBeingReplaced = parseInt ( this . id ) ;
75
78
this . style . backgroundImage = colorBeingDragged ;
76
- squares [
77
- squareIdBeingDragged
78
- ] . style . backgroundImage = colorBeingReplaced ;
79
+ squares [ squareIdBeingDragged ] . style . backgroundImage = colorBeingReplaced ;
79
80
}
80
81
81
82
function dragEnd ( ) {
82
- //Defining, What is a valid move?
83
+ // Define valid moves (adjacent squares: left, up, right, down)
83
84
let validMoves = [
84
85
squareIdBeingDragged - 1 ,
85
86
squareIdBeingDragged - width ,
@@ -89,186 +90,157 @@ function candyCrushGame() {
89
90
let validMove = validMoves . includes ( squareIdBeingReplaced ) ;
90
91
91
92
if ( squareIdBeingReplaced && validMove ) {
92
- squareIdBeingReplaced = null ;
93
+ squareIdBeingReplaced = null ; // Move is valid, keep the swap
93
94
} 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
+ }
104
102
}
105
103
106
- //Dropping candies once some have been cleared
104
+ // Move Candies Down
107
105
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 ++ ) {
109
115
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 ;
112
117
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
- }
121
118
}
122
119
}
123
120
}
124
121
125
- ///-> Checking for Matches <-///
126
-
127
- //For Row of Four
122
+ // Check for Matches
128
123
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
130
126
let rowOfFour = [ i , i + 1 , i + 2 , i + 3 ] ;
131
127
let decidedColor = squares [ i ] . style . backgroundImage ;
132
128
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 ) ) {
166
130
score += 4 ;
167
131
scoreDisplay . innerHTML = score ;
168
- rowOfFour . forEach ( ( index ) => {
169
- squares [ index ] . style . backgroundImage = "" ;
170
- } ) ;
132
+ rowOfFour . forEach ( index => squares [ index ] . style . backgroundImage = "" ) ;
171
133
}
172
134
}
173
135
}
174
- checkRowForFour ( ) ;
175
136
176
- //For Column of Four
177
137
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 ] ;
180
140
let decidedColor = squares [ i ] . style . backgroundImage ;
181
141
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 ) ) {
190
143
score += 4 ;
191
144
scoreDisplay . innerHTML = score ;
192
- columnOfFour . forEach ( ( index ) => {
193
- squares [ index ] . style . backgroundImage = "" ;
194
- } ) ;
145
+ columnOfFour . forEach ( index => squares [ index ] . style . backgroundImage = "" ) ;
195
146
}
196
147
}
197
148
}
198
- checkColumnForFour ( ) ;
199
149
200
- //For Row of Three
201
150
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
203
153
let rowOfThree = [ i , i + 1 , i + 2 ] ;
204
154
let decidedColor = squares [ i ] . style . backgroundImage ;
205
155
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 ) ) {
232
157
score += 3 ;
233
158
scoreDisplay . innerHTML = score ;
234
- rowOfThree . forEach ( ( index ) => {
235
- squares [ index ] . style . backgroundImage = "" ;
236
- } ) ;
159
+ rowOfThree . forEach ( index => squares [ index ] . style . backgroundImage = "" ) ;
237
160
}
238
161
}
239
162
}
240
- checkRowForThree ( ) ;
241
163
242
- //For Column of Three
243
164
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 ] ;
246
167
let decidedColor = squares [ i ] . style . backgroundImage ;
247
168
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 ) ) {
256
170
score += 3 ;
257
171
scoreDisplay . innerHTML = score ;
258
- columnOfThree . forEach ( ( index ) => {
259
- squares [ index ] . style . backgroundImage = "" ;
260
- } ) ;
172
+ columnOfThree . forEach ( index => squares [ index ] . style . backgroundImage = "" ) ;
261
173
}
262
174
}
263
175
}
264
- checkColumnForThree ( ) ;
265
-
266
176
267
- window . setInterval ( function ( ) {
177
+ // Game Loop
178
+ function gameLoop ( ) {
268
179
checkRowForFour ( ) ;
269
180
checkColumnForFour ( ) ;
270
181
checkRowForThree ( ) ;
271
182
checkColumnForThree ( ) ;
272
183
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