-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
355 lines (302 loc) · 10.7 KB
/
index.html
File metadata and controls
355 lines (302 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
<!--
CandyCrush
Your Name: Urja Soni
Collaborators:Did not collaborate with anyone for this project
-->
<!DOCTYPE html>
<html>
<!--
/* Copyright (c) 2017 MIT 6.813/6.831 course staff, all rights reserved.
* Redistribution of original or derived work requires permission of course staff.
*/
-->
<head>
<meta charset="utf-8">
<title>CandyCrush</title>
<!-- Load style sheets -->
<link rel="stylesheet" href=
"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css">
<link rel="stylesheet" href="mainLayout.css">
<!-- Use mobile-aware viewport -->
<meta name="viewport" content=
"width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Load any supplemental Javascript libraries here -->
<script src=
"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src=
"https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.2/seedrandom.js">
</script>
</script>
<script src="candy.js"></script>
<script src="board.js"></script>
<script src="rules.js"></script>
<script>
// By default, the first board loaded by your page will be the same
// each time you load (which is accomplished by "seeding" the random
// number generator. This makes testing (and grading!) easier!
Math.seedrandom(0);
s
// A short jQuery extension to read query parameters from the URL.
$.extend({
getUrlVars: function() {
var vars = [], pair;
var pairs = window.location.search.substr(1).split('&');
for (var i = 0; i < pairs.length; i++) {
pair = pairs[i].split('=');
vars.push(pair[0]);
vars[pair[0]] = pair[1] &&
decodeURIComponent(pair[1].replace(/\+/g, ' '));
}
return vars;
},
getUrlVar: function(name) {
return $.getUrlVars()[name];
}
});
// constants
var DEFAULT_BOARD_SIZE = 8;
// data model at global scope for easier debugging
var board;
var rules;
var boardElement;
// initialize board
if ($.getUrlVar('size') && $.getUrlVar('size') >= 3) {
board = new Board($.getUrlVar('size'));
} else {
board = new Board(DEFAULT_BOARD_SIZE);
}
// load a rule
rules = new Rules(board);
// Final initialization entry point: the Javascript code inside this block
// runs at the end of start-up when the page has finished loading.
$(document).ready(function()
{
// Your code here.
rules.prepareNewGame();
buildGameUI();
});
/* Event Handlers */
// access the candy object with info.candy
// add a candy to the board
$(board).on('add', function(e, info)
{
var targetRow = $(boardElement).find('tr').eq(info.toRow);
var targetCol = $(targetRow).find('td').eq(info.toCol);
var candyMarkup = generateCandyMarkup(info.candy);
// a little timeout of 0.5 seconds to animate
setTimeout(function(){
$(targetCol).replaceWith(candyMarkup);
}, 500);
/*
* Handle the "Crush Once" button enable/disable for cases,
when some candies are automatically matched as result of new game or new candies are spawned.
*/
var allPossibleMatches = rules.getCandyCrushes();
if( allPossibleMatches.length ){
$('#crushCandiesBtn').prop('disabled', false).addClass('btn-success text-white');
}else{
$('#crushCandiesBtn').prop('disabled', true).removeClass('btn-success text-white');
}
});
// move a candy on the board
$(board).on('move', function(e, info)
{
/*
When a candy is moved there are two steps to do.
1. Move candy to the its destination by getting the candy info from callback param.
2. Remove the target candy at UI level that was just moved (if its still there in our data structure) in order to avoid replication
{
candy: {},
fromRow:
fromCol:
toRow:
toCol:
}
*/
var destinationRow = $(boardElement).find('tr').eq(info.toRow);
var destinationCol = $(destinationRow).find('td').eq(info.toCol);
var candyAtDestination = board.getCandyAt( info.candy.row, info.candy.col );
var candyMarkup = generateCandyMarkup(candyAtDestination);
$(destinationCol).replaceWith( candyMarkup ); // Boom!
// Candy has already been moved by clonning process, now lets remove the actual one
var targetRow = $(boardElement).find('tr').eq(info.fromRow);
var targetCol = $(targetRow).find('td').eq(info.fromCol);
var targetCandy = board.getCandyAt( info.fromRow, info.toRow );
// Remove the candy from UI after moving to new position
if(!targetCandy){
$(targetCol).text('').css('backgroundColor', '#fff');
}
});
// remove a candy from the board
$(board).on('remove', function(e, info)
{
$('#' + info.candy.id).text('').css('backgroundColor','#fff');
});
// move a candy on the board
$(board).on('scoreUpdate', function(e, info)
{
// Your code here. To be implemented in pset 2.
});
// Button Events
$(document).on('click', "#crushCandiesBtn", function(evt)
{
var allPossibleMatches = rules.getCandyCrushes();
if( allPossibleMatches.length ){
rules.removeCrushes( allPossibleMatches );
rules.moveCandiesDown();
}
});
// keyboard events arrive here
$(document).on('keydown', function(evt) {
// Your code here.
// New game when space bar (Key code 32) or 'n' key (Key code 78) is pressed
if(evt.keyCode === 32 || evt.keyCode === 78){
resetBoardAndStartNewGame();
}
});
function resetBoardAndStartNewGame(){
board.clear();
rules.prepareNewGame();
buildGameUI();
}
/*
* Generate an HTML table dynamically according to the size of the board (resetting everything)
*/
function buildGameUI(){
// Grab the table body element and assign it to global variable for later use
boardElement = document.querySelector('#mainColumn table tbody');
var tableContent = '';
// Loop over the board to generate an actual board using DHTML.
for(var row of board.square){
tableContent += '<tr>';
for(var candy of row){
tableContent += generateCandyMarkup(candy);
}
tableContent += '</tr>';
}
// Finally append the HTML string to the table to render that into the view
$(boardElement).html(tableContent);
$('#lastColumn').show();
}
/*
* Markup helper function that takes a candy instance as a parameter and returns HTML required for a single candy
*/
function generateCandyMarkup(candy){
// Convert 0,1,2,3 to a,b,c,d using binary-to-text encoding scheme (36)
var data = (candy.col + 10).toString(36) + (candy.row + 1);
// If the color is yellow, the text-color should be a color other than the default (white)
var colorProp = candy.color == 'yellow' ? 'color:#555;' : '';
return `<td style="background-color:${candy.color};${colorProp}" id="${candy.id}">${data}</td>`;
}
/*
Get input value and move the board elements accordingly
This function move elements on data structure level only
The actual change occurs when `move` event is fired
*/
function moveCandy(direction){
var candyName = $('#inputCandyName').val();
if(!isCandyNameValid(candyName)){
return false;
}
candyName = candyName.toLowerCase();
var candy = getCandyByName( candyName );
if(rules.isMoveTypeValid(candy, direction) == true ){
var targetCandy = board.getCandyInDirection(candy, direction);
board.flipCandies(candy, targetCandy);
$('#inputCandyName').val('').focus();
// Disable all buttons
disableDirectionalButtons();
$('#crushCandiesBtn').prop('disabled', false).addClass('btn-success text-white');
}else{
console.log('Invalid Move');
}
}
/*
* Takes candy name as a string parameter, where first character is the alphabet representing column
* and second character is a number representing the row.
* Converts first character to ascci to get the column index.
*/
function getCandyByName(candyName){
var candyCol = candyName.charCodeAt(0) - 97;
var candyRow = Number(candyName.charAt(1)) - 1;
return board.getCandyAt(candyRow, candyCol);
}
/**
* On user input, check if input is valid, enable/disable the movement buttons accordingly
*/
function decidePossibleActions(){
var candyName = $('#inputCandyName').val();
disableDirectionalButtons();
if(!isCandyNameValid(candyName)){
return false;
}
candyName = candyName.toLowerCase();
var candy = getCandyByName( candyName );
// if its an invalid input like Z9, clear the input and return false.
if(!candy){
$('#inputCandyName').val('');
return false;
}
var directions = ['up','down','left','right'];
// Loop over all possible directions to find out which ones are valid for the current input
for(var dir of directions){
$('#' + dir + 'ArrowBtn').prop('disabled', rules.isMoveTypeValid(candy, dir) === false );
if(rules.isMoveTypeValid(candy, dir) == true){
$('#' + dir + 'ArrowBtn').addClass('btn-success text-white');
}else{
$('#' + dir + 'ArrowBtn').removeClass('btn-success text-white');
}
}
}
/*
UI helper function to disable all buttons
*/
function disableDirectionalButtons(){
var buttonIds = ['upArrowBtn','downArrowBtn','leftArrowBtn','rightArrowBtn'];
for(var buttonId of buttonIds){
$('#' + buttonId).prop('disabled', true).removeClass('btn-success text-white');
}
}
/*
* Validation helper function to check validity of user input
*/
function isCandyNameValid(candyName){
return candyName && candyName.length == 2;
}
</script>
</head>
<body>
<div class="container pt-5">
<div class="row d-flex flex-column flex-sm-row align-items-center justify-content-between">
<div id="firstColumn" class="mb-5">
<div class="text-center">
<!-- Column 1 Code Here -->
<h2 class="game-title">Candy Crush</h2>
<input type="button" class="btn btn-default" onclick="resetBoardAndStartNewGame()" value="New Game">
</div>
</div>
<div id="mainColumn">
<table class="table table-bordered">
<tbody></tbody>
</table>
<!-- Column 2 Code Here -->
</div>
<div class="text-center" id="lastColumn">
<!-- Column 3 Code Here -->
<h3>Move: <input type="text" style="width:50px" id="inputCandyName" maxlength="2" onkeyup="decidePossibleActions()" /> </h3>
<div class="d-flex justify-content-center">
<button class="btn btn-default arrow-button" id="upArrowBtn" onclick="moveCandy('up')">↑</button>
</div>
<div class="d-flex justify-content-between">
<button class="btn btn-default arrow-button" id="leftArrowBtn" onclick="moveCandy('left')">←</button>
<button class="btn btn-default arrow-button" id="rightArrowBtn" onclick="moveCandy('right')">→</button>
</div>
<button class="btn btn-default arrow-button" id="downArrowBtn" onclick="moveCandy('down')">↓</button>
<div class="mt-4">
<button class="btn btn-default" id="crushCandiesBtn" disabled>Crush Once</button>
</div>
</div>
</div> <!-- class="row" -->
</div> <!-- class="container" -->
</body>
</html>