mau-mau
Version:
Card game for 2 or more players, popular in Czech Republic, Germany and other lands
1,354 lines (1,159 loc) • 288 kB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
},{}],2:[function(require,module,exports){
// # Localize
// is a GNU gettext-inspired (but not conformant) localization library for
// Node.js
var path = require('path');
var fs = require('fs');
function Localize(translations, dateFormats, defaultLocale) {
// Make sure the defaultLocale is something sane, and set the locale to
// its value. Also configure ``Localize`` to throw an error if missing
// a translation.
defaultLocale = typeof(defaultLocale) === "string" ? defaultLocale : "en";
var locale = defaultLocale;
var missingTranslationThrow = true;
// ## The *mergeObjs* function
// is a simple helper function to create a new object based on input objects.
function mergeObjs() {
var outObj = {};
for(var i in arguments) {
if(arguments[i] instanceof Object) {
/* jshint forin: false */
for(var j in arguments[i]) {
// Does not check for collisions, newer object
// definitions clobber old definitions
outObj[j] = arguments[i][j];
}
}
}
return outObj;
}
// ## The *setLocale* function
// simply sets the locale to whatever is specified at the moment, as long as it
// is a string.
this.setLocale = function(newLocale) {
if(typeof(newLocale) === "string") {
locale = newLocale;
} else {
throw new Error("Locale must be a string");
}
};
// ## The *strings* object
// contains a series of key-val pairs to be used for translating very large strings
// that aren't desirable to have duplicated in several locations
this.strings = {};
// ## The *getTranslations* function
// is a recursive function that checks the specified directory, and all child
// directories, for ``translations.json`` files, combines them into one JSON
// object, and returns them.
function getTranslations(currDir, translations, strings) {
if(fs.existsSync(currDir)) {
// Load translations.json file in current directory, if any
if(fs.existsSync(path.join(currDir, "translations.json"))) {
translations = mergeObjs(translations,
JSON.parse(fs.readFileSync(path.join(path.resolve(currDir), "translations.json")))
);
}
var pathChildren;
// Load large text translations in translations subdirectory, if it exists
var translationPath = path.join(currDir, "translations");
if(fs.existsSync(translationPath) && fs.statSync(translationPath).isDirectory()) {
// Get all children in the translations directory
pathChildren = fs.readdirSync(translationPath);
// Filter out all non-default translations (the ones without a lang type)
pathChildren.filter(function(child) {
return !/^.*\..*\..*/.test(child);
// And map these default translations into an object containing the variable name to use,
// the default text, and an array of translations for this text
}).map(function(child) {
return {
name: child.replace(/\..*$/, ""),
defaultText: fs.readFileSync(path.join(translationPath, child), 'utf8'),
// To make the array of translations for this default translation, filter out
// all files that do not start with the primary translation filename (minus extension), with a special
// case to filter out the primary translation, as well
translations: pathChildren.filter(function(secondChild) {
return (new RegExp("^" + child.replace(/\..*$/, ""))).test(secondChild) && child !== secondChild;
// Then map this array of files into an object containing the language specified
// and the translation text for this language
}).map(function(secondChild) {
return {
lang: secondChild.replace(/\.[^\.]*$/, "").replace(/^[^\.]*\./, ""),
text: fs.readFileSync(path.join(translationPath, secondChild), 'utf8')
};
})
};
// For each of these long-form translation objects, add the default text to the strings object using the
// desired variable name, and create a translation object for all defined languages for this text.
}).forEach(function(translation) {
strings[translation.name] = translation.defaultText;
translations[translation.defaultText] = {};
translation.translations.forEach(function(lang) {
translations[translation.defaultText][lang.lang] = lang.text;
});
});
}
// Recurse down each directory and get the translations for that directory
pathChildren = fs.readdirSync(currDir);
/* jshint forin: false */
for(var child in pathChildren) {
var childPath = path.resolve(path.join(currDir, pathChildren[child]));
if(fs.statSync(childPath).isDirectory()) {
var tempArray = getTranslations(childPath, translations, strings);
translations = tempArray[0];
strings = tempArray[1];
}
}
} else {
throw new Error("Translation Path Invalid");
}
return [translations, strings];
}
// ## The *validateTranslations* function
// determines whether or not the provided JSON object is in a valid
// format for ``localize``.
function validateTranslations(newTranslations) {
if(typeof(newTranslations) !== "object") { return false; }
/* jshint forin: false */
for(var translation in newTranslations) {
if(typeof(translation) !== "string") { return false; }
if(typeof(newTranslations[translation]) !== "object" ) { return false; }
for(var lang in newTranslations[translation]) {
if(typeof(lang) !== "string") { return false; }
if(typeof(newTranslations[translation][lang]) !== "string") { return false; }
}
}
return true;
}
// ## The *loadTranslations* function
// takes a string or object, and attempts to append the specified translation
// to its store of translations, either by loading all translations from the
// specified directory (string), or appending the object directly.
this.loadTranslations = function(newTranslations) {
if(typeof(newTranslations) === "string") {
var tempArray = getTranslations(newTranslations, {}, this.strings);
newTranslations = tempArray[0];
this.strings = tempArray[1];
}
if(validateTranslations(newTranslations)) {
translations = mergeObjs(translations, newTranslations);
} else {
throw new Error("Must provide a valid set of translations.");
}
};
// Now that we have the infrastructure in place, let's verify that the
// provided translations are valid.
this.loadTranslations(translations);
// ## The *clearTranslations* function
// simply resets the translations variable to a clean slate.
this.clearTranslations = function() {
translations = {};
};
// ## The *getTranslations* function
// simply returns the entire translations object, or returns that portion
// of translations matched by the elements of a provided array of text to
// translate
this.getTranslations = function(textArr) {
if(textArr instanceof Array) {
var outObj = {};
textArr.forEach(function(text) {
outObj[text] = translations[text];
});
return outObj;
} else {
return translations;
}
};
// ## The *throwOnMissingTranslation* function
// lets the user decide if a missing translation should cause an Error
// to be thrown. Turning it off for development and on for testing is
// recommended. The function coerces whatever it receives into a bool.
this.throwOnMissingTranslation = function(shouldThrow) {
missingTranslationThrow = !!shouldThrow;
};
// ## The *buildString* function
// is a string-building function inspired by both ``sprintf`` and
// [jQuery Templates](http://api.jquery.com/category/plugins/templates/)
// and a small helping of RegExp. The first argument to buildString is
// the source string, which has special ``$[x]`` blocks, where ``x`` is
// a number from 1 to Infinity, matching the nth argument provided.
// Because of ``.toString()``, string formatting _a la_ ``sprintf`` is
// avoided, and the numeric identification allows the same parameter to
// be used multiple times, and the parameter order need not match the
// string referencing order (important for translations)
function buildString() {
var outString = arguments[0];
for(var i = 1; i < arguments.length; i++) {
outString = outString.replace(new RegExp("\\$\\[" + i + "\\]", "g"), arguments[i]);
}
return outString;
}
// ## The *translate* function
// is a thin automatic substitution wrapper around ``buildString``. In
// fact, it short-circuits to ``buildString`` when ``locale`` equals
// ``defaultLocale``. Otherwise, it looks up the required translated
// string and executes ``buildString`` on that, instead
this.translate = function() {
if(locale === defaultLocale) {
return buildString.apply(this, arguments);
}
var newText = translations[arguments[0]] && translations[arguments[0]][locale] ?
translations[arguments[0]][locale] : null;
if(missingTranslationThrow && typeof(newText) !== "string") {
throw new Error("Could not find translation for '" +
arguments[0] + "' in the " + locale + " locale");
} else if(typeof(newText) !== "string") {
newText = arguments[0];
}
var newArr = Array.prototype.splice.call(arguments, 1, arguments.length - 1);
newArr.unshift(newText);
return buildString.apply(this, newArr);
};
// ## The *validateDateFormats* function
// determines whether or not the provided dateFormat object conforms to
// the necessary structure
function validateDateFormats(dateFormats) {
if(typeof(dateFormats) !== "object") { return false; }
/* jshint forin: false */
for(var lang in dateFormats) {
if(typeof(lang) !== "string") { return false; }
if(typeof(dateFormats[lang]) !== "object") { return false; }
if(!(dateFormats[lang].dayNames instanceof Array)) { return false; }
if(!(dateFormats[lang].monthNames instanceof Array)) { return false; }
if(typeof(dateFormats[lang].masks) !== "object") { return false; }
if(typeof(dateFormats[lang].masks["default"]) !== "string") { return false; }
if(dateFormats[lang].dayNames.length !== 14) { return false; }
if(dateFormats[lang].monthNames.length !== 24) { return false; }
for(var i = 0; i < 24; i++) {
if(i < 14 && typeof(dateFormats[lang].dayNames[i]) !== "string") { return false; }
if(typeof(dateFormats[lang].monthNames[i]) !== "string") { return false; }
}
}
return true;
}
// ## The *loadDateFormats* function
// appends the provided ``dateFormats`` object, if valid, to the current
// ``dateFormats`` object. Otherwise, it throws an error.
this.loadDateFormats = function(newDateFormats) {
if(validateDateFormats(newDateFormats)) {
dateFormats = mergeObjs(dateFormats, newDateFormats);
} else {
throw new Error("Invalid Date Format provided");
}
};
// ## The *clearDateFormats* function
// resets the ``dateFormats`` object to English dates.
this.clearDateFormats = function() {
dateFormats = {
"en": {
dayNames: [
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
],
monthNames: [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
],
masks: {
"default": "ddd mmm dd yyyy HH:MM:ss",
shortDate: "m/d/yy",
mediumDate: "mmm d, yyyy",
longDate: "mmmm d, yyyy",
fullDate: "dddd, mmmm d, yyyy",
shortTime: "h:MM TT",
mediumTime: "h:MM:ss TT",
longTime: "h:MM:ss TT Z",
isoDate: "yyyy-mm-dd",
isoTime: "HH:MM:ss",
isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
}
}
};
};
// ## The *getDateFormats* function
// returns the currently-defined ``dateFormats`` object
this.getDateFormats = function() {
return dateFormats;
};
// Now that we have the infrastructure in place, let's validate the
// optional ``dateFormats`` object if provided, or initialize it.
if(validateDateFormats(dateFormats)) {
this.loadDateFormats(dateFormats);
} else {
this.clearDateFormats();
}
// The *localDate* function
// provides easy-to-use date localization support. Based heavily on
// [node-dateFormat](https://github.com/felixge/node-dateformat) by
// Steven Levithan <stevenlevithan.com>
// Scott Trenda <scott.trenda.net>
// Kris Kowal <cixar.com/~kris.kowal/>
// Felix Geisendörfer <debuggable.com>
// MIT Licensed, as with this library. The resultant API is one where
// a date string or object is the first argument, a mask string (being
// either a key in the ``masks`` object or an arbitrary mask is the
// second argument, and a third is a bool flag on whether local or UTC
// time should be used.
this.localDate = (function() {
var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
timezoneClip = /[^-+\dA-Z]/g,
pad = function (val, len) {
val = String(val);
len = len || 2;
while (val.length < len) val = "0" + val;
return val;
};
// Regexes and supporting functions are cached through closure
return function (date, mask, utc) {
// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
if (arguments.length === 1 &&
Object.prototype.toString.call(date) === "[object String]" &&
!/\d/.test(date)) {
mask = date;
date = undefined;
}
date = date || new Date();
if(!(date instanceof Date)) {
date = new Date(date);
}
if(isNaN(date)) {
throw new TypeError("Invalid date");
}
mask = String(dateFormats[locale].masks[mask] || mask || dateFormats[locale].masks["default"]);
// Allow setting the utc argument via the mask
if (mask.slice(0, 4) === "UTC:") {
mask = mask.slice(4);
utc = true;
}
var _ = utc ? "getUTC" : "get",
d = date[_ + "Date"](),
D = date[_ + "Day"](),
m = date[_ + "Month"](),
y = date[_ + "FullYear"](),
H = date[_ + "Hours"](),
M = date[_ + "Minutes"](),
s = date[_ + "Seconds"](),
L = date[_ + "Milliseconds"](),
o = utc ? 0 : date.getTimezoneOffset(),
flags = {
d: d,
dd: pad(d),
ddd: dateFormats[locale].dayNames[D],
dddd: dateFormats[locale].dayNames[D + 7],
m: m + 1,
mm: pad(m + 1),
mmm: dateFormats[locale].monthNames[m],
mmmm: dateFormats[locale].monthNames[m + 12],
yy: String(y).slice(2),
yyyy: y,
h: H % 12 || 12,
hh: pad(H % 12 || 12),
H: H,
HH: pad(H),
M: M,
MM: pad(M),
s: s,
ss: pad(s),
l: pad(L, 3),
L: pad(L > 99 ? Math.round(L / 10) : L),
t: H < 12 ? "a" : "p",
tt: H < 12 ? "am" : "pm",
T: H < 12 ? "A" : "P",
TT: H < 12 ? "AM" : "PM",
Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 !== 10) * d % 10]
};
return mask.replace(token, function ($0) {
return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
});
};
})();
return this;
}
Localize.source = Localize.toString();
module.exports = Localize;
},{"fs":1,"path":3}],3:[function(require,module,exports){
(function (process){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// resolves . and .. elements in a path array with directory names there
// must be no slashes, empty elements, or device names (c:\) in the array
// (so also no leading and trailing slashes - it does not distinguish
// relative and absolute paths)
function normalizeArray(parts, allowAboveRoot) {
// if the path tries to go above the root, `up` ends up > 0
var up = 0;
for (var i = parts.length - 1; i >= 0; i--) {
var last = parts[i];
if (last === '.') {
parts.splice(i, 1);
} else if (last === '..') {
parts.splice(i, 1);
up++;
} else if (up) {
parts.splice(i, 1);
up--;
}
}
// if the path is allowed to go above the root, restore leading ..s
if (allowAboveRoot) {
for (; up--; up) {
parts.unshift('..');
}
}
return parts;
}
// Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
var splitPathRe =
/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
var splitPath = function(filename) {
return splitPathRe.exec(filename).slice(1);
};
// path.resolve([from ...], to)
// posix version
exports.resolve = function() {
var resolvedPath = '',
resolvedAbsolute = false;
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
var path = (i >= 0) ? arguments[i] : process.cwd();
// Skip empty and invalid entries
if (typeof path !== 'string') {
throw new TypeError('Arguments to path.resolve must be strings');
} else if (!path) {
continue;
}
resolvedPath = path + '/' + resolvedPath;
resolvedAbsolute = path.charAt(0) === '/';
}
// At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
return !!p;
}), !resolvedAbsolute).join('/');
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
};
// path.normalize(path)
// posix version
exports.normalize = function(path) {
var isAbsolute = exports.isAbsolute(path),
trailingSlash = substr(path, -1) === '/';
// Normalize the path
path = normalizeArray(filter(path.split('/'), function(p) {
return !!p;
}), !isAbsolute).join('/');
if (!path && !isAbsolute) {
path = '.';
}
if (path && trailingSlash) {
path += '/';
}
return (isAbsolute ? '/' : '') + path;
};
// posix version
exports.isAbsolute = function(path) {
return path.charAt(0) === '/';
};
// posix version
exports.join = function() {
var paths = Array.prototype.slice.call(arguments, 0);
return exports.normalize(filter(paths, function(p, index) {
if (typeof p !== 'string') {
throw new TypeError('Arguments to path.join must be strings');
}
return p;
}).join('/'));
};
// path.relative(from, to)
// posix version
exports.relative = function(from, to) {
from = exports.resolve(from).substr(1);
to = exports.resolve(to).substr(1);
function trim(arr) {
var start = 0;
for (; start < arr.length; start++) {
if (arr[start] !== '') break;
}
var end = arr.length - 1;
for (; end >= 0; end--) {
if (arr[end] !== '') break;
}
if (start > end) return [];
return arr.slice(start, end - start + 1);
}
var fromParts = trim(from.split('/'));
var toParts = trim(to.split('/'));
var length = Math.min(fromParts.length, toParts.length);
var samePartsLength = length;
for (var i = 0; i < length; i++) {
if (fromParts[i] !== toParts[i]) {
samePartsLength = i;
break;
}
}
var outputParts = [];
for (var i = samePartsLength; i < fromParts.length; i++) {
outputParts.push('..');
}
outputParts = outputParts.concat(toParts.slice(samePartsLength));
return outputParts.join('/');
};
exports.sep = '/';
exports.delimiter = ':';
exports.dirname = function(path) {
var result = splitPath(path),
root = result[0],
dir = result[1];
if (!root && !dir) {
// No dirname whatsoever
return '.';
}
if (dir) {
// It has a dirname, strip trailing slash
dir = dir.substr(0, dir.length - 1);
}
return root + dir;
};
exports.basename = function(path, ext) {
var f = splitPath(path)[2];
// TODO: make this comparison case-insensitive on windows?
if (ext && f.substr(-1 * ext.length) === ext) {
f = f.substr(0, f.length - ext.length);
}
return f;
};
exports.extname = function(path) {
return splitPath(path)[3];
};
function filter (xs, f) {
if (xs.filter) return xs.filter(f);
var res = [];
for (var i = 0; i < xs.length; i++) {
if (f(xs[i], i, xs)) res.push(xs[i]);
}
return res;
}
// String.prototype.substr - negative index don't work in IE8
var substr = 'ab'.substr(-1) === 'b'
? function (str, start, len) { return str.substr(start, len) }
: function (str, start, len) {
if (start < 0) start = str.length + start;
return str.substr(start, len);
}
;
}).call(this,require('_process'))
},{"_process":4}],4:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout;
var cachedClearTimeout;
function defaultSetTimout() {
throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
throw new Error('clearTimeout has not been defined');
}
(function () {
try {
if (typeof setTimeout === 'function') {
cachedSetTimeout = setTimeout;
} else {
cachedSetTimeout = defaultSetTimout;
}
} catch (e) {
cachedSetTimeout = defaultSetTimout;
}
try {
if (typeof clearTimeout === 'function') {
cachedClearTimeout = clearTimeout;
} else {
cachedClearTimeout = defaultClearTimeout;
}
} catch (e) {
cachedClearTimeout = defaultClearTimeout;
}
} ())
function runTimeout(fun) {
if (cachedSetTimeout === setTimeout) {
//normal enviroments in sane situations
return setTimeout(fun, 0);
}
// if setTimeout wasn't available but was latter defined
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
cachedSetTimeout = setTimeout;
return setTimeout(fun, 0);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout(fun, 0);
} catch(e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout.call(null, fun, 0);
} catch(e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout.call(this, fun, 0);
}
}
}
function runClearTimeout(marker) {
if (cachedClearTimeout === clearTimeout) {
//normal enviroments in sane situations
return clearTimeout(marker);
}
// if clearTimeout wasn't available but was latter defined
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
cachedClearTimeout = clearTimeout;
return clearTimeout(marker);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout(marker);
} catch (e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout.call(null, marker);
} catch (e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout.call(this, marker);
}
}
}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
if (!draining || !currentQueue) {
return;
}
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
} else {
queueIndex = -1;
}
if (queue.length) {
drainQueue();
}
}
function drainQueue() {
if (draining) {
return;
}
var timeout = runTimeout(cleanUpNextTick);
draining = true;
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
while (++queueIndex < len) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len = queue.length;
}
currentQueue = null;
draining = false;
runClearTimeout(timeout);
}
process.nextTick = function (fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
// v8 likes predictible objects
function Item(fun, array) {
this.fun = fun;
this.array = array;
}
Item.prototype.run = function () {
this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };
},{}],5:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
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; }; }();
var _Prompt2 = require('../engine/game/Prompt');
var _Prompt3 = _interopRequireDefault(_Prompt2);
var _Ranks = require('../engine/cards/Ranks');
var _Ranks2 = _interopRequireDefault(_Ranks);
var _SuitSelector = require('./SuitSelector');
var _SuitSelector2 = _interopRequireDefault(_SuitSelector);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var BrowserPrompt = function (_Prompt) {
_inherits(BrowserPrompt, _Prompt);
function BrowserPrompt() {
_classCallCheck(this, BrowserPrompt);
var _this = _possibleConstructorReturn(this, (BrowserPrompt.__proto__ || Object.getPrototypeOf(BrowserPrompt)).call(this));
_this.suitSelector = new _SuitSelector2.default();
return _this;
}
_createClass(BrowserPrompt, [{
key: 'attachGame',
value: function attachGame(game) {
_Prompt3.default.prototype.attachGame.apply(this, arguments);
this.suitSelector.attachGame(game);
}
}, {
key: 'attachPlay',
value: function attachPlay(htmlHand, drawingStack) {
drawingStack.addEventListener('click', drawCard.bind(this));
htmlHand.addEventListener('click', playCard.bind(this));
htmlHand.addEventListener('mousemove', selectCard.bind(this));
}
}, {
key: 'chooseCard',
value: function chooseCard(player) {
var _this2 = this;
return new Promise(function (resolve, reject) {
_this2.player = player;
_this2.resolve = resolve;
_this2.reject = reject;
});
}
}]);
return BrowserPrompt;
}(_Prompt3.default);
function getParentCard(child) {
while (!child.classList.contains('card')) {
child = child.parentElement;
}
return child;
}
function drawCard() {
if (this.player) {
var reject = this.reject;
this.player = this.resolve = this.reject = undefined;
reject();
}
}
function playCard(event) {
if (this.player) {
var htmlCard = getParentCard(event.target),
card = htmlCard.card;
if (card) {
var playableCards = this.game.rules.pickPlayableCards(this.player.hand);
if (playableCards.indexOf(card) >= 0) {
if (card.rank === _Ranks2.default.queen && this.player.hand.cardCount > 1) {
this.suitSelector.chooseSuit().then(dropCard.bind(this, card, htmlCard)).catch(function (error) {
console.log(error);
});
} else {
dropCard.call(this, card, htmlCard);
}
}
}
}
}
var topCardZIndex = 1;
function selectCard(event) {
var htmlCard = getParentCard(event.target),
card = htmlCard.card;
if (htmlCard.style.zIndex != topCardZIndex && card) {
var availableCards = this.player.hand.pickCards();
if (availableCards.indexOf(card) >= 0) {
htmlCard.style.zIndex = ++topCardZIndex;
}
}
}
function dropCard(card, htmlCard) {
var resolve = this.resolve;
this.player = this.resolve = this.reject = undefined;
htmlCard.style.zIndex = '';
resolve(card);
}
exports.default = BrowserPrompt;
},{"../engine/cards/Ranks":13,"../engine/game/Prompt":19,"./SuitSelector":8}],6:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
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"); } }
var Menu = function () {
function Menu() {
_classCallCheck(this, Menu);
var templateImport = document.getElementById('template-import'),
template = templateImport.import.getElementById('menu-template'),
fragment = document.importNode(template.content, true);
this.menu = document.getElementById('menu');
this.menu.appendChild(fragment);
this.playerSelector = document.getElementById('players');
document.getElementById('new-game').addEventListener('click', function () {
location.reload();
});
}
_createClass(Menu, [{
key: 'attachGame',
value: function attachGame(game) {
this.game = game;
}
}]);
return Menu;
}();
function show() {}
function hide() {}
exports.default = Menu;
},{}],7:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
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"); } }
var SuitDisplay = function () {
function SuitDisplay() {
_classCallCheck(this, SuitDisplay);
var templateImport = document.getElementById('template-import'),
template = templateImport.import.getElementById('suit-display-template'),
fragment = document.importNode(template.content, true);
this.suitDisplay = document.getElementById('show-suit');
this.suitDisplay.appendChild(fragment);
this.suitValue = document.getElementById('suit');
}
_createClass(SuitDisplay, [{
key: 'attachGame',
value: function attachGame(game) {
this.game = game;
}
}, {
key: 'showSuit',
value: function showSuit(suit) {
if (suit) {
this.suitValue.textContent = suit;
this.suitDisplay.style.display = '';
} else {
this.suitDisplay.style.display = 'none';
}
}
}]);
return SuitDisplay;
}();
function show() {}
function hide() {}
exports.default = SuitDisplay;
},{}],8:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
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; }; }();
var _Suits = require('../engine/cards/Suits');
var _Suits2 = _interopRequireDefault(_Suits);
var _EventEmitter2 = require('../engine/misc/EventEmitter');
var _EventEmitter3 = _interopRequireDefault(_EventEmitter2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var SuitSelector = function (_EventEmitter) {
_inherits(SuitSelector, _EventEmitter);
function SuitSelector() {
_classCallCheck(this, SuitSelector);
var templateImport = document.getElementById('template-import'),
template = templateImport.import.getElementById('suit-selector-template'),
fragment = document.importNode(template.content, true);
var _this = _possibleConstructorReturn(this, (SuitSelector.__proto__ || Object.getPrototypeOf(SuitSelector)).call(this));
_this.suitSelector = document.getElementById('choose-suit');
_this.suitSelector.addEventListener('click', chooseSuit.bind(_this));
_this.suitSelector.appendChild(fragment);
return _this;
}
_createClass(SuitSelector, [{
key: 'attachGame',
value: function attachGame(game) {
this.game = game;
}
}, {
key: 'chooseSuit',
value: function chooseSuit() {
var _this2 = this;
this.suitSelector.style.display = '';
return new Promise(function (resolve) {
return _this2.resolve = resolve;
});
}
}]);
return SuitSelector;
}(_EventEmitter3.default);
function show() {}
function hide() {}
function chooseSuit(event) {
var suit = event.target.id;
if (_Suits2.default[suit]) {
this.suitSelector.style.display = 'none';
this.game.rules.chosenSuit = suit;
this.resolve(suit);
}
}
exports.default = SuitSelector;
},{"../engine/cards/Suits":15,"../engine/misc/EventEmitter":21}],9:[function(require,module,exports){
'use strict';
var _Ranks = require('../engine/cards/Ranks');
var _Ranks2 = _interopRequireDefault(_Ranks);
var _Game = require('../engine/game/Game');
var _Game2 = _interopRequireDefault(_Game);
var _Human = require('../engine/players/Human');
var _Human2 = _interopRequireDefault(_Human);
var _SmartComputer = require('../engine/players/SmartComputer');
var _SmartComputer2 = _interopRequireDefault(_SmartComputer);
var _Reporter = require('../engine/misc/Reporter');
var _Reporter2 = _interopRequireDefault(_Reporter);
var _BrowserPrompt = require('./BrowserPrompt');
var _BrowserPrompt2 = _interopRequireDefault(_BrowserPrompt);
var _SuitDisplay = require('./SuitDisplay');
var _SuitDisplay2 = _interopRequireDefault(_SuitDisplay);
var _Menu = require('./Menu');
var _Menu2 = _interopRequireDefault(_Menu);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
document.addEventListener('HTMLImportsLoaded', startApplication);
function startApplication() {
var cardImport = document.getElementById('template-import'),
cardTemplate = cardImport.import.getElementById('card-template'),
drawingStack = document.querySelector('.drawing-stack'),
playingStack = document.querySelector('.playing-stack'),
hands = document.querySelector('.hands'),
htmlCards = {},
htmlHands = {},
cardAnimations = [],
playerCountValue = /[?&]playerCount=(\d+)/.exec(location.search),
playerCount = playerCountValue && parseInt(playerCountValue[1], 10) || 4,
players = [],
dealingCards;
function getHTMLHand(player) {
var htmlHand = htmlHands[player];
if (!htmlHand) {
htmlHand = htmlHands[player] = document.createElement('div');
htmlHand.classList.add('hand');
if (player instanceof _Human2.default) {
htmlHand.classList.add('human');
prompt.attachPlay(htmlHand, drawingStack);
}
htmlHand.setAttribute('title', player.toString());
hands.appendChild(htmlHand);
}
return htmlHand;
}
function getHTMLCard(card) {
var htmlCard = htmlCards[card];
if (!htmlCard) {
var cardFragment = document.importNode(cardTemplate.content, true);
htmlCard = htmlCards[card] = cardFragment.children[0];
htmlCard.classList.add(card.suit, card.rank);
htmlCard.card = card;
}
return htmlCard;
}
function scheduleCardAnimation(card, player, callback) {
var direction;
if (player) {
var availableCards = player.hand.pickCards();
direction = availableCards.indexOf(card) >= 0 ? 'to' : 'from';
}
cardAnimations.push({
card: card,
player: player,
direction: direction,
callback: callback,
delay: dealingCards ? 10 : 0
});
if (cardAnimations.length === 1) {
animateCard();
}
}
function animateCard() {
var cardAnimation = cardAnimations[0],
card = cardAnimation.card,
htmlCard = htmlCards[card],
player = cardAnimation.player;
function afterInitialFlipAnimation() {
htmlCard.removeEventListener('transitionend', afterInitialFlipAnimation);
htmlCard.classList.add('from-pack');
htmlCard.addEventListener('transitionend', afterMoveAnimation);
htmlCard.classList.add(cardAnimation.direction + '-player-' + (players.indexOf(player) + 1));
}
function afterMoveAnimation() {
if (player && htmlCard) {
htmlCard.removeEventListener('transitionend', afterMoveAnimation);
if (player instanceof _Human2.default && cardAnimation.direction == 'to') {
if (htmlCard.classList.contains('flipped')) {
htmlCard.addEventListener('transitionend', afterFinalFlipAnimation);
htmlCard.classList.remove('flipped');
return;
}
}
}
afterFinalFlipAnimation();
}
function afterFinalFlipAnimation() {
if (player && htmlCard) {
htmlCard.style.zIndex = '';
htmlCard.removeEventListener('transitionend', afterFinalFlipAnimation);
}
setTimeout(function () {
if (htmlCard) {
htmlCard.classList.remove('selected');
if (player) {
htmlCard.classList.remove('from-pack', 'from-player-1', 'from-player-2', 'from-player-3', 'from-player-4', 'to-player-1', 'to-player-2', 'to-player-3', 'to-player-4');
}
}
cardAnimation.callback.call(this, card);
cardAnimations.shift();
if (cardAnimations.length) {
setTimeout(animateCard, 0);
}
}, cardAnimation.delay);
}
if (player && htmlCard) {
htmlCard.style.zIndex = 100;
var method = cardAnimation.direction == 'to' ? 'add' : 'remove',
flipped = htmlCard.classList.contains('flipped');
if (flipped && method === 'remove' || !flipped && method === 'add') {
htmlCard.addEventListener('transitionend', afterInitialFlipAnimation);
htmlCard.classList[method]('flipped');
} else {
afterInitialFlipAnimation();
}
return;
}
if (htmlCard) {
htmlCard.classList.add('selected');
}
afterMoveAnimation();
}
players.push(new _Human2.default());
while (--playerCount) {
players.push(new _SmartComputer2.default());
}
var prompt = new _BrowserPrompt2.default(),
game = new _Game2.default({
players: players,
prompt: prompt
}),
suitDisplay = new _SuitDisplay2.default(),
menu = new _Menu2.default();
suitDisplay.attachGame(game);
menu.attachGame(game);
game.on('game:starting', function () {
dealingCards = true;
// Initial card dealing and turning over the playing stack
game.drawingStack.on('cards:received', function (cards) {
// The first card (the top card) has to be the last element added,
// so that it gets naturally to the top without z-index
cards.reverse().forEach(function (card) {
scheduleCardAnimation(card, undefined, function () {
var htmlCard = getHTMLCard(card);
htmlCard.classList.add('flipped');
drawingStack.appendChild(htmlCard);
});
});
});
// Playing a card
game.playingStack.on('cards:received', function (cards) {
if (dealingCards) {
cards.forEach(function (card) {
scheduleCardAnimation(card, undefined, function () {
var htmlCard = getHTMLCard(card);
htmlCard.classList.remove('flipped');
playingStack.appendChild(htmlCard);
});
});
}
});
// Drawing a card
game.players.forEach(function (player, index) {
player.on('player:drawn', function (card) {
scheduleCardAnimation(card, !dealingCards && player, function () {
var htmlCard = getHTMLCard(card),
htmlHand = getHTMLHand(player),
method = player instanceof _Human2.default ? 'remove' : 'add';
htmlCard.classList[method]('flipped');
htmlHand.appendChild(htmlCard);
});
}).on('player:played', function (card) {
scheduleCardAnimation(card, player, function () {
var htmlCard = getHTMLCard(card);
htmlCard.classList.remove('flipped', 'selected');
playingStack.appendChild(htmlCard);
});
var suit = game.playingStack.peekAtTopCard().rank === _Ranks2.default.queen && game.rules.chosenSuit;
suitDisplay.showSuit(!game.rules.whoWins() && suit);
});
});
});
game.on('game:started', function () {
dealingCards = false;
});
game.on('game:turning-over', function () {
dealingCards = true;
});
game.on('game:turned-over', function () {
dealingCards = false;
});
game.start();
}
},{"../engine/cards/Ranks":13,"../engine/game/Game":17,"../engi