PageSourceSearch

https://orgaos-portugal.net/calcudoku-html5-game/js/game.js

js orgaos-portugal.net collected 2026-09-25 01:37:33 UTC 51,310 bytes, 1,693 lines download raw bytes

1////////////////////////////////////////////////////////////
2// GAME v1.2
3////////////////////////////////////////////////////////////
4
5/*!
6 * 
7 * GAME SETTING CUSTOMIZATION START
8 * 
9 */
10
11var stageW=1280; //game width
12var stageH=768; //game height
13var portraitW=380; //game portrait width
14var portraitH=650; //game portrait height
15var fitToScreen = true; //fit to browser screen
16var maintainAspectRatio = true; //maintain aspect ratio
17
18var puzzleSettings = {
19    borderSize:5, //cell border size
20    borderDividerSize:15, //cell border wall size
21    borderColour:'#000', //cell border colour
22    colour:['#ff9d00','#2ce6ff','#00ff79','#fb6b4b','#f0cd0f','#6864ff','#efc37d','#b95bfc','#e9f734','#ff83fc','#ffbab2','#35e5bb','#c6c6c6'], //cell group colours
23}
24
25var timerSettings = {
26						status:true, //true or false to enable timer
27						mode:'countdown', //default or countdown mode
28                        hintPenalty:5000, //hint penalty
29						timesupText:'TIME\'S UP', //time's up text display
30					};
31
32//easy, normal, hard, expert mode settings
33var puzzleLevelSettings = [
34                            {size:3, group_limit:3, timer:50000}, //grid size, group limit, timer for countdown mode
35                            {size:4, group_limit:3, timer:80000},
36                            {size:5, group_limit:4, timer:120000},
37                            {size:6, group_limit:5, timer:250000},
38                        ]
39
40var enableHintButton = true; //toggle Hint button (true, false)
41var enableSolveButton = true; //toggle Solve button (true, false)
42var hintTips = 'Give me hint (-5s penalty).'; //hint tips
43var solveTips = 'See solution.'; //solve tips
44
45var instructionText = 'FILL IN THE GRID'; //instruction text display
46var resultCompleteText = 'CALCUDOKU COMPLETED!'; //puzzle complete text display
47var resultInCompleteText = 'BETTER LUCK NEXT TIME!'; //puzzle incomplete text display
48
49//Social share, [SCORE] will replace with game score
50var shareEnable = true; //toggle share
51var shareText = 'Share your score'; //social share guide
52var shareTitle = 'Highscore on CalcuDoku Game is [SCORE]';//social share score title
53var shareMessage = '[SCORE] is mine new highscore on CalcuDoku Game! Try it now!'; //social share score message
54
55/*!
56 *
57 * GAME SETTING CUSTOMIZATION END
58 *
59 */
60var playerData = {timer:0};
61var gameData = {page:'', mode:'landscape', completed:false, failed:false, solved:false};
62var timeData = {enable:false, startDate:null, nowDate:null, timer:0, countdown:0, penalty:0};
63
64var puzzleData = {
65					size:5,
66					borders:[],
67					groups:[],
68					rows:[],
69					cells:[],
70					group_limit:3,
71					solved:false,
72					result:false,
73                    hint:false,
74					error:false,
75                    colour:[]
76				}
77
78var puzzleFontSize = [
79                    {size:3, number:100, rule:60},
80                    {size:4, number:80, rule:50},
81                    {size:5, number:65, rule:40},
82                    {size:6, number:50, rule:30}
83                ];
84
85/*!
86 * 
87 * GAME BUTTONS - This is the function that runs to setup button event
88 * 
89 */
90function buildGameButton(){
91	$(window).focus(function() {
92		if($('#buttonSound').hasClass('buttonSoundOn')){
93			toggleSoundInMute(false);
94		}
95	});
96	
97	$(window).blur(function() {
98		if($('#buttonSound').hasClass('buttonSoundOn')){
99			toggleSoundInMute(true);
100		}
101	});
102
103    puzzleData.colour = puzzleSettings.colour;
104    
105    toggleConfirm(false);
106    toggleTutorial(false);
107    
108    $('.gameGuideStatus').html(instructionText);
109    $('.gameResultStatus').html(resultCompleteText);
110    $('.gameShareStatus').html(shareText);
111    
112	$('#buttonStart').click(function() {
113		playSound('soundClick');
114        toggleGameMode(true);
115    });
116    
117    $('#buttonGameEasy').click(function() {
118		playSound('soundClick');
119        getSettings(0)
120        goPage('game');
121    });
122    
123    $('#buttonGameMedium').click(function() {
124		playSound('soundClick');
125        getSettings(1)
126        goPage('game');
127    });
128    
129    $('#buttonGameHard').click(function() {
130		playSound('soundClick');
131        getSettings(2)
132        goPage('game');
133    });
134    
135    $('#buttonGameExpert').click(function() {
136		playSound('soundClick');
137        getSettings(3)
138        goPage('game');
139    });
140    
141    $('#buttonHowToPlay, #buttonTutorial').click(function() {
142		playSound('soundClick');
143		toggleTutorial(true);
144        toggleGameOption(false);
145    });
146    
147    $('#buttonHowToPlayOk').click(function() {
148		playSound('soundClick');
149		toggleTutorial(false);
150    });
151	
152	$('#buttonOk').click(function() {
153		playSound('soundClick');
154		toggleConfirm(false);
155		stopGame();
156		goPage('main');
157    });
158	
159	$('#buttonCancel').click(function() {
160		playSound('soundClick');
161		toggleConfirm(false);
162    });
163	
164	$('#buttonContinue').click(function() {
165		playSound('soundClick');
166		goPage('main');
167    });
168	
169	$('#buttonFacebook').click(function() {
170        share('facebook');
171    });
172	
173	$('#buttonTwitter').click(function() {
174        share('twitter');
175    });
176	
177	$('#buttonWhatsapp').click(function() {
178        share('whatsapp');
179    });
180	
181	$('#buttonOption').click(function() {
182		playSound('soundClick');
183        toggleGameOption();
184    });
185	
186	$('#buttonSound').click(function() {
187		playSound('soundClick');
188        toggleGameMute();
189    });
190	
191	$('#buttonFullscreen').click(function() {
192		playSound('soundClick');
193        toggleFullScreen();
194    });
195	
196	$('#buttonExit').click(function() {
197		playSound('soundClick');
198		toggleGameOption();
199        toggleConfirm(true);
200    });
201	
202	$(window).focus(function() {
203        //resizeGameDetail();
204    });
205}
206
207
208/*!
209 * 
210 * DISPLAY PAGES - This is the function that runs to display pages
211 * 
212 */
213function goPage(page){
214	gameData.page = page;
215	$('#logoHolder').hide();
216	$('#gameHolder').hide();
217	$('#resultHolder').hide();
218	$('#buttonExit').show();
219    $('#buttonTutorial').show();
220	
221	var targetContainer = ''
222	switch(page){
223		case 'main':
224			targetContainer = $('#logoHolder');
225			$('#buttonExit').hide();
226            $('#buttonTutorial').hide();
227            toggleGameMode(false);
228		break;
229		
230		case 'game':
231			targetContainer = $('#gameHolder');
232			startGame();
233		break;
234	}
235	
236	targetContainer.show();
237	TweenMax.to(targetContainer, 0, {opacity:0, overwrite:true});
238	TweenMax.to(targetContainer, 1, {opacity:1, overwrite:true});
239    
240    toggleGameOption(false);
241    resizeGameDetail();
242}
243
244function toggleGameMode(con){
245    $('#buttonStart').hide();
246    $('#buttonHowToPlay').hide();
247    $('#buttonGameEasy').hide();
248    $('#buttonGameMedium').hide();
249    $('#buttonGameHard').hide();
250    $('#buttonGameExpert').hide();
251    $('#logoHolder .action').removeClass('level');
252    
253    if(con){
254        if(gameData.mode == 'landscape'){
255            $('#logoHolder .action').addClass('level');
256        }
257        $('#buttonGameEasy').show();
258        $('#buttonGameMedium').show();
259        $('#buttonGameHard').show();
260        $('#buttonGameExpert').show();
261    }else{
262        $('#buttonStart').show();
263        $('#buttonHowToPlay').show();
264    }
265}
266
267/*!
268 * 
269 * START GAME - This is the function that runs to start play game
270 * 
271 */
272function startGame(){
273    shuffleClass();
274	playSound('soundStart');
275    $('.gameButtonGuideStatus').html('').hide();
276    
277    toggleResult(false);
278    toggleGameTimer(true);
279    generatePuzzle();
280}
281
282 /*!
283 * 
284 * STOP GAME - This is the function that runs to stop play game
285 * 
286 */
287function stopGame(){
288	stopAudio();
289	TweenMax.killAll(false, true, false);
290}
291
292function saveGame(score, type){
293	if ( typeof toggleScoreboardSave == 'function' ) { 
294		$.scoreData.score = score;
295		if(typeof type != 'undefined'){
296			$.scoreData.type = type;	
297		}
298		toggleScoreboardSave(true);
299	}
300
301	/*$.ajax({
302      type: "POST",
303      url: 'saveResults.php',
304      data: {score:score},
305      success: function (result) {
306          console.log(result);
307      }
308    });*/
309}
310
311function getSettings(type){
312    puzzleData.size = puzzleLevelSettings[type].size;
313    puzzleData.group_limit = puzzleLevelSettings[type].group_limit;
314    timeData.countdown = puzzleLevelSettings[type].timer;
315}
316
317/*!
318 * 
319 * GENERATE BOARD - This is the function that runs to generate board
320 * 
321 */
322function generateBoard(){
323	var boardPuzzle = $('#puzzleTable');
324    boardPuzzle.html("");
325
326    puzzleData.borders = [];
327    for (var row = 0; row < puzzleData.size + 1; row++) {
328        puzzleData.borders.push([]);
329        for (var col = 0; col < puzzleData.size + 1; col++) {
330            puzzleData.borders[row].push(false); 
331        }
332    }
333
334    // reset rows
335    puzzleData.rows = [];
336    puzzleData.cells = [];
337    puzzleData.groups = [];
338	
339    for (var row = 0; row < puzzleData.size; row++) {
340        puzzleData.rows.push([]);
341		
342		var tableRow = $(document.createElement('tr'));
343        tableRow.addClass('row'); 
344		boardPuzzle.append(tableRow);
345		
346        for (var col = 0; col < puzzleData.size; col++) {
347            var i = row * puzzleData.size + col;
348            var tableCell = new createCell(row, col, i);
349            puzzleData.rows[row][col] = tableCell;
350            puzzleData.cells[i] = tableCell;
351            tableRow.append(tableCell.div);
352        }
353    }
354    updateGroups();	
355	updateInputs();
356}
357
358/*!
359 * 
360 * UPDATE INPUTS - This is the function that runs to update inputs
361 * 
362 */
363function updateInputs(){
364    $('.gameChoiceWrapper ul').empty();
365    for (var i = 0; i < puzzleData.size; i++) {
366        var numberHTML = '';
367        numberHTML += '<li class="buttonClick" data-calcudoku="'+(i+1)+'">';
368        numberHTML += '<div class="gameChoiceNumber resizeFont" data-fontSize="50" data-lineHeight="50">'+(i+1)+'</div>';
369        numberHTML += '<img src="assets/item_number_bg.svg" />';
370        numberHTML += '</li>';
371        
372		$('.gameChoiceWrapper ul').append(numberHTML);
373    }
374    
375    //remove
376    var numberHTML = '';
377    numberHTML += '<li class="buttonClick" data-calcudoku="">';
378    numberHTML += '<div class="gameChoiceNumber resizeFont" data-fontSize="50" data-lineHeight="50">X</div>';
379    numberHTML += '<img src="assets/item_number_bg.svg" />';
380    numberHTML += '</li>';
381    $('.gameChoiceWrapper ul').append(numberHTML);
382    
383    //hint
384    if(enableHintButton){
385        var numberHTML = '';
386        numberHTML += '<li class="buttonClick" data-calcudoku="HINT">';
387        numberHTML += '<img src="assets/button_hint.svg" />';
388        numberHTML += '</li>';
389        $('.gameChoiceWrapper ul').append(numberHTML);
390    }
391    
392    //solve
393    if(enableSolveButton){
394        var numberHTML = '';
395        numberHTML += '<li class="buttonClick" data-calcudoku="SOLVE">';
396        numberHTML += '<img src="assets/button_solve.svg" />';
397        numberHTML += '</li>';
398        $('.gameChoiceWrapper ul').append(numberHTML);
399    }
400    
401    
402    $('.gameChoiceWrapper li').each(function(index, element) {
403        $(this).click(function() {
404            playSound('soundSelect');
405            var currentValue = $(this).attr('data-calcudoku');
406            
407            if(currentValue == 'SOLVE'){
408                displayGroupSolve();
409            }else if(currentValue == 'HINT'){
410                findNextHint();
411            }else{
412                $('.currentFocus .numberWrapper').html(currentValue);
413                checkCellError();
414                checkCellComplete();  
415            }
416        });
417        
418        $(this).hover(
419           function () {
420              var currentValue = $(this).attr('data-calcudoku');
421               if(currentValue == 'SOLVE'){
422                    $('.gameButtonGuideStatus').html(solveTips).fadeIn();
423                }else if(currentValue == 'HINT'){
424                    $('.gameButtonGuideStatus').html(hintTips).fadeIn();
425                }else{
426                    $('.gameButtonGuideStatus').html('').hide();
427                }
428           }, 
429
430           function () {
431              var currentValue = $(this).attr('data-calcudoku');
432               $('.gameButtonGuideStatus').html('').hide();
433           }
434        );
435    });
436    
437    $("body").keypress(function(e){
438        if (e.shiftKey || e.ctrlKey || e.altKey) {
439            e.preventDefault();
440        } else {
441        var key = e.keyCode;
442            if (!((key == 8) || (key == 46) || (key >= 35 && key <= 40) || (key >= 48 && key <= 57) || (key >= 96 && key <= 105))) {
443                e.preventDefault();
444            }
445        }
446        
447        if(gameData.completed){
448            return;
449        }
450        
451        var value = e.key;
452        if(!isNaN(value)){
453            if(value.length > 1){
454                value = Number(value.substring(1,2));
455            }
456
457            if (value < 1 && isNaN(value)){
458                value = 1;
459            }
460
461            if (value > puzzleData.size){
462                value = puzzleData.size;
463            }
464            
465            playSound('soundSelect');
466            $('.currentFocus .numberWrapper').html(value);
467            checkCellError();
468            checkCellComplete();
469        }
470    });
471    
472	$('.numberWrapper').each(function(index, element) {
473        $(this).click(function() {
474            if(gameData.completed){
475                return;
476            }
477
478            $('.numberWrapper').each(function(index, element) {
479                $(this).parent().removeClass('currentFocus');
480            });  
481            $(this).parent().addClass('currentFocus');
482        });
483    });
484}
485
486/*!
487 * 
488 * CHECK CELL ERROR - This is the function that runs to check cell error
489 * 
490 */
491function checkCellError(){
492	puzzleData.error = false;
493	$('.cell').removeClass('error');
494	
495	for (var i = 0; i < puzzleData.rows.length; i++) {
496		var in_row = [];
497        for (var j = 0; j < puzzleData.rows.length; j++) {
498			var value = puzzleData.rows[i][j].div.find('.numberWrapper').html();
499			
500			if(value != ''){
501				var checkIndex = jQuery.inArray(value, in_row);
502				if(checkIndex != -1 && value != -1){
503					 puzzleData.error = true;
504					 puzzleData.rows[i][j].div.addClass('error');
505					 puzzleData.rows[i][checkIndex].div.addClass('error');
506				}
507			}
508			in_row.push(value);
509        }
510    }
511	
512	for (var i = 0; i < puzzleData.rows.length; i++) {
513		var in_col = [];
514        for (var j = 0; j < puzzleData.rows.length; j++) {
515			var value = puzzleData.rows[j][i].div.find('.numberWrapper').html();
516			
517			if(value != ''){
518				var checkIndex = jQuery.inArray(value, in_col);
519				if(checkIndex != -1 && value != -1){
520					 puzzleData.error = true;
521					 puzzleData.rows[j][i].div.addClass('error');
522					 puzzleData.rows[checkIndex][i].div.addClass('error');
523				}
524			}
525			in_col.push(value);
526        }
527    }
528    
529    if(puzzleData.error)
530        playSound('soundError');
531}
532
533/*!
534 * 
535 * CHECK CELL COMPLETE - This is the function that runs to check if puzzle is complete
536 * 
537 */
538function checkCellComplete(){
539	var currentLength = $('.numberWrapper').length;
540	var completeLength = 0;
541	
542	$('.numberWrapper').each(function(index, element) {
543		var currentValue = $(this).html();
544        if(currentValue != '' && !isNaN(currentValue)){
545			completeLength++;	
546		}
547    });
548	
549	if(currentLength == completeLength && !puzzleData.error){
550		if(!puzzleData.solved){
551			groupSolve();
552		}else{
553			checkPuzzleSolve();	
554		}
555	}
556}
557
558/*!
559 * 
560 * CHECK PUZZLE SOLVE - This is the function that runs to check if puzzle is solve
561 * 
562 */
563function checkPuzzleSolve(){
564	checkCellError();
565	
566	var correctGroupLength = 0;
567	for (var i = 0; i < puzzleData.groups.length; i++) {
568		var array = [];
569		for (var m = 0; m < puzzleData.groups[i].members.length; m++) {
570			var row = puzzleData.groups[i].members[m].row;
571			var col = puzzleData.groups[i].members[m].col;
572			array.push(puzzleData.rows[row][col].div.find('.numberWrapper').html());
573		}
574		
575		for (var p = 0; p < puzzleData.groups[i].possible.length; p++) {
576			var correctCount = 0;
577			for (var v = 0; v < puzzleData.groups[i].possible[p].length; v++) {
578				if(puzzleData.groups[i].possible[p][v] == array[v]){
579					correctCount++;
580				}
581			}
582			
583			if(correctCount == puzzleData.groups[i].possible[p].length){
584				p = puzzleData.groups[i].possible.length;	
585				correctGroupLength++;
586			}
587		}
588	}
589	
590	if(correctGroupLength == puzzleData.groups.length){
591        toggleGameTimer(false);
592        toggleResult(true);
593	}
594}
595
596/*!
597 * 
598 * CREATE CELL & GROUP - This is the function that runs to create cell and group
599 * 
600 */
601function createCell(row, col, index) {
602    this.row = row;
603    this.col = col;
604    this.index = index;
605    this.group = null;
606    this.sol = function(solution) {
607        return solution[this.row][this.col];
608    };
609    this.possible = [];
610    this.addPossibleChoices = function(arr) {
611        for (var i = 0; i < arr.length; i++) {
612            if (jQuery.inArray(arr[i], this.possible) == -1) {
613                this.possible.push(arr[i]);
614            }
615        }
616    };
617    // group related bits
618    
619    this.border_top = false;
620    this.border_right = false;
621	
622    this.div = $(document.createElement("td")).attr({
623            class: "cell buttonClick",
624            id: "c" + row + "c" + col,
625			row: row,
626			col: col
627        });
628    
629    var sizeIndex = 0;
630    for(var n=0; n<puzzleFontSize.length; n++){
631        if(puzzleData.size == puzzleFontSize[n].size){
632           sizeIndex = n;
633        }
634    }
635	
636	this.bg_div = $(document.createElement("div"));
637    this.value_div = $(document.createElement("div"));
638	this.rule_div = $(document.createElement("div"));
639	this.bg_div.addClass('bgWrapper');
640	this.value_div.addClass('numberWrapper');
641    this.value_div.addClass('resizeFont');
642    this.value_div.attr('data-fontSize', puzzleFontSize[sizeIndex].number);
643    this.value_div.attr('data-lineHeight', puzzleFontSize[sizeIndex].number * 2);
644	this.rule_div.addClass('ruleWrapper');
645    this.rule_div.addClass('resizeFont');
646    this.rule_div.attr('data-fontSize', puzzleFontSize[sizeIndex].rule);
647    this.rule_div.attr('data-lineHeight', puzzleFontSize[sizeIndex].rule);
648	
649	this.div.append(this.bg_div);
650    this.div.append(this.value_div);
651	this.div.append(this.rule_div);
652}
653
654function createGroup() {
655    this.goal = 0;
656    this.index = -1;
657    this.operation = "+";
658	
659    // The cell containing the description.
660    this.topmost = null;
661    this.members = [];
662	
663    this.add = function(cell) {
664        cell.group = this;
665		$.each(puzzleData.colour, function(i, v){
666		   cell.bg_div.css('background', 'transparent');
667		});
668		cell.bg_div.css('background', puzzleData.colour[puzzleData.classShuffle[puzzleData.classNum]]);
669        this.members.push(cell);
670    }
671    this.addAll = function(all) {
672        for (var i = 0; i < all.length; i++) {
673            this.add(all[i]);
674        }
675    }
676	
677	puzzleData.classNum++;
678	if(puzzleData.classNum > puzzleData.classShuffle.length-1){
679		shuffleClass();
680	}
681}
682
683function shuffleClass(){
684    puzzleData.classNum = 0;
685    puzzleData.classShuffle = [];
686	for(var n=0; n<puzzleData.colour.length; n++){
687		puzzleData.classShuffle.push(n);	
688	}
689	shuffle(puzzleData.classShuffle);
690}
691
692/*!
693 * 
694 * GENERATE PUZZLE - This is the function that runs to create puzzle
695 * 
696 */
697function generatePuzzle() {
698	puzzleData.solved = false;
699	puzzleData.result = false;
700    puzzleData.hint = false;
701    
702    generateBoard();
703	
704    for (var c = 0; c < puzzleData.cells.length; c++) {
705        puzzleData.cells[c].group = null;
706    }
707    puzzleData.groups = [];
708
709    // create groups
710    var visited = []
711    for (var c = 0; c < puzzleData.cells.length; c++) {
712        var cell = puzzleData.cells[c];
713        if (cell.group === null) {
714            // add the rows to the group
715            var g = new createGroup();
716            g.topmost = cell;
717            g.add(cell);
718            var g_cell = cell;
719            while (g.members.length < puzzleData.group_limit) {
720                var r = Math.random();
721                var neighbors = [];
722                var addNeighbor = function(row, col) {
723                    try {
724                        var neighbor = puzzleData.rows[g_cell.row + row][g_cell.col + col];
725                        if (neighbor.group == null) {
726                            neighbors.push(neighbor);
727                        }
728                    } catch (err) {}
729                };
730                addNeighbor(0, -1); // left
731                addNeighbor(0, 1); // right
732                addNeighbor(1, 0); // top
733                addNeighbor(-1, 0); // bottom
734
735                if (neighbors.length == 0 || Math.random() < 0.3) {
736                    break;
737                }
738                var pick = neighbors[Math.floor(Math.random() * neighbors.length)];
739                g.add(pick);
740                g_cell = pick;
741            }
742            // update borders
743            for (var i = 0; i < g.members.length; i++) {
744                var m = g.members[i];
745                if (m.row > 0 && puzzleData.rows[m.row - 1][m.col].group != g) {
746                    m.border_top = true;
747                }
748                if (m.col < puzzleData.rows.length - 1 && puzzleData.rows[m.row][m.col + 1].group != g) {
749                    m.border_right = true;
750                }
751            }
752            puzzleData.groups.push(g);
753        }
754    }
755    
756    var solution = [];
757    var c = 0;
758    for (var i = 0; i < puzzleData.rows.length; i++) {
759        solution.push([]);
760        for (var j = 1; j < puzzleData.rows.length + 1; j++) {
761            solution[i].push(((c + i) % puzzleData.rows.length) + 1);
762            c++;
763        }
764    }
765    // randomize the rows
766    for (var i = 0; i < 10; i++) {
767        var from_row = Math.floor(Math.random() * puzzleData.rows.length);
768        var to_row = Math.floor(Math.random() * puzzleData.rows.length);
769        var temp = solution[from_row];
770        solution[from_row] = solution[to_row];
771        solution[to_row] = temp;
772    }
773    // randomize the columns
774    for (var i = 0; i < 10; i++) {
775        var from_col = Math.floor(Math.random() * puzzleData.rows.length);
776        var to_col = Math.floor(Math.random() * puzzleData.rows.length);
777        var temp;
778        for (var j = 0; j < puzzleData.rows.length; j++) {
779            temp = solution[j][from_col];
780            solution[j][from_col] = solution[j][to_col];
781            solution[j][to_col] = temp;
782        }
783    }
784    
785    // Choose an operation and calculate target
786    var group_solutions = function(group) {
787        var sols = [];
788        for (var i = 0; i < group.members.length; i++) {
789            sols.push(solution[group.members[i].row][group.members[i].col]);
790        }
791        return sols;
792    };
793    for (var i = 0; i < puzzleData.groups.length; i++) {
794        var g = puzzleData.groups[i];
795        var s = group_solutions(g);
796        if (g.members.length === 1) {
797            g.operation = "+";
798        } else {
799            var possible = ["+", "*"];
800            if (g.members.length === 2) {
801                possible.push("-");
802                if ((s[0] / s[1]) == Math.floor(s[0] / s[1]) || 
803                    (s[1] / s[0]) == Math.floor(s[1] / s[0])) {
804                    possible.push("/");
805                }
806            } 
807            g.operation = possible[Math.floor(Math.random() * possible.length)];
808        }
809        if (g.operation == "-") {
810            g.goal = (s[0] - s[1]) > 0 ? (s[0] - s[1]) : (s[1] - s[0]);
811        } else if (g.operation == "/") {
812            if (s[0] / s[1] == Math.floor(s[0] / s[1])) {
813                g.goal = s[0] / s[1];
814            } else {
815                g.goal = s[1] / s[0];
816            }
817        } else if (g.operation == "*") {
818            g.goal = 1;
819            for (var j = 0; j < s.length; j++) {
820                g.goal *= s[j];
821            }
822        } else if (g.operation == "+") {
823            g.goal = 0;
824            for (var j = 0; j < s.length; j++) {
825                g.goal += s[j];
826            }
827        }
828    }
829
830    updateBorders();
831    updateRules();
832}
833
834/*!
835 * 
836 * GROUP CELLS - This is the function that runs to find group cells
837 * 
838 */
839function findNeighbors(cell, neighbors) {
840    // banking on the fact that all top-row cells have a top border
841    if (!neighbors) {
842        neighbors = [cell];
843    }
844    if (!cell.border_top && cell.row > 0) {
845        findNeighborsPush(puzzleData.rows[cell.row - 1][cell.col], neighbors);
846    }
847    if (!cell.border_right && cell.col < puzzleData.rows.length - 1) {
848        findNeighborsPush(puzzleData.rows[cell.row][cell.col + 1], neighbors);
849    }
850    if (cell.row < puzzleData.rows.length - 1) {
851        var below = puzzleData.rows[cell.row + 1][cell.col];
852        if (!below.border_top) {
853            findNeighborsPush(below, neighbors);
854        }
855    }
856    if (cell.col > 0) {
857        var left = puzzleData.rows[cell.row][cell.col - 1];
858        if (!left.border_right) {
859            findNeighborsPush(left, neighbors);
860        }
861    }
862    return neighbors;
863}
864
865function findNeighborsPush(cell, neighbors) {
866    if (jQuery.inArray(cell, neighbors) == -1) {
867        neighbors.push(cell);
868        findNeighbors(cell, neighbors);
869    }
870}
871
872/*!
873 * 
874 * UPDATE GROUPS - This is the function that runs to update cell groups
875 * 
876 */
877function updateGroups() {
878    var old_groups = puzzleData.groups;
879    puzzleData.groups = [];
880	
881    // get the list of groups from the UI.
882    var g = new createGroup();
883    var visited = [];
884    for (var i = 0; i < puzzleData.cells.length; i++) {
885        var cell = puzzleData.cells[i];
886		
887        if (jQuery.inArray(cell, visited) == -1) {
888            var neighbors = findNeighbors(cell, null);
889            g.addAll(neighbors);
890            g.topmost = cell;
891            g.index = puzzleData.groups.length;
892            puzzleData.groups.push(g);
893            for (var n = 0; n < neighbors.length; n++) {
894                neighbors[n].group = g;
895            }
896            visited = jQuery.merge(visited, neighbors);
897            // start again for next group
898            g = new createGroup();
899        }
900    }
901    var num_groups = Math.min(old_groups.length, puzzleData.groups.length);
902    for (var i = 0; i < num_groups; i++) {
903        puzzleData.groups[i].goal = old_groups[i].goal;
904        puzzleData.groups[i].operation = old_groups[i].operation;
905    }
906	
907    updateBorders();
908    updateRules();
909}
910
911/*!
912 * 
913 * UPDATE BORDERS - This is the function that runs to update cell borders
914 * 
915 */
916function updateBorders() {
917    for (var row = 0; row < puzzleData.rows.length; row++) {
918        for (var col = 0; col < puzzleData.rows[row].length; col++) {
919            // Update cell border
920            if (row == 0 || puzzleData.rows[row][col].border_top) {
921                puzzleData.rows[row][col].div.addClass('border-top');
922            } else {
923                puzzleData.rows[row][col].div.removeClass('border-top');
924            }
925            if (col == puzzleData.rows[row].length - 1 || puzzleData.rows[row][col].border_right) {
926                puzzleData.rows[row][col].div.addClass('border-right');
927            } else if (col != puzzleData.rows[row].length) {
928                puzzleData.rows[row][col].div.removeClass('border-right');
929            }
930            if (col == 0) {
931                puzzleData.rows[row][col].div.addClass('border-left');
932            } else {
933                puzzleData.rows[row][col].div.removeClass('border-left');
934            }
935            if (row == puzzleData.rows.length - 1) {
936                puzzleData.rows[row][col].div.addClass('border-bottom');
937            } else {
938                puzzleData.rows[row][col].div.removeClass('border-bottom');
939            }
940        }
941    }
942}
943
944/*!
945 * 
946 * UPDATE RULES - This is the function that runs to update rules
947 * 
948 */
949function updateRules() {
950    for (var i = 0; i < puzzleData.cells.length; i++) {
951        var cell = puzzleData.cells[i];
952        cell.rule_div.html("");
953        if (cell.group.topmost == cell) {
954            cell.rule_div.append(cell.group.goal + " " + cell.group.operation);
955        }
956    }
957}
958
959function findNextHint(){
960    puzzleData.hint = true;
961    
962    if(!puzzleData.solved){
963        groupSolve();
964    }else{
965        displayHint();
966    }
967}
968
969function displayHint(){
970    var hintFound = false;
971    
972    for (var i = 0; i < puzzleData.rows.length; i++) {
973        for (var j = 0; j < puzzleData.rows.length; j++) {
974            var currentValue = Number(puzzleData.rows[i][j].div.find('.numberWrapper').html());
975            if(currentValue != puzzleData.rows[i][j].div.solved){
976                puzzleData.rows[i][j].div.find('.numberWrapper').html(puzzleData.rows[i][j].div.solved);
977                i = puzzleData.rows.length;
978                j = puzzleData.rows.length;
979                hintFound = true;
980            }
981        }
982    }
983    puzzleData.hint = false;
984    
985    if(hintFound){
986        timeData.penalty += timerSettings.hintPenalty;
987        checkCellError();
988        checkCellComplete();  
989    }
990}
991
992/*!
993 * 
994 * DISPLAY GROUP SOLVE - This is the function that runs to reveal puzzle solution
995 * 
996 */
997function displayGroupSolve(){
998    gameData.solved = true;
999	puzzleData.result = true;
1000	groupSolve();
1001}
1002
1003function checkCurrentSolve(){
1004	getAllGroupSolutions();
1005    puzzleData.groups = puzzleData.groups.sort(function(a, b) {
1006        if (a.possible.length < b.possible.length) {
1007            return -1;
1008        } else if (a.possible.length == b.possible.length) {
1009            return 0;
1010        }
1011        return 1;
1012    });	
1013}
1014 
1015function groupSolve(){
1016    var start = new Date();
1017    getAllGroupSolutions();
1018    puzzleData.groups = puzzleData.groups.sort(function(a, b) {
1019        if (a.possible.length < b.possible.length) {
1020            return -1;
1021        } else if (a.possible.length == b.possible.length) {
1022            return 0;
1023        }
1024        return 1;
1025    });
1026
1027    var searchspace = 1;
1028    var group_nums = "";
1029    for (var i = 0; i < puzzleData.groups.length; i++) {
1030        searchspace *= puzzleData.groups[i].possible.length;
1031        group_nums += puzzleData.groups[i].possible.length + " ";
1032    }
1033
1034    var gindices = [];
1035    var solution = [];
1036    for (var i = 0; i < puzzleData.rows.length; i++) {
1037        solution.push([]);
1038        for (var j = 0; j < puzzleData.rows.length; j++) {
1039            solution[i].push(0);
1040        }
1041    }
1042    var fill_solution = function() {
1043        for (var i = 0; i < gindices.length; i++) {
1044            var group = puzzleData.groups[i];
1045            for (var c = 0; c < group.members.length; c++) {
1046                var cell = group.members[c];
1047                solution[cell.row][cell.col] = group.possible[gindices[i]][c];
1048            }
1049        }
1050        for (var j = gindices.length; j < puzzleData.groups.length; j++) {
1051            var group = puzzleData.groups[j];
1052            for (var i = 0; i < group.members.length; i++) {
1053                var cell = group.members[i];
1054                solution[cell.row][cell.col] = 0;
1055            }
1056        }
1057    };
1058    var visited = new Set();
1059    var to_visit = new Stack();
1060    for (var i = 0; i < puzzleData.groups[0].possible.length; i++) {
1061        to_visit.push([i]);
1062    }
1063    var solved = false;
1064    var traversed = 0;
1065    while (to_visit.length > 0) {
1066        gindices = to_visit.pop();
1067        traversed += 1;
1068        fill_solution();
1069        if (gindices.length == puzzleData.groups.length) {
1070            if (checkAll(solution)) {
1071                var solved = true;
1072                drawSolution(solution);
1073                break;
1074            } else {
1075                continue;
1076            }
1077        } else {
1078            if (!visited.contains(gindices) && checkRows(solution) && checkCols(solution)) {
1079                visited.add(gindices);
1080                var pos = gindices.length;
1081                gindices.push(0);
1082                for (var i = 0; i < puzzleData.groups[pos].possible.length; i++) {
1083                    gindices[pos] = i;
1084                    to_visit.push(gindices);
1085                }
1086            }
1087        }
1088    }
1089    var end = new Date();
1090    if (!solved) {
1091        alert("No solution!");
1092    } else {
1093		puzzleData.solved = true;
1094        if(puzzleData.hint){
1095            displayHint();
1096        }else{
1097            checkPuzzleSolve();   
1098        }
1099        console.log("Solved in " + ((end - start) / 1000.) + " seconds.");
1100    }
1101}
1102
1103function copyArray(arr) {
1104    var copy = [];
1105    for (var i = 0; i < arr.length; i++) {
1106        copy.push(arr[i]);
1107    }
1108    return copy;
1109}
1110function Set() {
1111    var visited = [];
1112    this.add = function(thing) {
1113        if (!this.contains(thing)) {
1114
1115            visited.push(copyArray(thing));
1116        }
1117    };
1118    this.contains = function(thing) {
1119        return jQuery.inArray(thing, visited) != -1;
1120    };
1121}
1122function Stack() {
1123    var stack = [];
1124    this.length = 0;
1125    this.push = function(arr) {
1126        stack.push(copyArray(arr));
1127        this.length += 1;
1128    }
1129    this.pop = function(arr) {
1130        this.length -= 1;
1131        return stack.pop();
1132    }
1133}
1134function copyNumSort(array) {
1135    var copy = array.slice();
1136    copy.sort(function(a, b) { return a < b ? -1 : (a > b ? 1 : 0) });
1137    return copy;
1138}
1139function getAllGroupSolutions() {
1140    for (var g = 0; g < puzzleData.groups.length; g++) {
1141        var group = puzzleData.groups[g];
1142        var combine;
1143        if (group.operation == "-") {
1144            combine = function(choices) {
1145                choices = copyNumSort(choices);
1146                var val = choices[choices.length-1];
1147                for (var i = choices.length - 2; i >= 0; i--) {
1148                    val -= choices[i];
1149                }
1150                return val;
1151            }
1152        } else if (group.operation == "*") {
1153            combine = function(choices) {
1154                var total = 1;
1155                for (var i = 0; i < choices.length; i++) {
1156                    total *= choices[i];
1157                }
1158                return total;
1159            }
1160        } else if (group.operation == "/") {
1161            combine = function(choices) {
1162                choices = copyNumSort(choices);
1163                var val = choices[choices.length-1];
1164                for (var i = choices.length - 2; i >= 0; i--) {
1165                    val /= choices[i];
1166                }
1167                return val;
1168            }
1169        } else {
1170            combine = function(choices) {
1171                var total = 0;
1172                for (var i = 0; i < choices.length; i++) {
1173                    total += choices[i];
1174                }
1175                return total;
1176            }
1177        }
1178        var choices = [];
1179        var max = puzzleData.rows.length;
1180        var min = 1;
1181        for (var i = 0; i < group.members.length; i++) {
1182            choices.push(min);
1183        }
1184        var incomplete = 1;
1185        group.possible = [];
1186        var check_solution = function(choices) {
1187            if (combine(choices) != group.goal) {
1188                return false;
1189            }
1190            var solution = [];
1191            for (var i = 0; i < puzzleData.rows.length; i++) {
1192                solution.push([]);
1193                for (var j = 0; j < puzzleData.rows.length; j++) {
1194                    solution[i].push(0);
1195                }
1196            }
1197            for (var i = 0; i < choices.length; i++) {
1198                solution[group.members[i].row][group.members[i].col] = choices[i];
1199            }
1200            return checkRows(solution) && checkCols(solution);
1201        };
1202        while (incomplete) {
1203            if (check_solution(choices)) {
1204                group.possible.push(copyArray(choices));
1205            }
1206            var p = 0;
1207            choices[p] += 1;
1208            while (choices[p] > max) {
1209                choices[p] = min;
1210                p += 1;
1211                if (p >= choices.length) {
1212                    incomplete = 0;
1213                } else {
1214                    choices[p] += 1;
1215                }
1216            }
1217        }
1218    }
1219
1220}
1221function constructGroupConstrainedChoices() {
1222    for (var g = 0; g < puzzleData.groups.length; g++) {
1223        var group = puzzleData.groups[g];
1224        var combine;
1225        if (group.operation == "-") {
1226            combine = function(choices) {
1227                choices = copyNumSort(choices);
1228                var total = choices[choices.length - 1];
1229                for (var i = choices.length - 2; i >= 0; i--) {
1230                    total -= choices[i];
1231                }
1232                return total;
1233            }
1234        } else if (group.operation == "*") {
1235            combine = function(choices) {
1236                var total = 1;
1237                for (var i = 0; i < choices.length; i++) {
1238                    total *= choices[i];
1239                }
1240                return total;
1241            }
1242        } else if (group.operation == "/") {
1243            combine = function(choices) {
1244                choices = copyNumSort(choices);
1245                var total = choices[choices.length - 1];
1246                for (var i = 0; i < choices.length; i++) {
1247                    total /= choices[i];
1248                }
1249                return total;
1250            }
1251        } else {
1252            combine = function(choices) {
1253                var total = 0;
1254                for (var i = 0; i < choices.length; i++) {
1255                    total += choices[i];
1256                }
1257                return total;
1258            }
1259        }
1260        var choices = [];
1261        var max = puzzleData.rows.length;
1262        var min = 1;
1263        for (var i = 0; i < group.members.length; i++) {
1264            choices.push(min);
1265        }
1266        var incomplete = 1;
1267        while (incomplete) {
1268            if (combine(choices) == group.goal) {
1269                for (var m = 0; m < group.members.length; m++) {
1270                    group.members[m].addPossibleChoices(choices);
1271                }
1272            }
1273            var p = 0;
1274            choices[p] += 1;
1275            while (choices[p] > max) {
1276                choices[p] = min;
1277                p += 1;
1278                if (p >= choices.length) {
1279                    incomplete = 0;
1280                } else {
1281                    choices[p] += 1;
1282                }
1283            }
1284        }
1285    }
1286}
1287
1288/*!
1289 * 
1290 * DRAW SOLUTION - This is the function that runs to draw solution
1291 * 
1292 */
1293function drawSolution(solution) {
1294    for (var i = 0; i < puzzleData.rows.length; i++) {
1295        for (var j = 0; j < puzzleData.rows.length; j++) {
1296			puzzleData.rows[i][j].div.solved = solution[i][j];
1297			if(puzzleData.result){
1298				puzzleData.rows[i][j].div.find('.numberWrapper').html(solution[i][j]);	
1299			}
1300        }
1301    }
1302}
1303
1304/*!
1305 * 
1306 * CHECK PUZZLE VALIDITY - This is the function that runs to check if puzzle have a valid solution
1307 * 
1308 */
1309function checkAll(solution) {
1310    return checkGroups(solution) && checkCols(solution) && checkRows(solution);
1311}
1312function checkGroups(solution) {
1313    for (var g = 0; g < puzzleData.groups.length; g++) {
1314        if (!checkGroup(puzzleData.groups[g], solution)) {
1315            return false;
1316        }
1317    }
1318    return true;
1319}
1320function checkGroup(group, solution) {
1321    if (group.members.length == 1) {
1322        return true;
1323    } else if (group.operation == '+') {
1324        var total = 0;
1325        for (var g = 0; g < group.members.length; g++) {
1326            total += group.members[g].sol(solution);
1327        }
1328        return total == group.goal;
1329    } else if (group.operation == '*') {
1330        var total = 1;
1331        for (var g = 0; g < group.members.length; g++) {
1332            total *= group.members[g].sol(solution);
1333        }
1334        return total == group.goal;
1335    } else {
1336        // For divide and subtract, arrange operands in descending order.
1337        var operands = [];
1338        for (var i = 0; i < group.members.length; i++) {
1339            operands.push(group.members[i].sol(solution));
1340        }
1341        operands = copyNumSort(operands);
1342        var val = operands[operands.length - 1];
1343        for (var i = operands.length - 2; i >= 0; i--) {
1344            if (group.operation == '-') {
1345                val -= operands[i];
1346            } else if (group.operation == '/') {
1347                val /= operands[i];
1348            }
1349        }
1350        return val == group.goal;
1351    }
1352    return false;
1353}
1354
1355function checkRows(solution) {
1356    for (var row = 0; row < puzzleData.rows.length; row++) {
1357        var in_row = [];
1358        for (var col = 0; col < puzzleData.rows[row].length; col++) {
1359            var val = solution[row][col];
1360            if (val != 0 && jQuery.inArray(val, in_row) != -1) {
1361                return false;
1362            }
1363            in_row.push(val);
1364        }
1365    }
1366    return true;
1367}
1368function checkCols(solution) {
1369    for (var col = 0; col < puzzleData.rows.length; col++) {
1370        var in_col = [];
1371        for (var row = 0; row < puzzleData.rows.length; row++) {
1372            var val = solution[row][col];
1373            if (val != 0 && jQuery.inArray(val, in_col) != -1) {
1374                return false;
1375            }
1376            in_col.push(val);
1377        }
1378    }
1379    return true;
1380}
1381
1382/*!
1383 * 
1384 * GAME TIMER - This is the function that runs for game timer
1385 * 
1386 */
1387function toggleGameTimer(con){
1388	if(!timerSettings.status){
1389		return;	
1390	}
1391	
1392	if(con){
1393        timeData.penalty = 0;
1394		timeData.startDate = new Date();
1395		loopGameTimer();
1396	}else{
1397		
1398	}
1399	timeData.enable = con;
1400}
1401
1402function loopGameTimer(){
1403	TweenMax.to(timeData, .2, {overwrite:true, onComplete:updateGameTimer});		
1404}
1405
1406function updateGameTimer(){
1407	if(!timeData.enable){
1408		return;	
1409	}
1410	
1411	timeData.nowDate = new Date();
1412	var elapsedTime = (timeData.nowDate.getTime() - timeData.startDate.getTime());
1413	
1414	if(timerSettings.mode == 'default'){
1415		timeData.timer = Math.floor(elapsedTime + timeData.penalty);
1416	}else if(timerSettings.mode == 'countdown'){
1417		timeData.timer = Math.floor(((timeData.countdown)) - (elapsedTime + timeData.penalty))
1418	}
1419	
1420    playerData.timer = timeData.timer;
1421	$('.gameTimerStatus').html(millisecondsToTime(timeData.timer));
1422	
1423	var timerContinue = true;
1424	if(timerSettings.mode == 'countdown'){
1425		if(timeData.timer <= 0){
1426			timerContinue = false;	
1427		}
1428	}
1429	
1430	if(timerContinue){
1431		loopGameTimer();
1432	}else{
1433		$('.gameTimerStatus').html(millisecondsToTime(0));
1434		
1435		gameData.failed = true;
1436        toggleResult(true);
1437	}
1438}
1439
1440/*!
1441 * 
1442 * TOGGLE RESULT - This is the function that runs to toggle result
1443 * 
1444 */
1445function toggleResult(con){
1446    $('.gameChoiceHolder').hide();
1447    $('.gameResultHolder').hide();
1448    
1449	if(con){
1450		$('.numberWrapper').each(function(index, element) {
1451            $(this).parent().removeClass('currentFocus');
1452        });
1453        gameData.completed = true;
1454		$('.gameResultHolder').fadeIn();
1455        
1456        $('.resultOption').show();
1457        if(!shareEnable){
1458            $('.resultOption').hide();
1459        }
1460        
1461        stopGame();
1462        if(gameData.solved){
1463            playSound('soundOver');
1464            $('.resultOption').hide();
1465            $('.gameResultStatus').html(resultInCompleteText);
1466        }else if(gameData.failed){
1467            $('.gameResultStatus').html(timerSettings.timesupText);
1468            playSound('soundOver');
1469        }else{
1470            $('.gameResultStatus').html(resultCompleteText);
1471            playSound('soundComplete');
1472        }
1473	}else{
1474        gameData.completed = false;
1475        gameData.failed = false;
1476        gameData.solved = false;
1477		$('.gameChoiceHolder').fadeIn();
1478	}
1479}
1480
1481function resizeGameDetail(){
1482    var curScalePercent = scalePercent;
1483    
1484    if(gameData.mode == 'portrait'){
1485        curScalePercent = scalePercent * .5;
1486        $('.gameTimerHolder').css('left', 'auto');
1487        
1488        $('.gameTimerStatus').attr('data-fontsize', 80);
1489		$('.gameTimerStatus').attr('data-lineheight', 160);
1490        
1491        $('.gameGuideStatus').attr('data-fontsize', 50);
1492		$('.gameGuideStatus').attr('data-lineheight', 50);
1493        
1494        $('.gameButtonGuideStatus').attr('data-fontsize', 40);
1495		$('.gameButtonGuideStatus').attr('data-lineheight', 40);
1496    }else{
1497        var targetPuzzle = $("#puzzleHolder").position();
1498        $('.gameTimerHolder').css('left', targetPuzzle.left + $("#puzzleHolder").outerWidth());
1499        
1500        $('.gameTimerStatus').attr('data-fontsize', 60);
1501		$('.gameTimerStatus').attr('data-lineheight', 120);
1502        
1503        $('.gameGuideStatus').attr('data-fontsize', 30);
1504		$('.gameGuideStatus').attr('data-lineheight', 30);
1505        
1506        $('.gameButtonGuideStatus').attr('data-fontsize', 25);
1507		$('.gameButtonGuideStatus').attr('data-lineheight', 25);
1508    }
1509    
1510    $('#puzzleTable .cell').each(function(index, element) {
1511        var currentWidth = $(this).outerWidth();
1512        $(this).css('height', currentWidth);
1513        $(this).css('border', puzzleSettings.borderColour+' solid '+(puzzleSettings.borderSize * curScalePercent)+'px');
1514    });
1515    
1516    $('.border-left').each(function(index, element) {
1517        $(this).css('border-left', puzzleSettings.borderColour+' solid '+(puzzleSettings.borderDividerSize * curScalePercent)+'px');
1518    });
1519    $('.border-right').each(function(index, element) {
1520        $(this).css('border-right', puzzleSettings.borderColour+' solid '+(puzzleSettings.borderDividerSize * curScalePercent)+'px');
1521    });
1522    $('.border-top').each(function(index, element) {
1523        $(this).css('border-top', puzzleSettings.borderColour+' solid '+(puzzleSettings.borderDividerSize * curScalePercent)+'px');
1524    });
1525    $('.border-bottom').each(function(index, element) {
1526        $(this).css('border-bottom', puzzleSettings.borderColour+' solid '+(puzzleSettings.borderDividerSize * curScalePercent)+'px');
1527    });
1528    
1529    resizeGameFonts();
1530}
1531
1532/*!
1533 * 
1534 * RESIZE GAME FONTS - This is the function that runs to resize game fonts
1535 * 
1536 */
1537function resizeGameFonts(){
1538    var curScalePercent = scalePercent;
1539    if(gameData.mode == 'portrait'){
1540        curScalePercent = scalePercent * .5;
1541    }
1542    
1543	$('.resizeFont').each(function(index, element) {
1544        $(this).css('font-size', Math.round(Number($(this).attr('data-fontSize'))*curScalePercent)+'px');
1545		$(this).css('line-height', Math.round(Number($(this).attr('data-lineHeight'))*curScalePercent)+'px');
1546    });
1547}
1548
1549/*!
1550 * 
1551 * MILLISECONDS CONVERT - This is the function that runs to convert milliseconds to time
1552 * 
1553 */
1554function millisecondsToTime(milli) {
1555	var milliseconds = milli % 1000;
1556	var seconds = Math.floor((milli / 1000) % 60);
1557	var minutes = Math.floor((milli / (60 * 1000)) % 60);
1558	
1559	if(seconds<10){
1560		seconds = '0'+seconds;  
1561	}
1562	
1563	if(minutes<10){
1564		minutes = '0'+minutes;  
1565	}
1566	
1567	return minutes+':'+seconds;
1568}
1569
1570
1571/*!
1572 * 
1573 * TOGGLE CONFIRM - This is the function that runs to toggle confirm exit
1574 * 
1575 */
1576function toggleConfirm(con){
1577	if(con){
1578		$('#confirmHolder').show();
1579	}else{
1580		$('#confirmHolder').hide();	
1581	}
1582}
1583
1584/*!
1585 * 
1586 * TOGGLE TUTORIAL - This is the function that runs to toggle tutorial content
1587 * 
1588 */
1589function toggleTutorial(con){
1590	if(con){
1591		$('#tutorialHolder').show();
1592	}else{
1593		$('#tutorialHolder').hide();	
1594	}
1595}
1596
1597
1598/*!
1599 * 
1600 * OPTIONS - This is the function that runs to mute and fullscreen
1601 * 
1602 */
1603function toggleGameOption(con){
1604    if(con != undefined){
1605		$('#buttonOption').removeClass('buttonOptionOff');
1606        $('#buttonOption').removeClass('buttonOptionOn');
1607        
1608        if(!con){
1609            $('#buttonOption').addClass('buttonOptionOn');
1610            $('#optionList').show();
1611        }else{
1612            $('#buttonOption').addClass('buttonOptionOff');
1613            $('#optionList').hide();
1614        }
1615    }
1616	if($('#buttonOption').hasClass('buttonOptionOn')){
1617		$('#buttonOption').removeClass('buttonOptionOn');
1618		$('#buttonOption').addClass('buttonOptionOff');
1619		$('#optionList').hide();
1620	}else{
1621		$('#buttonOption').removeClass('buttonOptionOff');
1622		$('#buttonOption').addClass('buttonOptionOn');
1623		$('#optionList').show();
1624	}
1625}
1626
1627function toggleGameMute(){
1628	if($('#buttonSound').hasClass('buttonSoundOn')){
1629		$('#buttonSound').removeClass('buttonSoundOn');
1630		$('#buttonSound').addClass('buttonSoundOff');
1631		toggleSoundInMute(true);
1632	}else{
1633		$('#buttonSound').removeClass('buttonSoundOff');
1634		$('#buttonSound').addClass('buttonSoundOn');
1635		toggleSoundInMute(false);
1636	}
1637}
1638
1639
1640function toggleFullScreen() {
1641  if (!document.fullscreenElement &&    // alternative standard method
1642      !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement ) {  // current working methods
1643    if (document.documentElement.requestFullscreen) {
1644      document.documentElement.requestFullscreen();
1645    } else if (document.documentElement.msRequestFullscreen) {
1646      document.documentElement.msRequestFullscreen();
1647    } else if (document.documentElement.mozRequestFullScreen) {
1648      document.documentElement.mozRequestFullScreen();
1649    } else if (document.documentElement.webkitRequestFullscreen) {
1650      document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
1651    }
1652  } else {
1653    if (document.exitFullscreen) {
1654      document.exitFullscreen();
1655    } else if (document.msExitFullscreen) {
1656      document.msExitFullscreen();
1657    } else if (document.mozCancelFullScreen) {
1658      document.mozCancelFullScreen();
1659    } else if (document.webkitExitFullscreen) {
1660      document.webkitExitFullscreen();
1661    }
1662  }
1663}
1664
1665
1666/*!
1667 * 
1668 * SHARE - This is the function that runs to open share url
1669 * 
1670 */
1671function share(action){
1672	gtag('event','click',{'event_category':'share','event_label':action});
1673	
1674	var loc = location.href
1675	loc = loc.substring(0, loc.lastIndexOf("/") + 1);
1676	
1677	var title = '';
1678	var text = '';
1679	
1680	title = shareTitle.replace("[SCORE]", millisecondsToTime(playerData.timer));
1681    text = shareMessage.replace("[SCORE]", millisecondsToTime(playerData.timer));
1682	var shareurl = '';
1683	
1684	if( action == 'twitter' ) {
1685		shareurl = 'https://twitter.com/intent/tweet?url='+loc+'&text='+text;
1686	}else if( action == 'facebook' ){
1687		shareurl = 'https://www.facebook.com/sharer/sharer.php?u='+encodeURIComponent(loc+'share.php?desc='+text+'&title='+title+'&url='+loc+'&thumb='+loc+'share.jpg&width=590&height=300');
1688	}else if( action == 'whatsapp' ){
1689		shareurl = "whatsapp://send?text=" + encodeURIComponent(text) + " - " + encodeURIComponent(loc);
1690	}
1691	
1692	window.open(shareurl);
1693}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.