Skip to content

Instantly share code, notes, and snippets.

@questsin
Created February 20, 2019 14:57
Show Gist options
  • Save questsin/448fddcb9a01f628a1e79c81b3f2dc49 to your computer and use it in GitHub Desktop.
Save questsin/448fddcb9a01f628a1e79c81b3f2dc49 to your computer and use it in GitHub Desktop.
'use strict';
/** Helper function for 2 leading zeros padding. */
var __pad2 = function __pad2(n) {
return ('00' + n).slice(-2);
};
/** Format how dates will be displayed. Used in the highscore list. */
var DATE_FMT = self.Intl ? new Intl.DateTimeFormat('de', {
year: 'numeric', month: '2-digit', day: '2-digit'
}) : { format: function format(tm) {
return __pad2(tm.getDate()) + '/' + __pad2(tm.getMonth() + 1) + '/' + tm.getFullYear();
} };
/* exported DATE_FMT */
/** Global constants for the chess pieces. Has to agree with chess.js. */
var PAWN = 'p';
var KNIGHT = 'n';
var BISHOP = 'b';
var ROOK = 'r';
var QUEEN = 'q';
var KING = 'k';
/* exported PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING */
/** Global constants for the chess player colors. */
var WHITE = 'w';
var BLACK = 'b';
/** All pieces in an ordered list */
var ALL_PIECES = ['wk', 'wq', 'wr', 'wb', 'wn', 'wp', 'bk', 'bq', 'br', 'bb', 'bn', 'bp'];
/* exported WHITE, BLACK, ALL_PIECES */
/***********************************************************************
* Constants for game events.
*/
/** A new game has started. */
var GAME_EVENT_START = 'START';
/** A game has ended by a winner or draw. */
var GAME_EVENT_END = 'END';
/** Undo of a move was requested. */
var GAME_EVENT_UNDO = 'UNDO';
/** Suggestion of a move. */
var GAME_EVENT_SUGGEST = 'SUGGEST';
/** The final dialog, which shows the results, has been dismissed. */
var GAME_EVENT_RESULTDLG_DISMISS = 'RESULTDLG_DISMISS';
/* exported GAME_EVENT_START, GAME_EVENT_END, GAME_EVENT_UNDO, GAME_EVENT_SUGGEST, GAME_EVENT_RESULTDLG_DISMISS */
/*************************************************************************
* Constant for display
*/
/** Class for squares on chessboard as defined by chessboard.js. */
var CSS_SQUARE_CLS = '.square-55d63';
/** Class to add to chess squares to mark them as a valid target for a move. */
var CSS_LEGAL_SQUARE_CLS = 'possible-target-square';
/* exported CSS_SQUARE_CLS, CSS_LEGAL_SQUARE_CLS */
/** HTML unicode chess symbols stored in a <color><piece>-property schema. */
var UNICODE_CHESS_SYMBOLS = {
wk: '&#9812;', wq: '&#9813;', wr: '&#9814;', wb: '&#9815;', wn: '&#9816;', wp: '&#9817;',
bk: '&#9818;', bq: '&#9819;', br: '&#9820;', bb: '&#9821;', bn: '&#9822;', bp: '&#9823;'
};
var CHEQ_TT_CHESS_SYMBOLS = {
wk: 'k', wq: 'q', wr: 'r', wb: 'b', wn: 'h', wp: 'p',
bk: 'l', bq: 'w', br: 't', bb: 'n', bn: 'j', bp: 'o'
};
/* Screen orientation is portrait. */
var SCREEN_PORTRAIT = 1;
/* Screen orientation is landscape. */
var SCREEN_LANDSCAPE = 2;
/* exported SCREEN_PORTRAIT, SCREEN_LANDSCAPE */
/** Test if the move was the move of the human player. */
function isPlayersMove(move) {
return move && move.color === chessieSettings.playerColor();
}
function isOpponentsMove(move) {
return !isPlayersMove(move);
}
function isPlayersColor(color) {
return color && color === chessieSettings.playerColor();
}
function isOpponentsColor(color) {
return isPlayersColor(oppositeColor(color));
}
function isPlayersPiece(piece) {
return piece.charAt(0) == chessieSettings.playerColor();
}
function oppositeColor(c) {
return c == WHITE ? BLACK : c == BLACK ? WHITE : null;
}
/* exported isOpponentsMove, isOpponentsColor, isPlayersPiece */
/** Evaluates if a move as provided by chess.js is a capture of an opponent's piece.*/
function isCapture(move) {
// flag contains either an 'c' (standard capture)
// or an 'e' (en passant capture)
return move && move.flags && move.flags.search(/e|c/) >= 0;
}
/* exported isCapture */
/**
* Generates an HTML fragment for display of a chess piece.
* The function accepts either a combined key 'bk' (black king) in the 1st argument
* or separately the color in the 1st and the piece in the second argument.
*
* @param {any} color color or the full piece with color
* @param {any} piece piece only, color needs to be set to 'b' or 'w'
*/
function pieceHtml(color, piece) {
var key = color && piece ? color + piece : color;
if (UNICODE_CHESS_SYMBOLS[key]) {
return pieceCheqTT(key);
} else {
return '';
}
}
/* exported pieceHtml */
function pieceHtmlUnicode(key) {
return '<span class="piecesymbol">' + UNICODE_CHESS_SYMBOLS[key] + '</span>';
}
function pieceCheqTT(key) {
return '<span class="piecesymbol cheqtt">' + CHEQ_TT_CHESS_SYMBOLS[key] + '</span>';
}
//# sourceMappingURL=globals.js.map
'use strict';
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Structure with all settings, stored locally to be provided
*/
var ChessieSettings = (function () {
function ChessieSettings() {
_classCallCheck(this, ChessieSettings);
this.name = 'Player';
this.sound = true;
this.color = 'w';
this.opponent = 'chessie';
this.level = 1;
this.hintsButton = true;
this.showLegalMoves = true;
this.language = null;
}
/** Returns the orientation of the board depending on the player's color. */
_createClass(ChessieSettings, [{
key: 'boardOrientation',
value: function boardOrientation() {
return this.color == 'w' ? 'white' : 'black';
}
}, {
key: 'playerColor',
value: function playerColor() {
switch (this.color) {
case 'w':case 'b':
return this.color;
default:
return 'w';
}
}
}, {
key: 'apply',
/** Applies the settings to the application for those settings that do have immediate
* consequences on the UI.
*/
value: function apply() {
$('#hintBtn').css('display', this.hintsButton ? 'block' : 'none');
}
}, {
key: 'fullLevelDescription',
get: function get() {
return 'Level: ' + this.level + ', Color: ' + this.color;
}
/**
* Load the settings from local storage. Creates a new settings objects if no
* settings object can be found in the local storage (bootstrap).
* @return {ChessieSettings} the settings
*/
}], [{
key: 'load',
value: function load() {
var retval = new ChessieSettings();
var savedSettings = localStorage.getItem('chessieSettings');
try {
Object.assign(retval, JSON.parse(savedSettings));
} catch (e) {
console.error('%s: Could not load saved settings... %s', e, savedSettings);
}
return retval;
}
}, {
key: 'save',
value: function save() {
localStorage.setItem('chessieSettings', JSON.stringify(chessieSettings));
}
}]);
return ChessieSettings;
})();
var chessieSettings = ChessieSettings.load();
chessieSettings.apply();
/** Show the game tab */
function hideSettings() {
$('#tabGame').tab('show');
}
$('#settingsBtn').on('click', showSettings);
/** Show the settings tab */
function showSettings() {
$('#optionsName').val(chessieSettings.name);
$('#optionsLanguage').val(chessieSettings.language || 'default');
$('#optionsSoundEnable').prop('checked', chessieSettings.sound);
$('input[name=optionsColor]').val([chessieSettings.color]);
$('input[name=optComputerPlayerMode]').val([chessieSettings.opponent]);
$('#optionsLevel').val(chessieSettings.level);
$('#optionsHintsEnable').prop('checked', chessieSettings.hintsButton);
$('#optionsHintsShowLegalMoves').prop('checked', chessieSettings.showLegalMoves);
$('#tabSettings').tab('show');
}
/* exported showSettings */
function showAbout() {
$('#tabAbout').tab('show');
}
$('#aboutSection').click(hideSettings);
/* exported showAbout */
function showRules() {
// extract the language without region from the i18n language code
var baseLang = (i18n.lng() || 'en').replace(/^([a-zA-Z]+).*/, '$1');
$('#tabRules').tab('show');
$('#rules').load('rules_' + baseLang + '.htm', function (response, status, xhr) {
if (status == 'error') {
console.error('Did not find rules in language %s. Loading default EN.', baseLang);
$('#rules').load('rules_en.htm');
}
});
}
$('#rules').on('click', '#rulesClose', hideSettings);
/* exported showRules */
$('#settingsOkBtn').click(function () {
chessieSettings.name = $('#optionsName').val();
chessieSettings.sound = $('#optionsSoundEnable').prop('checked');
// check if the language has changed
var oldLang = chessieSettings.language;
chessieSettings.language = parseLanguage($('#optionsLanguage').val());
if (oldLang != chessieSettings.language) {
initI18n();
}
// collect other settings
var restartRequired = false;
/** Function to call the setter and return true if the value was actually changed. */
function setConfigProperty(name, newValue) {
var oldVal = chessieSettings[name];
var changed = oldVal != newValue;
chessieSettings[name] = newValue;
return changed;
}
restartRequired = restartRequired || setConfigProperty('color', $('input[name=optionsColor]:checked').val());
// change level
setConfigProperty('opponent', $('input[name=optComputerPlayerMode]:checked').val());
chessieSettings.level = Number.parseInt($('#optionsLevel').val());
applyGameLevel();
// hints
chessieSettings.hintsButton = $('#optionsHintsEnable').prop('checked');
chessieSettings.showLegalMoves = $('#optionsHintsShowLegalMoves').prop('checked');
ChessieSettings.save();
chessieSettings.apply();
// if anything relevant has changed we'll ask if the game should start as a new game
if (restartRequired) {
if (gameStarted) {
bootbox.confirm($.t('gameend.settingschange'), function (result) {
if (result) {
newGame();
}
});
} else {
// game not yet started ...
initChessBoard();
}
}
});
function parseLanguage(s) {
var sTrimmed = s ? s.trim() : null;
if (sTrimmed == null || sTrimmed == '') {
return null;
} else if (sTrimmed.toLowerCase() == 'default') {
return null;
} else {
return sTrimmed;
}
}
// the 'game' tab needs to be resized after the containing tab is redisplayed
$('#settingsCancelBtn, #settingsOkBtn').click(function (e) {
hideSettings();
});
//# sourceMappingURL=settings.js.map
'use strict';
// Signal the application complete to the crosswalk browser 5s after start
if (window.screen.show) {
setTimeout(function () {
return window.screen.show();
}, 5000);
}
// initialize i18n
i18n.init({
resGetPath: 'locales/__ns__-__lng__.json',
ns: { namespaces: ['chessie'], defaultNs: 'chessie' },
fallbackLng: 'en',
useCookie: false,
lng: chessieSettings.language
});
function initI18n() {
// when i18next is initialized, translate the entire document body
i18n.setLng(chessieSettings.language);
i18n.init(function (err, t) {
$('body').i18n();
$('[data-popover-id]').each(function (i, e) {
var el = $(e);
var key = el.attr('data-popover-id');
el.popover('destroy');
el.html('<i class="fa fa-info-circle fa-fw"></i>');
// now this is funny - we must let some time pass before we can set a new popover
// after removal of existing ones... otherwise the new one will also be removed
// hence the - completely arbitrary value of a 2s delay, which will hopefully work on every device
setTimeout(function () {
el.popover({ title: $.t(key + '.title'), content: $.t(key + '.content'), trigger: 'focus', placement: 'bottom' });
}, 1000);
});
});
}
initI18n();
/**
* Screen orientation change event stream. Will provide the new orientation
* as value as either 1 (Portrait) or 2 (Landscape)
*/
var orientationChange = new Rx.Subject();
function windowOrientation() {
var aspectRatio = window.innerWidth / window.innerHeight;
return aspectRatio < 13 / 9 ? SCREEN_PORTRAIT : SCREEN_LANDSCAPE;
}
var currentWindowOrientation = windowOrientation();
var checkOrientation = function checkOrientation() {
var newWindowOrientation = windowOrientation();
if (currentWindowOrientation !== newWindowOrientation) {
currentWindowOrientation = newWindowOrientation;
$(window).trigger('jsfOrientationChange', newWindowOrientation);
orientationChange.onNext(newWindowOrientation);
}
};
Rx.Observable.fromEvent($(window), 'resize').debounce(200).subscribe(function () {
console.log('Resize occurred');
checkOrientation();
adaptBoardContainerSize();
chessBoard.resize();
});
orientationChange.subscribe(function (o) {
console.log('Orientation Change just now! bla' + (o == 1 ? 'Portrait' : 'Landscape'));
var oldCls = o == SCREEN_LANDSCAPE ? 'btn-group' : 'btn-group-vertical';
var newCls = o == SCREEN_LANDSCAPE ? 'btn-group-vertical' : 'btn-group';
$('#mainBtnGrp').removeClass(oldCls).addClass(newCls);
});
orientationChange.onNext(currentWindowOrientation);
function adaptBoardContainerSize() {
var ct = $('#board-outer-container');
var cpd = $('#capturedPiecesDisplay');
// calculate the optimum width for the board, based on the available with of its outer container
// it seems like the
var availableWidth = ct.innerWidth();
var availableHeight = ct.innerHeight();
// make a correction for the attached container with captured pieces,
// which resides below (PORTRAIT) or right of (LANDSCAPE) the chess board
switch (windowOrientation()) {
case SCREEN_PORTRAIT:
availableHeight -= cpd.height();break;
case SCREEN_LANDSCAPE:
availableWidth -= cpd.width();break;
default:
throw 'unknown scren orientation';
}
console.debug('outer container dimension: %d / %d', ct.innerWidth(), ct.innerHeight());
console.debug(' => calculating with: %d / %d', availableWidth, availableHeight);
// the board is rectangular, so we have to use the minimum of the available size
// whatever is left over will be added as half-left-margin to center the board
// we also subtract a few pixel in order to cater for the board's miscalculating
// behaviour when adding a border size of 2px on both sides
var newBoardSize = Math.min(availableWidth, availableHeight) - 2;
// by experience: the board size must be a multiple of 4... round down to nearest 4x
newBoardSize -= newBoardSize % 4;
console.debug(' => final width: %d', newBoardSize);
$('#board-container').width(newBoardSize, newBoardSize);
$('#board-container').css('margin-left', (availableWidth - newBoardSize) / 2);
}
// the 'game' tab needs to be resized after the containing tab is redisplayed
$('#tabGame').on('shown.bs.tab', function (e) {
adaptBoardContainerSize();
chessBoard.resize();
});
var toastEl = $('#toast');
var toastTxtFld = $('#toastTxtFld');
/** A toast function to display information about scores and other
* events of interest to the user. Text will be displyed in the footer.
*/
function toast(text) {
toastEl.addClass('fade');
Rx.Observable.timer(200).subscribe(function () {
toastTxtFld.html(text);
toastEl.removeClass('fade');
});
}
/* exported toast */
// initialize the TWEEN library with a timer
var absTime = Rx.Observable.interval(50 /*ms*/);
absTime.subscribe(function (t) {
return TWEEN.update(performance.now());
});
var appMenuEl = $('#appMenu');
var menuToggleEl = $('#menuToggle');
// pushmenu functions
/** When the user selects the classic 'toggle' icon on the top left.
* Use CSS animation to open the menu using the classes pushmenu- 'open' / 'right'.
*/
function pushmenuToggle(e) {
// prevent that the click also triggers the pushmenuHide()
// which is activated as a click trigger on the entire document body
e.stopPropagation();
$(document.body).toggleClass('pushmenu-right');
appMenuEl.toggleClass('pushmenu-open');
}
/** The */
function pushmenuHide(e) {
$(document.body).removeClass('pushmenu-right');
appMenuEl.removeClass('pushmenu-open');
}
menuToggleEl.click(pushmenuToggle);
$(document.body).click(pushmenuHide);
/** Method to center all modals on the scree when they are being
* displayed. If no such shift is done, the modals are placed
* so much to the top of the page that is esthetically less pleasing.
*/
(function ($) {
'use strict';
function centerModal() {
$(this).css('display', 'block');
var $dialog = $(this).find('.modal-dialog'),
offset = ($(window).height() - $dialog.height()) / 4,
bottomMargin = parseInt($dialog.css('marginBottom'), 10);
// Make sure you don't hide the top part of the modal w/ a negative margin if it's longer than the screen height, and keep the margin equal to the bottom margin of the modal
if (offset < bottomMargin) offset = bottomMargin;
$dialog.css('margin-top', offset);
}
$(document).on('show.bs.modal', '.modal', centerModal);
$(window).on('resize', function () {
return $('.modal:visible').each(centerModal);
});
$('[data-toggle="popover"]').popover();
})(jQuery);
// send an UNDO event when the undo button is clicked
$('#undoBtn').click(function () {
return sendGameEvent(GAME_EVENT_UNDO);
});
// send an SUGGEST event when the hint button is clicked
$('#hintBtn').click(function () {
return sendGameEvent(GAME_EVENT_SUGGEST);
});
// remove the focus from all clicked buttons to prevent
// them from being framed by the 'current focus' rectangle
$('button').click(function (e) {
return $(e.currentTarget).blur();
});
// when the user clicks on the chess board and no game is
// currently in progress, we'll ask if we should start one
$('#board').click(function () {
if (!gameStarted) {
bootbox.confirm($.t('gameend.nogamestarted'), function (okSelected) {
if (okSelected) {
newGame();
}
});
}
});
/** Prevents user input to the UI by stopping pointer-events on the document body. */
function lockMainUi() {
var lock = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];
$(document.body).css('pointer-events', lock ? 'none' : 'auto');
}
/* exported lockMainUi */
/** Do some fancy animation to indicate that the AI player is thinking hard. */
function showAiPlayerThinkingAnimation() {
var show = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];
$('#aiPlayerThinking').css('visibility', show ? 'visible' : 'hidden');
}
/* exported showAiPlayerThinkingAnimation */
/** Reveal one of the alternative bottom panels which either ho*/
function displayBottomPaneEl(el, display) {
el.css('display', display ? 'flex' : 'none');
setTimeout(function () {
return el.css('opacity', display ? 1 : 0);
}, 100);
}
function showGameEndPanel() {
//$('#gameHistoryBtn').attr('disabled', hasMoveHistory() ? null : 'disabled');
displayBottomPaneEl($('#controlsbox'), false);
displayBottomPaneEl($('#gameEndPanel'), true);
}
function hideGameEndPanel() {
displayBottomPaneEl($('#gameEndPanel'), false);
displayBottomPaneEl($('#controlsbox'), true);
}
/* exported showGameEndPanel, hideGameEndPanel*/
// --- remote logging for errors in order to provide hints about what can break in the app
var loggly = new LogglyTracker();
loggly.push({ tag: 'chessie', logglyKey: 'bcf090ec-6bb7-4fe5-a2c2-6f1eab4fbd7c', sendConsoleErrors: false });
function errorReportingOnErrorHandler(msg, url, line, col, err) {
loggly.push({
category: 'UncaughtJSException',
exception: {
message: msg,
url: url,
lineno: line,
colno: col
},
stack: err ? err.stack : ''
});
}
window.onerror = errorReportingOnErrorHandler;
//# sourceMappingURL=main.js.map
'use strict';
/** Interval that is used when pieces are moved over the board. */
var MOVE_ANIMATION_DURATION = 400;
/** Display time of a hint. */
var HINT_DISPLAY_TIME = 200;
/** Time to let the computer wait before a move is carried out by the computer player.*/
var COMPUTER_PLAYER_THINK_TIME = 100;
/* Chess.js class to track the game and give insights into positions and pieces. */
var game = new Chess();
/** Chessboard.js instance, to draw the game's status. */
var chessBoard = undefined;
/** This object keeps track of all pieces that were captured during the game.
* The number of pieces are stored in a property = <color><piece>, value = number of captures. */
var capturedPieces = {};
/** Global game status - is a game currently going on, or not yet/already finished. */
var gameStarted = false;
// RX Subjects to control the game
/** The events stream with all moves. Provides the moves from both players.
* Stream values are the chess.js move objects such as
* { color: 'w', from: 'a2', to: 'a3', flags: 'n', piece: 'p', san 'a3' }
* plus additional attributes { id: 1674, tm: 3487298472, duration: 1031 }.
* Publish to the subject only with the method sendNext (defined below)!
*/
var rxMoves = new Rx.Subject();
/** All events related to points contributing to the score of the game.
* Stream values are { basePoints: n, multiplier: m, totalPoints: p }
*/
var rxGameScore = new Rx.Subject();
/* exported rxGameScore */
/** Events to notify the game's end = winning or losing.
* The value object is { winner: 'w' / 'b', score: final score }
*/
var rxGameEvents = new Rx.Subject();
rxGameEvents.subscribe(function (e) {
return console.log('Game event %s: %o', e.event, e);
});
// create the background thread for the AI player
var aiPlayer = new Worker('scripts/chessie-ai2.js');
// translate post-back messages into events on the rx subject
var rxAiPlayerEvents = new Rx.Subject();
aiPlayer.onmessage = function (e) {
return rxAiPlayerEvents.onNext(e);
};
// notify the AI player about every move
rxMoves.subscribe(function (m) {
return aiPlayer.postMessage({ type: 'MOVE', from: m.from, to: m.to });
});
/** Sends a game event on the event stream and puts it into the window timeout queue
* for processing after the sending thread has ended.
*/
function sendGameEvent(event, data) {
data = data || {};
data.event = event;
window.setTimeout(function () {
return rxGameEvents.onNext(data, 0);
});
}
/** Registers a game event listener for a certain game event type. */
function listenToGameEvent(filter, callback) {
if (typeof filter === 'function') {
rxGameEvents.filter(filter).subscribe(callback);
} else {
rxGameEvents.filter(function (e) {
return filter == null || e.event == filter;
}).subscribe(callback);
}
}
/** Event stream for piece selection, i.e. tipping on one of one's own pieces. */
var rxBoardTouchEvents = new Rx.Subject();
/** Returns the square's address ('a5', 'f3', ...) from the DIV elements of the chess board.*/
function getSquareAddress(squareDivEl) {
return squareDivEl.attr('data-square');
}
/** Register handler on document ready - creating the chess board for display. */
$(document).ready(function () {
var cfg = {
draggable: true,
orientation: chessieSettings.boardOrientation(),
position: 'start',
onDragStart: onDragStart,
onDrop: onDrop,
onSnapEnd: onSnapEnd,
moveSpeed: MOVE_ANIMATION_DURATION,
sparePieces: false,
pieceTheme: 'images/chesspieces/wikipedia/{piece}.png'
};
adaptBoardContainerSize();
chessBoard = new ChessBoard('board', cfg);
$('#board').on('click', CSS_SQUARE_CLS, function (e) {
var target = $(e.target).closest(CSS_SQUARE_CLS).attr('data-square');
rxBoardTouchEvents.onNext({ type: 'square', target: target });
});
// create div-containers for the display of individual captured chess pieces
ALL_PIECES.forEach(function (p) {
$('#capturedPiecesDisplay').append('<div id="captured-' + p + '" style="display: none">' + pieceHtml(p) + '</div>');
});
$('#newGameBtn').click(newGame);
$('#highScoresBtn').click(function (e) {
return $('#highscores').modal('show');
});
$('#gameHistoryBtn').click(function (e) {
return showMoveHist();
});
});
function initChessBoard() {
chessBoard.clear(true);
chessBoard.orientation(chessieSettings.boardOrientation());
chessBoard.start(true);
}
/**
* Start a new game. This function will reset all the global state to the
* initial values and prepare the board for playing the game.
*/
function newGame() {
gameStarted = false;
$('#tabGame').tab('show');
game = new Chess();
initChessBoard();
resetCapturedPieces();
aiPlayer.postMessage({ type: 'RESET' });
scoreboard.reset();
scoreMultiplier.reset();
clearMoveHistory();
hideGameEndPanel();
gameStarted = true;
sendGameEvent(GAME_EVENT_START);
// start from here when the computer is white
if (isOpponentsColor('w')) {
makeOpponentsMove();
}
}
function applyGameLevel() {
aiPlayer.postMessage({ type: 'SET_ENGINE', opponent: chessieSettings.opponent, level: chessieSettings.level });
var levelChr = '&#' + (9312 /* encircled 1 in unicode */ + parseInt(chessieSettings.level) - 1) + ';';
$('#computerPlayerLevel').html(levelChr);
$('#computerPlayerType').removeClass('fa-child fa-mortar-board');
$('#computerPlayerType').addClass(chessieSettings.opponent == 'chessie' ? 'fa-child' : 'fa-mortar-board');
}
// initialize the levels and apply the loaded game level
applyGameLevel();
/** Sends the next move message out. This function will add important attributes:
* (1) a unique identifier (by using a simple integer counter) that allows to
* refer to moves unambigously
* (2) a timestamp, when the move was sent out to the stream
* (3) the duration it took between this move and the last move
*/
rxMoves.sendNext = function (move) {
this.idCounter = this.idCounter ? this.idCounter + 1 : 1;
move.id = this.idCounter;
move.tm = Date.now();
move.duration = this.lastSendTm ? move.tm - this.lastSendTm : undefined;
this.lastSendTm = move.tm;
this.onNext(move);
};
/** Check for game over by listening on the move and testing if more moves are available. */
rxMoves.subscribe(function (move) {
if (game.game_over() == true) {
var winner = game.in_draw() ? '-' : move.color;
if (game.in_checkmate()) {
var reason = $.t('gameend.checkmate');
} else if (game.in_stalemate()) {
reason = $.t('gameend.stalemate');
} else if (game.in_threefold_repetition()) {
reason = $.t('gameend.threefoldRepetition');
} else if (game.insufficient_material()) {
reason = $.t('gameend.insufficientMaterial');
} else if (game.history.length >= 50) {
reason = $.t('gameend.tooManyMoves');
} else {
reason = $.t('gameend.unknown');
}
sendGameEvent(GAME_EVENT_END, { winner: winner, reason: reason, score: scoreboard.score });
}
});
/** Main reaction on game end: display a message. */
listenToGameEvent(GAME_EVENT_END, function (r) {
gameStarted = false;
showGameEndPanel();
});
// do not pick up pieces if the game is over
// only pick up pieces for White
var onDragStart = function onDragStart(source, piece, position, orientation) {
if (!gameStarted || game.game_over() || !isPlayersPiece(piece)) {
return false;
}
};
function makeOpponentsMove() {
var delay = arguments.length <= 0 || arguments[0] === undefined ? COMPUTER_PLAYER_THINK_TIME : arguments[0];
showAiPlayerThinkingAnimation(true);
lockMainUi(true);
setTimeout(function () {
return aiPlayer.postMessage({ type: 'SUGGEST_MOVE', fen: game.fen() });
}, delay);
}
/** Callback on events from the AI player, running as a background thread */
rxAiPlayerEvents.filter(function (e) {
return e.data.type == 'SUGGEST_MOVE';
}).subscribe(function (e) {
showAiPlayerThinkingAnimation(false);
// do the move
var pickedMove = e.data.move;
if (pickedMove) {
var move = game.move(pickedMove);
if (move == null) {
throw 'Illegal move attempted by computer player!';
}
chessBoard.move(pickedMove.from + '-' + pickedMove.to);
rxMoves.sendNext(move);
}
// unlock the UI
lockMainUi(false);
});
function showPlayersPossibleMoves(fromSquare) {
if (chessieSettings.showLegalMoves) {
game.moves({ square: fromSquare, verbose: true }).forEach(function (s) {
squareEl(s.to).addClass(CSS_LEGAL_SQUARE_CLS);
});
}
}
function hidePlayersPossibleMoves() {
$(CSS_SQUARE_CLS).removeClass(CSS_LEGAL_SQUARE_CLS);
}
var selectedSquare = null;
function squareEl(target) {
return $('#board .square-' + target);
}
function selectSquare(target) {
unselectSquare();
var square = squareEl(target);
square.addClass('selected-square');
selectedSquare = square;
showPlayersPossibleMoves(getSquareAddress(square));
}
function unselectSquare() {
if (selectedSquare) {
selectedSquare.removeClass('selected-square');
selectedSquare = null;
hidePlayersPossibleMoves();
}
}
// any move taken will reset the selection
rxMoves.subscribe(unselectSquare);
rxBoardTouchEvents.subscribe(function (e) {
// when the type of the event is 'square' we will move the selected piece
// to this target (if there is a selected piece)
if (e.type == 'square') {
if (selectedSquare) {
var source = selectedSquare.attr('data-square');
onDrop(source, e.target, false);
chessBoard.position(game.fen());
}
// and remove the selection
unselectSquare();
} else if (e.type == 'piece') {
selectSquare(e.target);
}
});
function onDrop(source, target) {
var calledAsBoardEvent = arguments.length <= 2 || arguments[2] === undefined ? true : arguments[2];
if (source == target) {
rxBoardTouchEvents.onNext({ type: 'piece', target: target });
return;
}
// see if the move is legal
var move = game.move({
from: source,
to: target,
promotion: 'q' // NOTE: always promote to a queen for simplicity
});
if (move === null) {
// illegal move
return 'snapback';
} else {
rxMoves.sendNext(move);
}
// when this method has been called as a result of a chessboard drop event
// there is going to be no animation end event (as there was no animation)
// we'll generate such an event manually
if (!game.game_over()) {
makeOpponentsMove(calledAsBoardEvent ? COMPUTER_PLAYER_THINK_TIME : COMPUTER_PLAYER_THINK_TIME + MOVE_ANIMATION_DURATION);
}
}
/** Update the board position after the piece snap for castling, en passant, pawn promotion. */
function onSnapEnd() {
chessBoard.position(game.fen());
}
/** Opposite of the above: remove history entries including the last player's move. */
listenToGameEvent(GAME_EVENT_UNDO, function (e) {
var move = undefined;
do {
move = game.undo();
updateCapturedPiece(move, true);
} while (move != null && !isPlayersColor(game.turn()));
chessBoard.position(game.fen(), true);
updateGameAlerts();
// if we moved back to the beginning and the computer has white, we'll have to start again
if (isOpponentsColor(game.turn())) {
setTimeout(makeOpponentsMove, MOVE_ANIMATION_DURATION);
}
});
/** Called when the player selects the 'gimme a hint'-button.
* Uses the real chess player engine to suggest a simple, but reasonable move.
*/
listenToGameEvent(GAME_EVENT_SUGGEST, function () {
aiPlayer.postMessage({ type: 'HINT', fen: game.fen() });
});
/** Handler for the incoming hints from the web worker. */
rxAiPlayerEvents.filter(function (e) {
return e.data.type == 'HINT';
}).subscribe(function (e) {
if (isPlayersColor(game.turn())) {
(function () {
var hintMove = e.data.move;
var fen = game.fen();
if (game.move(hintMove)) {
var hintFen = game.fen();
game.undo();
chessBoard.position(hintFen, true);
setTimeout(function () {
return chessBoard.position(fen, true);
}, HINT_DISPLAY_TIME + MOVE_ANIMATION_DURATION);
}
})();
}
});
/** Sound effect when either the human or the computer player makes a move. */
var sndHumanPlayer = new Audio('sound/laptop_notebook_return_or_enter_key_press.mp3');
var sndComputerPlayer = new Audio('sound/laptop_notebook_delete_key_press.mp3');
// shift the volume to make the sound a bit softer - we don't want to click so loudly
[sndHumanPlayer, sndComputerPlayer].forEach(function (s) {
return s.volume = 0.25;
});
/** Subscribe to the move events and play a sound when a move happens. */
rxMoves.subscribe(function (m) {
if (chessieSettings.sound) {
(function () {
// chose the sound and the delay depending on who took the move
// the human player is greeted immediately wherease the computer
// player will give its sound only when the move animation finished
var snd = isPlayersMove(m) ? sndHumanPlayer : sndComputerPlayer;
var tim = isPlayersMove(m) ? 0 : MOVE_ANIMATION_DURATION;
// schedule the sound at the end of the move animation
setTimeout(function () {
return snd.play();
}, tim);
})();
}
});
/**
* Keep track of captured pieces.
* @param {Object} move object
* @param {boolean} undo=false set to true when the move should be subtracted due to an undo
*/
function updateCapturedPiece(move) {
var undo = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
if (isCapture(move)) {
var key = oppositeColor(move.color) + move.captured;
var count = (capturedPieces[key] || 0) + (undo ? -1 : 1);
capturedPieces[key] = count;
console.debug('piece capture update for %s - %d', key, capturedPieces[key]);
// update the element that shows the capture cound
var el = $('#captured-' + key);
el.css('display', count > 0 ? 'block' : 'none');
el.html(pieceHtml(key) + '<sub>' + count + '</sub>');
}
}
/** Hides all captured piece divs and sets the counters to 0. */
function resetCapturedPieces() {
$('#capturedPiecesDisplay div').css('display', 'none');
ALL_PIECES.forEach(function (p) {
return capturedPieces[p] = 0;
});
}
// update the list of captured pieces on every move
// note that undoing a move is handled separately in the corresponding UNDO handler
rxMoves.subscribe(function (m) {
return updateCapturedPiece(m);
});
// display chess flags for being 'in check' and others
var gameAlerts = $('#gameAlerts');
function updateGameAlerts() {
if (!game.game_over() && game.in_check()) {
var key = game.turn() + 'k';
gameAlerts.html('' + pieceHtml(key));
} else {
gameAlerts.html('');
}
}
// after every move, update the game alert status icons
rxMoves.subscribe(function (m) {
return updateGameAlerts();
});
// report detailed errors
rxAiPlayerEvents.filter(function (e) {
return e.data.type == 'ERROR';
}).subscribe(function (e) {
// forward to reporting error handler with a faked
// error object that has nothing but the reported stack
var d = e.data;
errorReportingOnErrorHandler(d.message, d.url, d.line, d.column, { stack: d.stack });
});
//# sourceMappingURL=game.js.map
'use strict';
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Global score display board.
*/
var scoreboard = {
score: 0,
moves: 0,
reset: function reset() {
this.score = 0;
this.displayScoreInternal = 0;
this.moves = 0;
this.updateDisplay();
},
incrementMoves: function incrementMoves() {
var num = arguments.length <= 0 || arguments[0] === undefined ? 1 : arguments[0];
this.moves += num;
this.updateDisplay();
},
decrementMoves: function decrementMoves() {
var num = arguments.length <= 0 || arguments[0] === undefined ? 1 : arguments[0];
this.moves -= num;
this.updateDisplay();
},
addPoints: function addPoints(score) {
var p = Math.floor(score.totalPoints);
this.score += p;
if (p > 0) {
toast(score.basePoints + ' (base) &times; ' + score.multiplier.toFixed(2) + ' (time) = ' + score.totalPoints);
}
this.updateDisplay();
},
updateDisplay: function updateDisplay() {
$('#movesFld').html(this.moves);
this.tween = new TWEEN.Tween(this).to({ displayScore: this.score }, 200).easing(TWEEN.Easing.Exponential.In);
this.tween.start();
},
get displayScore() {
return this.displayScoreInternal;
},
set displayScore(val) {
this.displayScoreInternal = Math.round(val);
$('#scoreFld').html(this.displayScoreInternal);
}
};
rxMoves.filter(function (move) {
return isPlayersMove(move);
}).subscribe(function () {
return scoreboard.incrementMoves();
});
rxGameScore.subscribe(function (score) {
return scoreboard.addPoints(score);
});
/** The table with score points by piece. */
var BASE_POINTS_BY_PIECE = {};
BASE_POINTS_BY_PIECE[PAWN] = 5;
BASE_POINTS_BY_PIECE[KNIGHT] = 15;
BASE_POINTS_BY_PIECE[BISHOP] = 20;
BASE_POINTS_BY_PIECE[ROOK] = 30;
BASE_POINTS_BY_PIECE[QUEEN] = 50;
BASE_POINTS_BY_PIECE[KING] = 100;
function basePointsForMove(move) {
var points = BASE_POINTS_BY_PIECE[move.captured];
return points || 0;
}
/** Game scoring function: we'll award points for good moves.
*/
rxMoves.subscribe(function (move) {
var points = 0;
if (isPlayersMove(move)) {
// we'll award 5 points for every capture of an opponent's figure
if (isCapture(move)) {
points += basePointsForMove(move);
}
} else {
// we'll award 2x points whenever the opponent was forced to capture one of our pieces
if (isCapture(move)) {
points += 2 * basePointsForMove(move);
}
}
// now combine the points and the time-factor multiplier into a score event
// and send the score event out over the RxJs stream
var factor = Number(scoreMultiplier.factor.toFixed(2));
var score = {
move: move,
basePoints: points,
multiplier: factor,
totalPoints: Math.floor(points * factor)
};
rxGameScore.onNext(score);
});
var timerProgressBar = $('#timer');
var ScoreMultipier = (function () {
function ScoreMultipier(top, countDownTime) {
_classCallCheck(this, ScoreMultipier);
this.top = top;
this.countDownTime = countDownTime;
this.pct = 100;
}
_createClass(ScoreMultipier, [{
key: 'reset',
value: function reset() {
stopTimer();
this.pct = 100;
}
}, {
key: 'pct',
set: function set(val) {
this._pct = val;
timerProgressBar.width(this._pct + '%');
timerProgressBar.html(this.factor.toFixed(1) + 'x');
},
get: function get() {
return this._pct;
}
}, {
key: 'factor',
get: function get() {
return this.pct / 100 * this.top;
}
}]);
return ScoreMultipier;
})();
/** Time is connected with a multiplier, which starts with the factor 5
* and is running down to 0 over a certain time period.
*/
var scoreMultiplier = new ScoreMultipier(5, 60 * 1000);
var scoreMultTween = null;
function stopTimer() {
if (scoreMultTween) {
scoreMultTween.stop();
scoreMultTween = null;
}
}
function startTimer() {
stopTimer();
scoreMultiplier.reset();
scoreMultTween = new TWEEN.Tween(scoreMultiplier).to({ pct: 0 }, scoreMultiplier.countDownTime).easing(TWEEN.Easing.Exponential.Out);
scoreMultTween.start();
}
rxMoves.filter(function (m) {
return isOpponentsMove(m);
}).subscribe(startTimer);
rxMoves.filter(function (m) {
return isPlayersMove(m);
}).subscribe(stopTimer);
//# sourceMappingURL=score.js.map
'use strict';
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*
* Highscore list handling functions
*/
var HS_MAX_ELEMENTS = 20;
var hsTableEl = $('#highscoresTbl');
var hsTableRowFrag = $('<tr><td></td><td></td><td align="right"></td><td align="center"></td></tr>');
var HsItem = function HsItem(name, score) {
_classCallCheck(this, HsItem);
// take over the initializer arguments
this.name = name;
this.score = score;
// computed attributes: date is initialized with current timestamp
// and the rank is set to 0 (will be assigned later when sorted)
this.tm = new Date();
this.rank = 0;
};
/** Saved high-scores, loaded from local storage. */
var highScores = JSON.parse(localStorage.getItem('highScores')) || [];
highScores.forEach(function (h) {
if (typeof h.tm == 'string') h.tm = new Date(h.tm);
});
renderHighScores();
function addHighScore(name, score) {
var entry = new HsItem(name, score);
highScores.push(entry);
highScores.sort(function (i1, i2) {
return i2.score - i1.score;
});
highScores.forEach(function (item, index) {
return item.rank = index + 1;
});
highScores = highScores.slice(0, HS_MAX_ELEMENTS);
localStorage.setItem('highScores', JSON.stringify(highScores));
}
/** Returns the position in which the score would go into the high score list.
*/
function rankOfScore(score) {
var i = highScores.findIndex(function (i) {
return i.score <= score;
});
return i < 0 ? highScores.length : i;
}
function renderHighScores() {
hsTableEl.find('tr').remove();
highScores.forEach(function (i) {
var tr = hsTableRowFrag.clone();
var tds = tr.children();
$(tds[0]).text(i.rank);
$(tds[1]).text(i.name);
$(tds[2]).text(i.score);
$(tds[3]).text(DATE_FMT.format(i.tm));
hsTableEl.append(tr);
});
}
function gameEndSmiley(winner) {
if (isPlayersColor(winner)) {
return '<i class="fa fa-smile-o fa-lg"></i>';
} else if (isOpponentsColor(winner)) {
return '<i class="fa fa-frown-o fa-lg"></i>';
} else {
return '<i class="fa fa-balance-scale fa-lg"></i>';
}
}
/** A decent handling of the game's end... */
listenToGameEvent(GAME_EVENT_END, function (r) {
var simeleyHtml = gameEndSmiley(r.winner);
toast(simeleyHtml + ' ' + r.reason);
var endComment = undefined;
if (isPlayersColor(r.winner)) {
endComment = $.t('gameend.messageWin');
} else if (isOpponentsColor(r.winner)) {
endComment = $.t('gameend.messageLose');
} else {
endComment = $.t('gameend.messageDraw');
}
var dlg = $('#gameEndModal');
dlg.find('h4').html(simeleyHtml + ' ' + endComment);
dlg.find('#endDlgReason').text(r.reason);
dlg.find('#endDlgScore').text($.t('gameend.achievedScore', { points: r.score }));
dlg.find('input').val(chessieSettings.name);
dlg.modal('show');
var isNewHighScore = rankOfScore(r.score) < HS_MAX_ELEMENTS;
dlg.find('#highScoreSection').css('display', isNewHighScore ? 'block' : 'none');
var modalBtn = dlg.find('button');
modalBtn.off();
modalBtn.click(function () {
var name = dlg.find('input').val();
addHighScore(name || '-', r.score);
renderHighScores();
dlg.modal('hide');
$('#highscores').modal('show');
});
});
// fire the dismiss-result-dialog event when the result dialog has been removed
$('#gameEndModal').on('hidden.bs.modal', function () {
return sendGameEvent(GAME_EVENT_RESULTDLG_DISMISS);
});
//# sourceMappingURL=highscores.js.map
'use strict';
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*
* Keeper of the move history.
*/
var moveHistory = [];
/* exported hasMoveHistory */
function hasMoveHistory() {
return moveHistory.length > 0;
}
var mhTableEl = $('#movehistoryTable tbody');
var mhTableRowFrag = $('<tr><td></td><td class="center"></td><td></td><td class="center"></td><td></td><td></td><td></td><td></td></tr>');
/** Captures a move of either the player or the oponent.
* Moves of players will have the extra information about the score
* which was achieved with the move.
*/
var MhEntry = (function () {
function MhEntry(num, move, score) {
_classCallCheck(this, MhEntry);
console.assert(move.from != null, 'not a move object');
this.number = num;
this.tr = null;
// copy all move attributes and the score
for (var attr in move) {
this[attr] = move[attr];
} // the player's moves are constructed with a score element
if (score) {
for (var attr in score) {
this[attr] = score[attr];
}
} else {
this.basePoints = '';
this.multiplier = '';
this.totalPoints = '';
}
}
_createClass(MhEntry, [{
key: 'toRow',
value: function toRow() {
var tr = mhTableRowFrag.clone();
var tds = tr.children();
var i = 0;
$(tds[i++]).html(this.number);
$(tds[i++]).html(pieceHtml(this.color, this.piece));
$(tds[i++]).html(this.from + '-' + this.to);
$(tds[i++]).html(pieceHtml(this.opponentColor, this.captured));
$(tds[i++]).html(this.durationHtml);
$(tds[i++]).html(this.basePointsHtml);
$(tds[i++]).html(this.multiplierHtml);
$(tds[i++]).html(this.totalPointsHtml);
return tr;
}
}, {
key: 'opponentColor',
get: function get() {
return this.color == 'w' ? 'b' : 'w';
}
}, {
key: 'durationHtml',
get: function get() {
if (isOpponentsMove(this) || !this.duration) {
return '';
}
var s = this.duration / 1000.;
if (s < 1) {
return '< 1s';
} else if (s < 60) {
return s.toFixed(1) + 's';
} else {
var m = Math.floor(s / 60);
var h = Math.floor(m / 60);
m -= h * 60;
s = Math.round(s - h * 3600 - m * 60);
return h > 0 ? h + 'h ' + m + 'm ' + s + 's' : m + 'm ' + s + 's';
}
}
}, {
key: 'multiplierHtml',
get: function get() {
return this.basePoints ? '&times;' + this.multiplier.toFixed(2) : '';
}
}, {
key: 'basePointsHtml',
get: function get() {
return this.basePoints ? this.basePoints : '';
}
}, {
key: 'totalPointsHtml',
get: function get() {
return this.totalPoints ? this.totalPoints : '';
}
}]);
return MhEntry;
})();
function addHistoryEntry(move, score) {
var num = moveHistory.length + 1;
var e = new MhEntry(num, move, score);
moveHistory.push(e);
e.tr = e.toRow();
mhTableEl.prepend(e.tr);
}
/* exported clearMoveHistory */
function clearMoveHistory() {
moveHistory = [];
$('tr', mhTableEl).remove();
}
/** Add an entry to the move history every time a move is made. */
rxGameScore.subscribe(function (sc) {
return addHistoryEntry(sc.move, sc);
});
/** Opposite of the above: remove history entries including the last player's move. */
listenToGameEvent(GAME_EVENT_UNDO, function (e) {
// get the last index in the move history which is from the player
// a bit hard to read in reduce(): start with -1 (no entry) and assign the index on player's entries
var iLastOfPlayer = moveHistory.reduce(function (prev, h, i) {
return isPlayersColor(h.color) ? i : prev;
}, -1);
// we'll remove everything from the last index on from the list of history entry
if (iLastOfPlayer >= 0) {
var pointsToRemove = 0;
for (var i = iLastOfPlayer; i < moveHistory.length; i++) {
moveHistory[i].tr.remove();
pointsToRemove += moveHistory[i].totalPoints;
}
scoreboard.addPoints({ totalPoints: -pointsToRemove });
scoreboard.decrementMoves(1);
moveHistory = moveHistory.slice(0, iLastOfPlayer);
}
});
/** Bring up the move history dialog. */
function showMoveHist() {
$('#moveHistTitle').text($.t('movehistory.title', { points: scoreboard.displayScore || 0 }));
$('#movehistory').modal('show');
}
/* exported showMoveHist */
//# sourceMappingURL=movehistory.js.map
'use strict';
/* global ga, isCordovaApp */
window.ga = window.ga || function () {
(ga.q = ga.q || []).push(arguments);
};ga.l = +new Date();
// when running from Cordova we'll have to initialize without cookies
ga('create', 'UA-65829240-3', {
'storage': 'none',
'clientId': localStorage.getItem('gaClientId')
});
ga("set", "appName", "chessie");
if (isCordovaApp) {
// and disable the check URL protocol task
ga('set', 'checkProtocolTask', null);
ga('set', 'checkStorageTask', null);
}
// callback, when we receive the tracking it - put it into the localStorage
ga(function (tracker) {
return localStorage.setItem('gaClientId', tracker.get('clientId'));
});
ga('require', 'displayfeatures');
// start out with the information, that the main screen is displyed (which it is after start...)
gaSendScreenView('Main');
/** Subscribe to all game events and report them to Analytics. */
listenToGameEvent(function (e) {
ga('send', {
'hitType': 'event', // Required.
'eventCategory': 'game', // Required.
'eventAction': e.event, // Required.
'eventLabel': '-'
});
//event', '', , '-', chessieSettings.fullLevelDescription);
});
/** Sends out a notification about a scren view to Analytics. */
function gaSendScreenView(screen) {
ga('send', 'screenview', {
'appName': 'chessie',
'screenName': screen
});
}
/**
* Event handler for switching the tab views on the page. We call each of
* the tabs a 'screen' and will report it to Analytics as an screeview event.
* Event data in the callback:
* e.target // newly activated tab
* e.relatedTarget // previous active tab
*/
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var screen = $(e.target).attr('data-screen-id');
console.log('switched to screen %s', screen);
gaSendScreenView(screen);
});
//# sourceMappingURL=analytics.js.map
'use strict';
/* global AdMob */
// select the right Ad Id according to platform
var admobId = {
banner: 'ca-app-pub-8455136100973745/2086286117',
interstitial: 'ca-app-pub-8455136100973745/1357929318'
};
document.addEventListener('deviceready', function () {
// standard banner options
var bannerOptions = {
adId: admobId.banner,
adSize: 'SMART_BANNER',
position: AdMob.AD_POSITION.BOTTOM_CENTER,
overlap: true,
orientationRenew: false,
autoShow: true,
isTesting: window.localStorage.getItem('adTestMode')
};
// is the admob plugin active?
if (typeof AdMob != 'undefined') {
AdMob.createBanner(bannerOptions);
orientationChange.subscribe(function () {
AdMob.removeBanner();
setTimeout(function () {
return AdMob.createBanner(bannerOptions);
}, 1000);
});
// as soon as a game has ended, we'll prepare an interstitial ad
listenToGameEvent(GAME_EVENT_END, function () {
// prepare at beginning of a game level
AdMob.prepareInterstitial({ adId: admobId.interstitial, autoShow: false });
});
// the interstitial ad will be displayed when the dialog with the result is dismissed
listenToGameEvent(GAME_EVENT_RESULTDLG_DISMISS, function () {
// check and show it at end of a game level
setTimeout(function () {
return AdMob.showInterstitial();
}, 1500);
});
}
}, false);
//# sourceMappingURL=monetize.js.map
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment