From b4eaac2fd4b3e6dc8358d12399e07bc273bdfb4e Mon Sep 17 00:00:00 2001 From: Raymond May Jr Date: Sat, 9 Feb 2013 14:57:15 +0100 Subject: [PATCH 1/4] cleanup --- js/game.js | 989 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 595 insertions(+), 394 deletions(-) diff --git a/js/game.js b/js/game.js index 9c7a756..ce4e426 100644 --- a/js/game.js +++ b/js/game.js @@ -4,429 +4,630 @@ * requires sudoku.js, jstorage */ +/* run */ +$(document).ready(function () { + + Game.start(); + Binds.optionBinds(); +}); + /* defaults settings */ var Settings = { - difficulty: 'medium', - show_conflicts: false + + difficulty: 'medium', + show_conflicts: false }; var Game = { - difficulties: {test_solved: 1, easy: 20, medium: 40, hard: 55, expert: 64}, - - grid: {}, user_values: [], game_values: [], time_elapsed: '', s_elapsed: 0, + + 'difficulties': { + + 'test_solved': 1, + 'easy': 20, + 'medium': 40, + 'hard': 55, + 'expert': 64 + }, - start: function(){ - this.grid = CU.Sudoku.generate(); - var loaded = this.loadState(); - if(loaded){ - this.grid.rows = this.game_values; - }else{ - CU.Sudoku.cull(this.grid, this.difficulties[Settings.difficulty]); - } - Display.gameTable(); - if(loaded){ - /* insert and display stored user values */ - Display.loadUserValues(); - } - $('.ending').fadeOut(function(){$(this).remove();}); - $('#timer').html('0:00:00'); - Timer.start(function(arr){ - Display.timer(arr[0]); - Game.time_elapsed = arr[0]; - Game.s_elapsed = Math.floor(arr[1]/1000); - $.jStorage.set('s_elapsed', JSON.stringify(Game.s_elapsed)); - }, Game.s_elapsed * 1000); - }, - - solved: function(){ - Timer.stop(); - Display.end(); - }, + 'grid': {}, + 'user_values': [], + 'game_values': [], + 'time_elapsed': '', + 's_elapsed': 0, + + // Start the game + 'start': function () { + + // Initialize a full internal sudoku grid + this.grid = CU.Sudoku.generate(); + + // Load previous game, or create a new one + var loaded = this.loadState(); + if (loaded) { + // load previous + this.grid.rows = this.game_values; + } + else { + // create a new game by culling full sudoku grid + CU.Sudoku.cull(this.grid, this.difficulties[Settings.difficulty]); + } + + Display.gameTable(); + + if (loaded) { + + // insert and display stored user values + Display.loadUserValues(); + } + + // remove ending screen + $('.ending').fadeOut(function () { + + $(this).remove(); + }); + + // reset timer display + $('#timer').html('0:00:00'); + + Timer.start(function (arr) { + + Display.timer(arr[0]); + Game.time_elapsed = arr[0]; + Game.s_elapsed = Math.floor(arr[1]/1000); + $.jStorage.set('s_elapsed', JSON.stringify(Game.s_elapsed)); + }, Game.s_elapsed * 1000); + }, + + 'solved': function () { + + Timer.stop(); + Display.end(); + }, - saveState: function(){ - this.user_values = this.fillRows(); - this.game_values = this.fillRows(); - var $rows = $('.game-row'); - for(var r = 0; r < 9; r++){ - var $row = $($rows[r]); - var $cells = $row.children('.cell'); - for(var c = 0; c < 9; c++){ - $cell = $($cells[c]); - var value = parseInt($cell.text()); - if($cell.is('.game-value')){ - this.game_values[r][c] = value; - }else if(value > 0){ - this.user_values[r][c] = value; - } - } + 'saveState': function () { + + this.user_values = this.fillRows(); + this.game_values = this.fillRows(); + var $rows = $('.game-row'); + + for (var r = 0; r < 9; r++) { + + var $row = $($rows[r]); + var $cells = $row.children('.cell'); + + for (var c = 0; c < 9; c++) { + + $cell = $($cells[c]); + var value = parseInt($cell.text(), 10); + if ($cell.is('.game-value')) { + + this.game_values[r][c] = value; } - $.jStorage.set('game_values', JSON.stringify(this.game_values)); - $.jStorage.set('user_values', JSON.stringify(this.user_values)); - }, - - loadState: function(){ - var _game_values = JSON.parse($.jStorage.get('game_values')) || []; - var _user_values = JSON.parse($.jStorage.get('user_values')) || []; - this.s_elapsed = 0; - if(_user_values.length > 0){ - this.user_values = _user_values; - }else{ - return false; - } - if(_game_values.length > 0){ - this.game_values = _game_values; - }else{ - return false; - } - this.s_elapsed = JSON.parse($.jStorage.get('s_elapsed')) || 0; - return true; - }, - - flushState: function(){ - $.jStorage.set('game_values', JSON.stringify([])); - $.jStorage.set('user_values', JSON.stringify([])); - $.jStorage.set('s_elapsed', '0'); - }, - - /** - * return zero-filled grid array - * used by saveState - */ - fillRows: function(){ - var rows = []; - for(var row = 0; row < 9; row++) - { - var cols = []; - for(var col = 0; col < 9; col++){ - cols[col] = 0; - } - rows[row] = cols; - } - return rows; + else if (value > 0) { + + this.user_values[r][c] = value; + } + } + } + + $.jStorage.set('game_values', JSON.stringify(this.game_values)); + $.jStorage.set('user_values', JSON.stringify(this.user_values)); + }, + + 'loadState': function () { + + var _game_values = JSON.parse($.jStorage.get('game_values')) || []; + var _user_values = JSON.parse($.jStorage.get('user_values')) || []; + + this.s_elapsed = 0; + + if (_user_values.length > 0) { + + this.user_values = _user_values; + } + else { + + return false; + } + + if (_game_values.length > 0) { + + this.game_values = _game_values; + } + else { + + return false; } + + this.s_elapsed = JSON.parse($.jStorage.get('s_elapsed')) || 0; + return true; + }, + + 'flushState': function () { + + $.jStorage.set('game_values', JSON.stringify([])); + $.jStorage.set('user_values', JSON.stringify([])); + $.jStorage.set('s_elapsed', '0'); + }, + + /** + * return zero-filled grid array + * used by saveState + **/ + 'fillRows': function () { + + var rows = []; + + for (var row = 0; row < 9; row++) { + + var cols = []; + for (var col = 0; col < 9; col++) { + + cols[col] = 0; + } + + rows[row] = cols; + } + + return rows; + } }; var Display = { - /* show game table */ - gameTable: function(){ - $game = $('#game'); - $game.empty(); - var table = $(document.createElement('table')); - for(var r = 0; r < 9; r++){ - var tr = $(document.createElement('tr')).addClass('game-row'); - for(var c = 0; c < 9; c++){ - var td = $(document.createElement('td')).addClass('cell'); - if(Game.grid.rows[r][c] !== 0){ - td.html(Game.grid.rows[r][c]).addClass('game-value'); - } - if(r === 0){ - td.addClass('first-row'); - } - if(c === 0){ - td.addClass('first-col'); - } - if((c+1) % 3 === 0){ - td.addClass('mini-right'); - } - if((r+1) % 3 === 0){ - td.addClass('mini-bottom'); - } - tr.append(td); - } - table.append(tr); + + /* show game table */ + 'gameTable': function () { + + $game = $('#game'); + $game.empty(); + + var $table = $(document.createElement('table')); + + for (var r = 0; r < 9; r++) { + + var $tr = $(document.createElement('tr')).addClass('game-row'); + + for (var c = 0; c < 9; c++) { + + var $td = $(document.createElement('td')).addClass('cell'); + if (Game.grid.rows[r][c] !== 0) { + + $td.html(Game.grid.rows[r][c]).addClass('game-value'); + } + + if (r === 0) { + + $td.addClass('first-row'); + } + + if (c === 0) { + + $td.addClass('first-col'); + } + + if ((c+1) % 3 === 0) { + + $td.addClass('mini-right'); + } + + if ((r+1) % 3 === 0) { + + $td.addClass('mini-bottom'); } - $game.append(table); - Binds.tableBinds(); - }, - - loadUserValues: function(){ - for(var r = 0; r < 9; r ++){ - for(var c = 0; c < 9; c++){ - if(Game.user_values[r][c] > 0){ - $(this.getCell(c,r)).html(Game.user_values[r][c]); - Game.grid.rows[r][c] = Game.user_values[r][c]; - } - } - } - }, + + $tr.append($td); + } + + $table.append($tr); + } - end: function(){ - var dialog = $(document.createElement('div')).addClass('ending').hide(); - var heading = $(document.createElement('h2')).html('Congratulations!'); - var text = $(document.createElement('p')).html('You solved this puzzle in ' + Game.time_elapsed); - dialog.append(heading); - dialog.append(text); - var tweet = $(document.createElement('p')); - var link = $(document.createElement('a')).addClass('button'); - link.attr('href', - 'http://twitter.com/home?status=I+finished+a+'+Settings.difficulty+'+sudoku+puzzle+in+'+encodeURI(Game.time_elapsed)+'++Try+and+beat+my+time+at+http%3A%2F%2Fsudokunomi.com'); - link.text('Tweet your time!'); - dialog.append(tweet.append(link)); - - $('body').append(dialog.fadeIn()); - }, - - timer: function(str){ - $('#timer').text(str); - }, + $game.append($table); + Binds.tableBinds(); + }, + + 'loadUserValues': function () { + + for (var r = 0; r < 9; r ++) { + + for (var c = 0; c < 9; c++) { + + if (Game.user_values[r][c] > 0) { + + $(this.getCell(c,r)).html(Game.user_values[r][c]); + Game.grid.rows[r][c] = Game.user_values[r][c]; + } + } + } + }, + + 'end': function () { + + var dialog = $(document.createElement('div')).addClass('ending').hide(); + var heading = $(document.createElement('h2')).html('Congratulations!'); + var text = $(document.createElement('p')).html('You solved this puzzle in ' + Game.time_elapsed); + + dialog.append(heading); + dialog.append(text); + + var tweet = $(document.createElement('p')); + var link = $(document.createElement('a')).addClass('button'); + + link.attr('href', 'http://twitter.com/home?status=I+finished+a+'+Settings.difficulty+'+sudoku+puzzle+in+'+encodeURI(Game.time_elapsed)+'++Try+and+beat+my+time+at+http%3A%2F%2Fsudokunomi.com'); + link.text('Tweet your time!'); + dialog.append(tweet.append(link)); + + $('body').append(dialog.fadeIn()); + }, + + 'timer': function (str) { + + $('#timer').text(str); + }, - entryDialog: function(cell){ - var $this = $(cell); - /* dialog to enter value */ - var dialog = $(document.createElement('div')).addClass('input-dialog').hide(); - var form = $(document.createElement('form')).addClass('input-form'); - var input = $('').addClass('input-input'); - dialog.append(form.append(input)); - /* display dialog */ - $('.input-dialog').remove(); - var cords = $this.offset(); - dialog.css('top', (cords.top /*+ $this.height()/2*/)); - dialog.css('left', (cords.left /*+ $this.width()/2*/)); - $('body').append(dialog.fadeTo(200, 0.8)); - $('.input-input').focus(); - $('.input-form').on('submit',function(){ - return false; - }); - $('.input-input').on('keydown',function(e){ - var keyCode = e.keyCode || e.which; - var $selected = $('.cell-selected:not(.game-value)'); - var pos = Display.getCellPosition($selected.get(0)); - if((keyCode > 47 && keyCode < 58) || (keyCode > 93 && keyCode < 106)){ - if($selected.length > 0){ - var value = String.fromCharCode((keyCode > 93 ? keyCode - 48 : keyCode)); - Game.grid.setValue(pos[0],pos[1], value); - $this.html((value === 0 ? '' : value)); - } - }else{ - Game.grid.setValue(pos[0],pos[1], 0); - $this.empty(); - } - Display.killDialog(); - Display.findConflicts(); - Game.saveState(); - }); - }, + 'entryDialog': function (cell) { + + var $this = $(cell); + + /* dialog to enter value */ + var dialog = $(document.createElement('div')).addClass('input-dialog').hide(); + var form = $(document.createElement('form')).addClass('input-form'); + var input = $('').addClass('input-input'); - killDialog: function(){ - $('.input-dialog').fadeOut(200, function(){$(this).remove();}); - }, - - getCellPosition: function(cell){ - var $this = $(cell); - var $rows = $('.game-row'); - for(var r = 0; r < 9; r++){ - var $row = $($rows[r]); - var $cells = $row.children('.cell'); - for(var c = 0; c < 9; c++){ - $cell = $($cells[c]); - if($cell.get(0) == $this.get(0)){ - return [c,r]; - } - } + dialog.append(form.append(input)); + + /* display dialog */ + $('.input-dialog').remove(); + var cords = $this.offset(); + dialog.css('top', (cords.top /*+ $this.height()/2*/)); + dialog.css('left', (cords.left /*+ $this.width()/2*/)); + + $('body').append(dialog.fadeTo(200, 0.8)); + $('.input-input').focus(); + $('.input-form').on('submit', function () { + + return false; + }); + + $('.input-input').on('keydown', function (e) { + + var keyCode = e.keyCode || e.which; + var $selected = $('.cell-selected:not(.game-value)'); + var pos = Display.getCellPosition($selected.get(0)); + + if ((keyCode > 47 && keyCode < 58) || (keyCode > 93 && keyCode < 106)) { + + if($selected.length > 0){ + + var value = String.fromCharCode((keyCode > 93 ? keyCode - 48 : keyCode)); + Game.grid.setValue(pos[0],pos[1], value); + $this.html((value === 0 ? '' : value)); } - return false; - }, + + } + else { + + Game.grid.setValue(pos[0],pos[1], 0); + $this.empty(); + } + + Display.killDialog(); + Display.findConflicts(); + Game.saveState(); + }); + }, - getCell: function(col,row){ - var $rows = $('.game-row'); - for(var r = 0; r < 9; r++){ - var $row = $($rows[r]); - var $cells = $row.children('.cell'); - for(var c = 0; c < 9; c++){ - $cell = $($cells[c]); - if(col == c && row == r){ - return $cell.get(0); - } - } - } - return false; - }, - - moveSelect: function(direction){ - var position = []; - $selected = $('.cell-selected'); - if($selected.length > 0){ - position = this.getCellPosition($('.cell-selected').get(0)); - }else{ - position = [0,0]; - } - /* kill any open dialog */ - this.killDialog(); - switch(direction){ - case 'up': - if(position[1] > 0) - position[1] -= 1; - break; - case 'down': - if(position[1] < 8) - position[1] += 1; - break; - case 'right': - if(position[0] < 8) - position[0] += 1; - break; - case 'left': - if(position[0] >0) - position[0] -= 1; - break; - } - /* remove prev selection */ - $('.cell-selected').removeClass('cell-selected'); - /* apply new selection */ - $(this.getCell(position[0], position[1])).addClass('cell-selected'); - }, - - /* highlight /all/ conflicting cells */ - findConflicts: function(){ - /* remove previous */ - $('.conflict').removeClass('conflict'); - if(Settings.show_conflicts){ - /* find conflicts */ - var $rows = $('.game-row'); - for(var r = 0; r < 9; r++){ - var $row = $($rows[r]); - var $cells = $row.children('.cell'); - for(var c = 0; c < 9; c++){ - if(!Game.grid.cellValid(c, r)){ - conflicts = true; - var $cell = $($cells[c]); - $cell.addClass('conflict'); - } - } - } - } - /* check if solved */ - if(Game.grid.gridSolved()){ - Game.solved(); - } + 'killDialog': function () { + + $('.input-dialog').fadeOut(200, function () { + $(this).remove(); + }); + }, + + 'getCellPosition': function (cell){ + + var $this = $(cell); + var $rows = $('.game-row'); + + for (var r = 0; r < 9; r++) { + + var $row = $($rows[r]); + var $cells = $row.children('.cell'); + for (var c = 0; c < 9; c++) { + + $cell = $($cells[c]); + + if ($cell.get(0) == $this.get(0)) { + + return [c,r]; + } + } } -}; + + return false; + }, -var Binds = { - /* binds for after table draw */ - tableBinds: function(){ - $('.cell:not(.game-value)').on('click', function(e){ - Binds.cellClick(this); - }); - $(document).off('keydown').on('keydown', function (e) { - if(!$(e.target).is('#options-wrap') && !$(e.target).is('.input-input')){ - var keyCode = e.keyCode || e.which, arrow = {left: 37, up: 38, right: 39, down: 40 }; - var arrows = [37,38,39,40]; - if(arrows.indexOf(keyCode) !== -1){ - e.preventDefault(); - } - switch (keyCode) { - case arrow.left: - Display.moveSelect('left'); - break; - case arrow.up: - Display.moveSelect('up'); - break; - case arrow.right: - Display.moveSelect('right'); - break; - case arrow.down: - Display.moveSelect('down'); - break; - case 13: - var $selected = $('.cell-selected'); - if($selected.length > 0){ - Display.entryDialog($selected.get(0)); - } - return false; /* do not pass enter/return through */ - } - /* enter cell values from the keyboard */ - if((keyCode > 47 && keyCode < 58) || (keyCode > 93 && keyCode < 106)){ - var $selected = $('.cell-selected:not(.game-value)'); - if($selected.length > 0){ - var value = String.fromCharCode((keyCode > 93 ? keyCode - 48 : keyCode)); - var pos = Display.getCellPosition($selected.get(0)); - Game.grid.setValue(pos[0],pos[1], value); - $cell.html((value === 0 ? '' : value)); - Display.findConflicts(); - Game.saveState(); - } - } - } - }); - }, - - optionBinds: function(){ - $('#opt-newpuzzle').on('click', function(){ - Timer.stop(); - Game.flushState(); - Game.start(); - }); - $('#opt-difficulty').on('change', function(){ - Timer.stop(); - Settings.difficulty = $(this).val(); - Game.flushState(); - Game.start(); - $(this).blur(); - }); - $('#opt-showhints').on('change', function(){ - Settings.show_conflicts = ($(this).is(':checked') ? true : false); - Display.findConflicts(); - }); - $('#opt-printpuzzle').on('click', function(){window.print();}); - }, + 'getCell': function (col, row) { + + var $rows = $('.game-row'); + for (var r = 0; r < 9; r++) { + + var $row = $($rows[r]); + var $cells = $row.children('.cell'); + + for (var c = 0; c < 9; c++) { + + $cell = $($cells[c]); + + if (col == c && row == r){ + + return $cell.get(0); + } + } + } + + return false; + }, + + 'moveSelect': function (direction) { + + var position = []; + + var $selected = $('.cell-selected'); + + if ($selected.length > 0) { + + position = this.getCellPosition($('.cell-selected').get(0)); + } + else { + + position = [0,0]; + } + + /* kill any open dialog */ + + this.killDialog(); + switch (direction) { + + case 'up': + + if (position[1] > 0) { + + position[1] -= 1; + } + break; + + case 'down': + + if (position[1] < 8) { + + position[1] += 1; + } + break; + + case 'right': + + if (position[0] < 8) { + + position[0] += 1; + } + break; + + case 'left': + + if (position[0] >0) { + + position[0] -= 1; + } + break; + } + + /* remove prev selection */ + $('.cell-selected').removeClass('cell-selected'); + + /* apply new selection */ + $(this.getCell(position[0], position[1])).addClass('cell-selected'); + }, + + /* highlight /all/ conflicting cells */ + 'findConflicts': function () { + + /* remove previous */ + $('.conflict').removeClass('conflict'); + + if (Settings.show_conflicts) { + + /* find conflicts */ + var $rows = $('.game-row'); + for (var r = 0; r < 9; r++) { + + var $row = $($rows[r]); + var $cells = $row.children('.cell'); + + for (var c = 0; c < 9; c++) { + + if (!Game.grid.cellValid(c, r)) { + + conflicts = true; + var $cell = $($cells[c]); + $cell.addClass('conflict'); + } + } + } + } - /* empty cell click */ - cellClick: function(elem){ - $('.cell').removeClass('cell-selected'); - $(elem).addClass('cell-selected'); - Display.entryDialog(elem); + /* check if solved */ + if (Game.grid.gridSolved()) { + + Game.solved(); } + } }; + +var Binds = { + + /* binds for after table draw */ + 'tableBinds': function () { -/* run */ -$(document).ready(function(){ - Game.start(); - Binds.optionBinds(); -}); + var $selected; + + $('.cell:not(.game-value)').on('click', function (e) { + + Binds.cellClick(this); + }); + + $(document).off('keydown').on('keydown', function (e) { + + if (!$(e.target).is('#options-wrap') && !$(e.target).is('.input-input')) { + + var keyCode = e.keyCode || e.which, arrow = {left: 37, up: 38, right: 39, down: 40 }; + var arrows = [37,38,39,40]; + + if (arrows.indexOf(keyCode) !== -1) { + + e.preventDefault(); + } + + switch (keyCode) { + + case arrow.left: + + Display.moveSelect('left'); + break; + + case arrow.up: + + Display.moveSelect('up'); + break; + + case arrow.right: + + Display.moveSelect('right'); + break; + + case arrow.down: + + Display.moveSelect('down'); + break; + + case 13: + + $selected = $('.cell-selected'); + if ($selected.length > 0) { + + Display.entryDialog($selected.get(0)); + } + return false; /* do not pass enter/return through */ + } + + /* enter cell values from the keyboard */ + if ((keyCode > 47 && keyCode < 58) || (keyCode > 93 && keyCode < 106)) { + + $selected = $('.cell-selected:not(.game-value)'); + + if ($selected.length > 0) { + + var value = String.fromCharCode((keyCode > 93 ? keyCode - 48 : keyCode)); + var pos = Display.getCellPosition($selected.get(0)); + Game.grid.setValue(pos[0],pos[1], value); + $cell.html((value === 0 ? '' : value)); + Display.findConflicts(); + Game.saveState(); + } + } + } + }); + }, + + 'optionBinds': function () { + + $('#opt-newpuzzle').on('click', function () { + + Timer.stop(); + Game.flushState(); + Game.start(); + }); + + $('#opt-difficulty').on('change', function () { + + Timer.stop(); + Settings.difficulty = $(this).val(); + Game.flushState(); + Game.start(); + $(this).blur(); + }); + + $('#opt-showhints').on('change', function () { + + Settings.show_conflicts = ($(this).is(':checked') ? true : false); + Display.findConflicts(); + }); + + $('#opt-printpuzzle').on('click', function () { + + window.print(); + }); + }, + + /* empty cell click */ + 'cellClick': function (elem) { + + $('.cell').removeClass('cell-selected'); + $(elem).addClass('cell-selected'); + Display.entryDialog(elem); + } +}; /* utils */ var Util = { - /* http://stackoverflow.com/a/1830844/933653 */ - isNumeric: function(n){ - return !isNaN(parseFloat(n)) && isFinite(n); - } -} + + /* http://stackoverflow.com/a/1830844/933653 */ + 'isNumeric': function (n) { + + return !isNaN(parseFloat(n)) && isFinite(n); + } +}; var Timer = { - start_time: null, - id: null, - callback: null, - - msToDuration: function(dur){ - var dur_s = dur / 1000; - var hours = Math.floor(dur_s / 3600); - var minutes = Math.floor((dur_s % 3600) / 60); - var seconds = Math.floor((dur_s % 3600) % 60); - - var str = ''; - str += (hours > 0) ? hours + ':' : '0:'; - str += (minutes > 0) ? (minutes < 10 ? '0' + minutes + ':' : minutes + ':') : '00:'; - str += (seconds > 0) ? (seconds < 10 ? '0' + seconds : seconds) : '00'; - - return str; - }, + + 'start_time': null, + 'id': null, + 'callback': null, - start: function(callback, offset){ - this.stop(); - this.callback = callback; - this.start_time = new Date();// - 3540000; test hour roll over - this.start_time = this.start_time - offset; - this.id = setInterval(Timer.run, 1000); - }, - stop: function(){ - if(this.id){ - clearInterval(this.id); - } - }, + 'msToDuration': function (dur) { + + var dur_s = dur / 1000; + var hours = Math.floor(dur_s / 3600); + var minutes = Math.floor((dur_s % 3600) / 60); + var seconds = Math.floor((dur_s % 3600) % 60); + + var str = ''; + str += (hours > 0) ? hours + ':' : '0:'; + str += (minutes > 0) ? (minutes < 10 ? '0' + minutes + ':' : minutes + ':') : '00:'; + str += (seconds > 0) ? (seconds < 10 ? '0' + seconds : seconds) : '00'; + + return str; + }, - run: function(){ - var now = new Date(); - Timer.callback([(Timer.msToDuration(now - Timer.start_time)), (now - Timer.start_time)]); + 'start': function (callback, offset){ + + this.stop(); + this.callback = callback; + this.start_time = new Date();// - 3540000; test hour roll over + this.start_time = this.start_time - offset; + this.id = setInterval(Timer.run, 1000); + }, + + 'stop': function (){ + + if (this.id) { + + clearInterval(this.id); } -} \ No newline at end of file + }, + + 'run': function () { + + var now = new Date(); + Timer.callback([(Timer.msToDuration(now - Timer.start_time)), (now - Timer.start_time)]); + } +}; \ No newline at end of file From 697a52cb5eacad2c5dc75502069b1a494acda9c0 Mon Sep 17 00:00:00 2001 From: Raymond May Jr Date: Sat, 9 Feb 2013 19:03:34 +0100 Subject: [PATCH 2/4] start modulization --- js/game.js | 56 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/js/game.js b/js/game.js index ce4e426..38cd678 100644 --- a/js/game.js +++ b/js/game.js @@ -587,13 +587,15 @@ var Util = { } }; -var Timer = { +var Timer = (function () { - 'start_time': null, - 'id': null, - 'callback': null, - - 'msToDuration': function (dur) { + var start_time = null; + var id = null; + var timerCallback = null; + var self; + + + function msToDuration (dur) { var dur_s = dur / 1000; var hours = Math.floor(dur_s / 3600); @@ -606,28 +608,36 @@ var Timer = { str += (seconds > 0) ? (seconds < 10 ? '0' + seconds : seconds) : '00'; return str; - }, - - 'start': function (callback, offset){ + } + + function start (callback, offset) { - this.stop(); - this.callback = callback; - this.start_time = new Date();// - 3540000; test hour roll over - this.start_time = this.start_time - offset; - this.id = setInterval(Timer.run, 1000); - }, + stop(); + timerCallback = callback; + start_time = new Date(); + start_time = start_time - offset; + id = setInterval(run, 1000); + } - 'stop': function (){ + function stop () { - if (this.id) { + if (id) { - clearInterval(this.id); + clearInterval(id); } - }, - - 'run': function () { + } + + function run () { var now = new Date(); - Timer.callback([(Timer.msToDuration(now - Timer.start_time)), (now - Timer.start_time)]); + if (timerCallback) { + + timerCallback([(msToDuration(now - start_time)), (now - start_time)]); + } } -}; \ No newline at end of file + return { + + 'start': start, + 'stop': stop + }; +})(); \ No newline at end of file From 6861c50d0f0d67802186d94a4e3ccff84b1fb4e7 Mon Sep 17 00:00:00 2001 From: Raymond May Jr Date: Sun, 10 Feb 2013 14:08:14 +0100 Subject: [PATCH 3/4] cleanup and organization --- js/game.js | 116 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 42 deletions(-) diff --git a/js/game.js b/js/game.js index 38cd678..c785ba5 100644 --- a/js/game.js +++ b/js/game.js @@ -4,20 +4,21 @@ * requires sudoku.js, jstorage */ -/* run */ +// Main $(document).ready(function () { Game.start(); Binds.optionBinds(); }); -/* defaults settings */ +// Default settings var Settings = { difficulty: 'medium', show_conflicts: false }; +// The Game var Game = { 'difficulties': { @@ -34,6 +35,7 @@ var Game = { 'game_values': [], 'time_elapsed': '', 's_elapsed': 0, + 'timer': null, // Start the game 'start': function () { @@ -44,32 +46,36 @@ var Game = { // Load previous game, or create a new one var loaded = this.loadState(); if (loaded) { - // load previous + // load previous values into memory this.grid.rows = this.game_values; } else { - // create a new game by culling full sudoku grid + // or create a new game by culling full sudoku grid CU.Sudoku.cull(this.grid, this.difficulties[Settings.difficulty]); } + // Setup display Display.gameTable(); - if (loaded) { - // insert and display stored user values + // display stored user values Display.loadUserValues(); } - // remove ending screen - $('.ending').fadeOut(function () { + // remove ending screen if visible + Display.hideEnding(); - $(this).remove(); - }); + // Start time elapsed display + this.startTimer(); + }, + + 'startTimer': function () { // reset timer display - $('#timer').html('0:00:00'); - - Timer.start(function (arr) { + Display.resetTimer(); + + this.timer = new Timer(); + this.timer.start(function (arr) { Display.timer(arr[0]); Game.time_elapsed = arr[0]; @@ -78,10 +84,18 @@ var Game = { }, Game.s_elapsed * 1000); }, + 'stopTimer': function () { + + if (this.timer) { + + this.timer.stop(); + } + }, + 'solved': function () { - Timer.stop(); - Display.end(); + this.stopTimer(); + Display.showEnding(); }, 'saveState': function () { @@ -240,7 +254,7 @@ var Display = { } }, - 'end': function () { + 'showEnding': function () { var dialog = $(document.createElement('div')).addClass('ending').hide(); var heading = $(document.createElement('h2')).html('Congratulations!'); @@ -259,10 +273,23 @@ var Display = { $('body').append(dialog.fadeIn()); }, + 'hideEnding': function () { + + $('.ending').fadeOut(function () { + + $(this).remove(); + }); + }, + 'timer': function (str) { $('#timer').text(str); }, + + 'resetTimer': function () { + + this.timer('0:00:00'); + }, 'entryDialog': function (cell) { @@ -319,6 +346,7 @@ var Display = { 'killDialog': function () { $('.input-dialog').fadeOut(200, function () { + $(this).remove(); }); }, @@ -383,8 +411,7 @@ var Display = { position = [0,0]; } - /* kill any open dialog */ - + // kill any open dialog this.killDialog(); switch (direction) { @@ -421,22 +448,22 @@ var Display = { break; } - /* remove prev selection */ + // remove prev selection $('.cell-selected').removeClass('cell-selected'); - /* apply new selection */ + // apply new selection $(this.getCell(position[0], position[1])).addClass('cell-selected'); }, - /* highlight /all/ conflicting cells */ + // highlight /all/ conflicting cells 'findConflicts': function () { - /* remove previous */ + // remove previous $('.conflict').removeClass('conflict'); if (Settings.show_conflicts) { - /* find conflicts */ + // find conflicts var $rows = $('.game-row'); for (var r = 0; r < 9; r++) { @@ -455,7 +482,7 @@ var Display = { } } - /* check if solved */ + // check if solved if (Game.grid.gridSolved()) { Game.solved(); @@ -465,7 +492,7 @@ var Display = { var Binds = { - /* binds for after table draw */ + // binds for after table draw 'tableBinds': function () { var $selected; @@ -516,10 +543,11 @@ var Binds = { Display.entryDialog($selected.get(0)); } - return false; /* do not pass enter/return through */ + // do not pass enter/return through + return false; } - /* enter cell values from the keyboard */ + // enter cell values from the keyboard if ((keyCode > 47 && keyCode < 58) || (keyCode > 93 && keyCode < 106)) { $selected = $('.cell-selected:not(.game-value)'); @@ -542,14 +570,14 @@ var Binds = { $('#opt-newpuzzle').on('click', function () { - Timer.stop(); + Game.stopTimer(); Game.flushState(); Game.start(); }); $('#opt-difficulty').on('change', function () { - Timer.stop(); + Game.stopTimer(); Settings.difficulty = $(this).val(); Game.flushState(); Game.start(); @@ -568,7 +596,7 @@ var Binds = { }); }, - /* empty cell click */ + // empty cell click 'cellClick': function (elem) { $('.cell').removeClass('cell-selected'); @@ -577,24 +605,13 @@ var Binds = { } }; -/* utils */ -var Util = { - - /* http://stackoverflow.com/a/1830844/933653 */ - 'isNumeric': function (n) { - - return !isNaN(parseFloat(n)) && isFinite(n); - } -}; - -var Timer = (function () { +var Timer = function () { var start_time = null; var id = null; var timerCallback = null; var self; - function msToDuration (dur) { var dur_s = dur / 1000; @@ -613,6 +630,7 @@ var Timer = (function () { function start (callback, offset) { stop(); + timerCallback = callback; start_time = new Date(); start_time = start_time - offset; @@ -635,9 +653,23 @@ var Timer = (function () { timerCallback([(msToDuration(now - start_time)), (now - start_time)]); } } + return { 'start': start, 'stop': stop }; +}; + +// general utilities +var Util = (function () { + + return { + + /* http://stackoverflow.com/a/1830844/933653 */ + 'isNumeric': function (n) { + + return !isNaN(parseFloat(n)) && isFinite(n); + } + }; })(); \ No newline at end of file From fa324e53963273bb0aff5f491f90084354be583e Mon Sep 17 00:00:00 2001 From: Raymond May Jr Date: Sun, 10 Feb 2013 15:27:54 +0100 Subject: [PATCH 4/4] further modulization --- js/game.js | 157 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 65 deletions(-) diff --git a/js/game.js b/js/game.js index c785ba5..04b89a0 100644 --- a/js/game.js +++ b/js/game.js @@ -4,6 +4,8 @@ * requires sudoku.js, jstorage */ +var game; + // Main $(document).ready(function () { @@ -19,39 +21,39 @@ var Settings = { }; // The Game -var Game = { +var Game = (function () { - 'difficulties': { + var difficulties = { 'test_solved': 1, 'easy': 20, 'medium': 40, 'hard': 55, 'expert': 64 - }, + }; - 'grid': {}, - 'user_values': [], - 'game_values': [], - 'time_elapsed': '', - 's_elapsed': 0, - 'timer': null, + var grid = {}; + var user_values = []; + var game_values = []; + var time_elapsed = ''; + var s_elapsed = 0; + var timer = null; // Start the game - 'start': function () { + function start () { // Initialize a full internal sudoku grid - this.grid = CU.Sudoku.generate(); + grid = CU.Sudoku.generate(); // Load previous game, or create a new one - var loaded = this.loadState(); + var loaded = loadState(); if (loaded) { // load previous values into memory - this.grid.rows = this.game_values; + grid.rows = game_values; } else { // or create a new game by culling full sudoku grid - CU.Sudoku.cull(this.grid, this.difficulties[Settings.difficulty]); + CU.Sudoku.cull(grid, difficulties[Settings.difficulty]); } // Setup display @@ -66,42 +68,43 @@ var Game = { Display.hideEnding(); // Start time elapsed display - this.startTimer(); - }, + startTimer(); + } - 'startTimer': function () { + function startTimer () { // reset timer display Display.resetTimer(); - this.timer = new Timer(); - this.timer.start(function (arr) { + timer = new Timer(); + timer.start(function (arr) { Display.timer(arr[0]); - Game.time_elapsed = arr[0]; - Game.s_elapsed = Math.floor(arr[1]/1000); - $.jStorage.set('s_elapsed', JSON.stringify(Game.s_elapsed)); - }, Game.s_elapsed * 1000); - }, + time_elapsed = arr[0]; + s_elapsed = Math.floor(arr[1]/1000); + $.jStorage.set('s_elapsed', JSON.stringify(s_elapsed)); + }, s_elapsed * 1000); + } - 'stopTimer': function () { + function stopTimer () { - if (this.timer) { + if (timer) { - this.timer.stop(); + timer.stop(); } - }, + } - 'solved': function () { + function solved () { - this.stopTimer(); + stopTimer(); Display.showEnding(); - }, + } - 'saveState': function () { + function saveState () { + + user_values = fillRows(); + game_values = fillRows(); - this.user_values = this.fillRows(); - this.game_values = this.fillRows(); var $rows = $('.game-row'); for (var r = 0; r < 9; r++) { @@ -115,29 +118,29 @@ var Game = { var value = parseInt($cell.text(), 10); if ($cell.is('.game-value')) { - this.game_values[r][c] = value; + game_values[r][c] = value; } else if (value > 0) { - this.user_values[r][c] = value; + user_values[r][c] = value; } } } - $.jStorage.set('game_values', JSON.stringify(this.game_values)); - $.jStorage.set('user_values', JSON.stringify(this.user_values)); - }, + $.jStorage.set('game_values', JSON.stringify(game_values)); + $.jStorage.set('user_values', JSON.stringify(user_values)); + } - 'loadState': function () { + function loadState () { var _game_values = JSON.parse($.jStorage.get('game_values')) || []; var _user_values = JSON.parse($.jStorage.get('user_values')) || []; - this.s_elapsed = 0; + s_elapsed = 0; if (_user_values.length > 0) { - this.user_values = _user_values; + user_values = _user_values; } else { @@ -146,29 +149,27 @@ var Game = { if (_game_values.length > 0) { - this.game_values = _game_values; + game_values = _game_values; } else { return false; } - this.s_elapsed = JSON.parse($.jStorage.get('s_elapsed')) || 0; + s_elapsed = JSON.parse($.jStorage.get('s_elapsed')) || 0; return true; - }, + } - 'flushState': function () { + function flushState () { $.jStorage.set('game_values', JSON.stringify([])); $.jStorage.set('user_values', JSON.stringify([])); $.jStorage.set('s_elapsed', '0'); - }, + } - /** - * return zero-filled grid array - * used by saveState - **/ - 'fillRows': function () { + // return zero-filled grid array + // used by saveState + function fillRows () { var rows = []; @@ -185,7 +186,33 @@ var Game = { return rows; } -}; + + return { + + // get access + 'getUserValues': function () { + + return user_values; + }, + 'getTimeElapsed': function () { + + return time_elapsed; + }, + + // public methods + 'flushState': flushState, + 'saveState': saveState, + 'solved': solved, + 'start': start, + 'stopTimer': stopTimer, + + // return internal sudoku grid object + 'getGrid': function () { + + return grid; + } + }; +}()); var Display = { @@ -204,9 +231,9 @@ var Display = { for (var c = 0; c < 9; c++) { var $td = $(document.createElement('td')).addClass('cell'); - if (Game.grid.rows[r][c] !== 0) { + if (Game.getGrid().rows[r][c] !== 0) { - $td.html(Game.grid.rows[r][c]).addClass('game-value'); + $td.html(Game.getGrid().rows[r][c]).addClass('game-value'); } if (r === 0) { @@ -245,10 +272,10 @@ var Display = { for (var c = 0; c < 9; c++) { - if (Game.user_values[r][c] > 0) { + if (Game.getUserValues()[r][c] > 0) { - $(this.getCell(c,r)).html(Game.user_values[r][c]); - Game.grid.rows[r][c] = Game.user_values[r][c]; + $(this.getCell(c,r)).html(Game.getUserValues()[r][c]); + Game.getGrid().rows[r][c] = Game.getUserValues()[r][c]; } } } @@ -258,7 +285,7 @@ var Display = { var dialog = $(document.createElement('div')).addClass('ending').hide(); var heading = $(document.createElement('h2')).html('Congratulations!'); - var text = $(document.createElement('p')).html('You solved this puzzle in ' + Game.time_elapsed); + var text = $(document.createElement('p')).html('You solved this puzzle in ' + Game.getTimeElapsed()); dialog.append(heading); dialog.append(text); @@ -266,7 +293,7 @@ var Display = { var tweet = $(document.createElement('p')); var link = $(document.createElement('a')).addClass('button'); - link.attr('href', 'http://twitter.com/home?status=I+finished+a+'+Settings.difficulty+'+sudoku+puzzle+in+'+encodeURI(Game.time_elapsed)+'++Try+and+beat+my+time+at+http%3A%2F%2Fsudokunomi.com'); + link.attr('href', 'http://twitter.com/home?status=I+finished+a+'+Settings.difficulty+'+sudoku+puzzle+in+'+encodeURI(Game.getTimeElapsed())+'++Try+and+beat+my+time+at+http%3A%2F%2Fsudokunomi.com'); link.text('Tweet your time!'); dialog.append(tweet.append(link)); @@ -326,14 +353,14 @@ var Display = { if($selected.length > 0){ var value = String.fromCharCode((keyCode > 93 ? keyCode - 48 : keyCode)); - Game.grid.setValue(pos[0],pos[1], value); + Game.getGrid().setValue(pos[0],pos[1], value); $this.html((value === 0 ? '' : value)); } } else { - Game.grid.setValue(pos[0],pos[1], 0); + Game.getGrid().setValue(pos[0],pos[1], 0); $this.empty(); } @@ -472,7 +499,7 @@ var Display = { for (var c = 0; c < 9; c++) { - if (!Game.grid.cellValid(c, r)) { + if (!Game.getGrid().cellValid(c, r)) { conflicts = true; var $cell = $($cells[c]); @@ -483,7 +510,7 @@ var Display = { } // check if solved - if (Game.grid.gridSolved()) { + if (Game.getGrid().gridSolved()) { Game.solved(); } @@ -556,7 +583,7 @@ var Binds = { var value = String.fromCharCode((keyCode > 93 ? keyCode - 48 : keyCode)); var pos = Display.getCellPosition($selected.get(0)); - Game.grid.setValue(pos[0],pos[1], value); + Game.getGrid().setValue(pos[0],pos[1], value); $cell.html((value === 0 ? '' : value)); Display.findConflicts(); Game.saveState();