Skip to content

Instantly share code, notes, and snippets.

@joliss
Last active January 4, 2016 09:29
Show Gist options
  • Save joliss/8602310 to your computer and use it in GitHub Desktop.
Save joliss/8602310 to your computer and use it in GitHub Desktop.
// Generated by CoffeeScript 1.6.3
(function() {
var _ref, _ref1, _ref10, _ref100, _ref101, _ref102, _ref103, _ref11, _ref12, _ref13, _ref14, _ref15, _ref16, _ref17, _ref18, _ref19, _ref2, _ref20, _ref21, _ref22, _ref23, _ref24, _ref25, _ref26, _ref27, _ref28, _ref29, _ref3, _ref30, _ref31, _ref32, _ref33, _ref34, _ref35, _ref36, _ref37, _ref38, _ref39, _ref4, _ref40, _ref41, _ref42, _ref43, _ref44, _ref45, _ref46, _ref47, _ref48, _ref49, _ref5, _ref50, _ref51, _ref52, _ref53, _ref54, _ref55, _ref56, _ref57, _ref58, _ref59, _ref6, _ref60, _ref61, _ref62, _ref63, _ref64, _ref65, _ref66, _ref67, _ref68, _ref69, _ref7, _ref70, _ref71, _ref72, _ref73, _ref74, _ref75, _ref76, _ref77, _ref78, _ref79, _ref8, _ref80, _ref81, _ref82, _ref83, _ref84, _ref85, _ref86, _ref87, _ref88, _ref89, _ref9, _ref90, _ref91, _ref92, _ref93, _ref94, _ref95, _ref96, _ref97, _ref98, _ref99,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__slice = [].slice,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref, _ref1;
_ref = [this.size.width, this.size.height], width = _ref[0], height = _ref[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref1 = [2 * width, 4 * height], left = _ref1[0], top = _ref1[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref, _results;
_results = [];
for (i = _i = 0, _ref = this.model.numberOfFoundations; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref, _results;
_results = [];
for (i = _i = 0, _ref = this.model.numberOfTableauPiles; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref, _ref1,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref = this.model.numberOfFoundations; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref1 = this.model.numberOfTableauPiles; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref, _ref1;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref = this.cardControllers;
for (id in _ref) {
controller = _ref[id];
controller.destroy();
}
this.cardControllers = {};
_ref1 = this.model.deck;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
card = _ref1[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref, _ref1, _ref2, _ref3, _ref4, _results;
zIndex = 1000;
_ref = this.model.stock;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
card = _ref[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref1 = this.model.waste;
for (index = _j = 0, _len1 = _ref1.length; _j < _len1; index = ++_j) {
card = _ref1[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref2 = this.model.foundations;
for (index = _k = 0, _len2 = _ref2.length; _k < _len2; index = ++_k) {
foundation = _ref2[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref3 = this.model.faceDownTableauPiles.length; 0 <= _ref3 ? _m < _ref3 : _m > _ref3; i = 0 <= _ref3 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref4 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref4.length; _n < _len4; _n++) {
card = _ref4[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref5, _results1;
_ref5 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref5.length; _o < _len5; _o++) {
card = _ref5[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref = this.model.waste.length) && _ref === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
controller = _ref[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref1, _results;
_ref1 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
c = _ref1[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref1 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
controller = _ref1[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref2 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
controller = _ref2[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref3 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
controller = _ref3[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref4 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref4.length; _m < _len4; _m++) {
controller = _ref4[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref5 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref5.length; _n < _len5; _n++) {
controller = _ref5[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref = [['waste']].concat(__slice.call((function() {
var _j, _ref, _results;
_results = [];
for (i = _j = 0, _ref = this.model.faceUpTableauPiles.length; 0 <= _ref ? _j < _ref : _j > _ref; i = 0 <= _ref ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
locator = _ref[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref, _ref1, _ref2, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref = _this.dragState.cards) != null ? _ref : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref1, _results;
_ref1 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
c = _ref1[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref1, _results;
_ref1 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
el = _ref1[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref1 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
el = _ref1[_i];
_results.push($(el).css({
zIndex: parseInt((_ref2 = $(el).css('zIndex')) != null ? _ref2 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref, _results;
_ref = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
el = _ref[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results, _results1;
if (!_this.dragState.cards) {
_ref = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
el = _ref[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref1, _results1;
_ref1 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
e = _ref1[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref1 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
dropZone = _ref1[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref2 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
controller = _ref2[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref, _ref1;
dropZones = [];
_ref = this.model.locators.foundations;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
locator = _ref[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref1 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
locator = _ref1[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref = this.model.foundations.length; 0 <= _ref ? _i < _ref : _i > _ref; foundationIndex = 0 <= _ref ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref1 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref1;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref2, _ref3;
_ref2 = [this.size.width, this.size.height], width = _ref2[0], height = _ref2[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref3 = [2 * width, 4 * height], left = _ref3[0], top = _ref3[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref2, _results;
_results = [];
for (i = _i = 0, _ref2 = this.model.numberOfFoundations; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref2, _results;
_results = [];
for (i = _i = 0, _ref2 = this.model.numberOfTableauPiles; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref2, _ref3,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref2 = this.model.numberOfFoundations; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref3 = this.model.numberOfTableauPiles; 0 <= _ref3 ? _j < _ref3 : _j > _ref3; i = 0 <= _ref3 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref2, _ref3;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref2 = this.cardControllers;
for (id in _ref2) {
controller = _ref2[id];
controller.destroy();
}
this.cardControllers = {};
_ref3 = this.model.deck;
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
card = _ref3[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref2, _ref3, _ref4, _ref5, _ref6, _results;
zIndex = 1000;
_ref2 = this.model.stock;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
card = _ref2[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref3 = this.model.waste;
for (index = _j = 0, _len1 = _ref3.length; _j < _len1; index = ++_j) {
card = _ref3[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref4 = this.model.foundations;
for (index = _k = 0, _len2 = _ref4.length; _k < _len2; index = ++_k) {
foundation = _ref4[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref5 = this.model.faceDownTableauPiles.length; 0 <= _ref5 ? _m < _ref5 : _m > _ref5; i = 0 <= _ref5 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref6 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref6.length; _n < _len4; _n++) {
card = _ref6[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref7, _results1;
_ref7 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref7.length; _o < _len5; _o++) {
card = _ref7[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref2;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref2 = this.model.waste.length) && _ref2 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref2 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
controller = _ref2[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref3, _results;
_ref3 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
c = _ref3[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref3 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
controller = _ref3[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref4 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) {
controller = _ref4[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref5 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref5.length; _l < _len3; _l++) {
controller = _ref5[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref6 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref6.length; _m < _len4; _m++) {
controller = _ref6[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref7 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref7.length; _n < _len5; _n++) {
controller = _ref7[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref2,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref2 = [['waste']].concat(__slice.call((function() {
var _j, _ref2, _results;
_results = [];
for (i = _j = 0, _ref2 = this.model.faceUpTableauPiles.length; 0 <= _ref2 ? _j < _ref2 : _j > _ref2; i = 0 <= _ref2 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
locator = _ref2[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref2, _ref3, _ref4, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref2 = _this.dragState.cards) != null ? _ref2 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref3, _results;
_ref3 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
c = _ref3[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref3, _results;
_ref3 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
el = _ref3[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref3 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
el = _ref3[_i];
_results.push($(el).css({
zIndex: parseInt((_ref4 = $(el).css('zIndex')) != null ? _ref4 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref2, _results;
_ref2 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) {
el = _ref2[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref2, _ref3, _ref4, _results, _results1;
if (!_this.dragState.cards) {
_ref2 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) {
el = _ref2[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref3, _results1;
_ref3 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
e = _ref3[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref3 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
dropZone = _ref3[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref4 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) {
controller = _ref4[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref2, _ref3;
dropZones = [];
_ref2 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) {
locator = _ref2[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref3 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref3.length; _j < _len1; i = ++_j) {
locator = _ref3[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref2, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref2 = this.model.foundations.length; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; foundationIndex = 0 <= _ref2 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref2 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref2;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref3 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref3;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref4, _ref5;
_ref4 = [this.size.width, this.size.height], width = _ref4[0], height = _ref4[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref5 = [2 * width, 4 * height], left = _ref5[0], top = _ref5[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref4, _results;
_results = [];
for (i = _i = 0, _ref4 = this.model.numberOfFoundations; 0 <= _ref4 ? _i < _ref4 : _i > _ref4; i = 0 <= _ref4 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref4, _results;
_results = [];
for (i = _i = 0, _ref4 = this.model.numberOfTableauPiles; 0 <= _ref4 ? _i < _ref4 : _i > _ref4; i = 0 <= _ref4 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref4, _ref5,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref4 = this.model.numberOfFoundations; 0 <= _ref4 ? _i < _ref4 : _i > _ref4; i = 0 <= _ref4 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref5 = this.model.numberOfTableauPiles; 0 <= _ref5 ? _j < _ref5 : _j > _ref5; i = 0 <= _ref5 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref4, _ref5;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref4 = this.cardControllers;
for (id in _ref4) {
controller = _ref4[id];
controller.destroy();
}
this.cardControllers = {};
_ref5 = this.model.deck;
for (_i = 0, _len = _ref5.length; _i < _len; _i++) {
card = _ref5[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref4, _ref5, _ref6, _ref7, _ref8, _results;
zIndex = 1000;
_ref4 = this.model.stock;
for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
card = _ref4[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref5 = this.model.waste;
for (index = _j = 0, _len1 = _ref5.length; _j < _len1; index = ++_j) {
card = _ref5[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref6 = this.model.foundations;
for (index = _k = 0, _len2 = _ref6.length; _k < _len2; index = ++_k) {
foundation = _ref6[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref7 = this.model.faceDownTableauPiles.length; 0 <= _ref7 ? _m < _ref7 : _m > _ref7; i = 0 <= _ref7 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref8 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref8.length; _n < _len4; _n++) {
card = _ref8[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref9, _results1;
_ref9 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref9.length; _o < _len5; _o++) {
card = _ref9[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref4;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref4 = this.model.waste.length) && _ref4 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref4 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
controller = _ref4[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref5, _results;
_ref5 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref5.length; _j < _len1; _j++) {
c = _ref5[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref5 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref5.length; _j < _len1; _j++) {
controller = _ref5[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref6 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref6.length; _k < _len2; _k++) {
controller = _ref6[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref7 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref7.length; _l < _len3; _l++) {
controller = _ref7[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref8 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref8.length; _m < _len4; _m++) {
controller = _ref8[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref9 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref9.length; _n < _len5; _n++) {
controller = _ref9[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref4,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref4 = [['waste']].concat(__slice.call((function() {
var _j, _ref4, _results;
_results = [];
for (i = _j = 0, _ref4 = this.model.faceUpTableauPiles.length; 0 <= _ref4 ? _j < _ref4 : _j > _ref4; i = 0 <= _ref4 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
locator = _ref4[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref4, _ref5, _ref6, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref4 = _this.dragState.cards) != null ? _ref4 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref5, _results;
_ref5 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref5.length; _i < _len; _i++) {
c = _ref5[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref5, _results;
_ref5 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref5.length; _i < _len; _i++) {
el = _ref5[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref5 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref5.length; _i < _len; _i++) {
el = _ref5[_i];
_results.push($(el).css({
zIndex: parseInt((_ref6 = $(el).css('zIndex')) != null ? _ref6 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref4, _results;
_ref4 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref4.length; _i < _len; i = ++_i) {
el = _ref4[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref4, _ref5, _ref6, _results, _results1;
if (!_this.dragState.cards) {
_ref4 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref4.length; _i < _len; i = ++_i) {
el = _ref4[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref5, _results1;
_ref5 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref5.length; _j < _len1; _j++) {
e = _ref5[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref5 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref5.length; _j < _len1; _j++) {
dropZone = _ref5[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref6 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref6.length; _k < _len2; _k++) {
controller = _ref6[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref4, _ref5;
dropZones = [];
_ref4 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref4.length; _i < _len; i = ++_i) {
locator = _ref4[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref5 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref5.length; _j < _len1; i = ++_j) {
locator = _ref5[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref4, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref4 = this.model.foundations.length; 0 <= _ref4 ? _i < _ref4 : _i > _ref4; foundationIndex = 0 <= _ref4 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref4 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref4;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref5 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref5;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref6, _ref7;
_ref6 = [this.size.width, this.size.height], width = _ref6[0], height = _ref6[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref7 = [2 * width, 4 * height], left = _ref7[0], top = _ref7[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref6, _results;
_results = [];
for (i = _i = 0, _ref6 = this.model.numberOfFoundations; 0 <= _ref6 ? _i < _ref6 : _i > _ref6; i = 0 <= _ref6 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref6, _results;
_results = [];
for (i = _i = 0, _ref6 = this.model.numberOfTableauPiles; 0 <= _ref6 ? _i < _ref6 : _i > _ref6; i = 0 <= _ref6 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref6, _ref7,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref6 = this.model.numberOfFoundations; 0 <= _ref6 ? _i < _ref6 : _i > _ref6; i = 0 <= _ref6 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref7 = this.model.numberOfTableauPiles; 0 <= _ref7 ? _j < _ref7 : _j > _ref7; i = 0 <= _ref7 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref6, _ref7;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref6 = this.cardControllers;
for (id in _ref6) {
controller = _ref6[id];
controller.destroy();
}
this.cardControllers = {};
_ref7 = this.model.deck;
for (_i = 0, _len = _ref7.length; _i < _len; _i++) {
card = _ref7[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref10, _ref6, _ref7, _ref8, _ref9, _results;
zIndex = 1000;
_ref6 = this.model.stock;
for (_i = 0, _len = _ref6.length; _i < _len; _i++) {
card = _ref6[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref7 = this.model.waste;
for (index = _j = 0, _len1 = _ref7.length; _j < _len1; index = ++_j) {
card = _ref7[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref8 = this.model.foundations;
for (index = _k = 0, _len2 = _ref8.length; _k < _len2; index = ++_k) {
foundation = _ref8[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref9 = this.model.faceDownTableauPiles.length; 0 <= _ref9 ? _m < _ref9 : _m > _ref9; i = 0 <= _ref9 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref10 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref10.length; _n < _len4; _n++) {
card = _ref10[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref11, _results1;
_ref11 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref11.length; _o < _len5; _o++) {
card = _ref11[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref6;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref6 = this.model.waste.length) && _ref6 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref10, _ref11, _ref6, _ref7, _ref8, _ref9, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref6 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref6.length; _i < _len; _i++) {
controller = _ref6[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref7, _results;
_ref7 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref7.length; _j < _len1; _j++) {
c = _ref7[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref7 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref7.length; _j < _len1; _j++) {
controller = _ref7[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref8 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref8.length; _k < _len2; _k++) {
controller = _ref8[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref9 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref9.length; _l < _len3; _l++) {
controller = _ref9[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref10 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref10.length; _m < _len4; _m++) {
controller = _ref10[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref11 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref11.length; _n < _len5; _n++) {
controller = _ref11[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref6,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref6 = [['waste']].concat(__slice.call((function() {
var _j, _ref6, _results;
_results = [];
for (i = _j = 0, _ref6 = this.model.faceUpTableauPiles.length; 0 <= _ref6 ? _j < _ref6 : _j > _ref6; i = 0 <= _ref6 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref6.length; _i < _len; _i++) {
locator = _ref6[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref6, _ref7, _ref8, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref6 = _this.dragState.cards) != null ? _ref6 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref7, _results;
_ref7 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref7.length; _i < _len; _i++) {
c = _ref7[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref7, _results;
_ref7 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref7.length; _i < _len; _i++) {
el = _ref7[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref7 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref7.length; _i < _len; _i++) {
el = _ref7[_i];
_results.push($(el).css({
zIndex: parseInt((_ref8 = $(el).css('zIndex')) != null ? _ref8 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref6, _results;
_ref6 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref6.length; _i < _len; i = ++_i) {
el = _ref6[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref6, _ref7, _ref8, _results, _results1;
if (!_this.dragState.cards) {
_ref6 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref6.length; _i < _len; i = ++_i) {
el = _ref6[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref7, _results1;
_ref7 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref7.length; _j < _len1; _j++) {
e = _ref7[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref7 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref7.length; _j < _len1; _j++) {
dropZone = _ref7[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref8 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref8.length; _k < _len2; _k++) {
controller = _ref8[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref6, _ref7;
dropZones = [];
_ref6 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref6.length; _i < _len; i = ++_i) {
locator = _ref6[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref7 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref7.length; _j < _len1; i = ++_j) {
locator = _ref7[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref6, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref6 = this.model.foundations.length; 0 <= _ref6 ? _i < _ref6 : _i > _ref6; foundationIndex = 0 <= _ref6 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref6 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref6;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref7 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref7;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref8, _ref9;
_ref8 = [this.size.width, this.size.height], width = _ref8[0], height = _ref8[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref9 = [2 * width, 4 * height], left = _ref9[0], top = _ref9[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref8, _results;
_results = [];
for (i = _i = 0, _ref8 = this.model.numberOfFoundations; 0 <= _ref8 ? _i < _ref8 : _i > _ref8; i = 0 <= _ref8 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref8, _results;
_results = [];
for (i = _i = 0, _ref8 = this.model.numberOfTableauPiles; 0 <= _ref8 ? _i < _ref8 : _i > _ref8; i = 0 <= _ref8 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref8, _ref9,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref8 = this.model.numberOfFoundations; 0 <= _ref8 ? _i < _ref8 : _i > _ref8; i = 0 <= _ref8 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref9 = this.model.numberOfTableauPiles; 0 <= _ref9 ? _j < _ref9 : _j > _ref9; i = 0 <= _ref9 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref8, _ref9;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref8 = this.cardControllers;
for (id in _ref8) {
controller = _ref8[id];
controller.destroy();
}
this.cardControllers = {};
_ref9 = this.model.deck;
for (_i = 0, _len = _ref9.length; _i < _len; _i++) {
card = _ref9[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref10, _ref11, _ref12, _ref8, _ref9, _results;
zIndex = 1000;
_ref8 = this.model.stock;
for (_i = 0, _len = _ref8.length; _i < _len; _i++) {
card = _ref8[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref9 = this.model.waste;
for (index = _j = 0, _len1 = _ref9.length; _j < _len1; index = ++_j) {
card = _ref9[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref10 = this.model.foundations;
for (index = _k = 0, _len2 = _ref10.length; _k < _len2; index = ++_k) {
foundation = _ref10[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref11 = this.model.faceDownTableauPiles.length; 0 <= _ref11 ? _m < _ref11 : _m > _ref11; i = 0 <= _ref11 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref12 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref12.length; _n < _len4; _n++) {
card = _ref12[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref13, _results1;
_ref13 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref13.length; _o < _len5; _o++) {
card = _ref13[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref8;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref8 = this.model.waste.length) && _ref8 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref10, _ref11, _ref12, _ref13, _ref8, _ref9, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref8 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref8.length; _i < _len; _i++) {
controller = _ref8[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref9, _results;
_ref9 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref9.length; _j < _len1; _j++) {
c = _ref9[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref9 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref9.length; _j < _len1; _j++) {
controller = _ref9[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref10 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref10.length; _k < _len2; _k++) {
controller = _ref10[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref11 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref11.length; _l < _len3; _l++) {
controller = _ref11[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref12 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref12.length; _m < _len4; _m++) {
controller = _ref12[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref13 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref13.length; _n < _len5; _n++) {
controller = _ref13[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref8,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref8 = [['waste']].concat(__slice.call((function() {
var _j, _ref8, _results;
_results = [];
for (i = _j = 0, _ref8 = this.model.faceUpTableauPiles.length; 0 <= _ref8 ? _j < _ref8 : _j > _ref8; i = 0 <= _ref8 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref8.length; _i < _len; _i++) {
locator = _ref8[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref10, _ref8, _ref9, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref8 = _this.dragState.cards) != null ? _ref8 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref9, _results;
_ref9 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref9.length; _i < _len; _i++) {
c = _ref9[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref9, _results;
_ref9 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref9.length; _i < _len; _i++) {
el = _ref9[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref9 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref9.length; _i < _len; _i++) {
el = _ref9[_i];
_results.push($(el).css({
zIndex: parseInt((_ref10 = $(el).css('zIndex')) != null ? _ref10 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref8, _results;
_ref8 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref8.length; _i < _len; i = ++_i) {
el = _ref8[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref10, _ref8, _ref9, _results, _results1;
if (!_this.dragState.cards) {
_ref8 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref8.length; _i < _len; i = ++_i) {
el = _ref8[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref9, _results1;
_ref9 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref9.length; _j < _len1; _j++) {
e = _ref9[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref9 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref9.length; _j < _len1; _j++) {
dropZone = _ref9[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref10 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref10.length; _k < _len2; _k++) {
controller = _ref10[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref8, _ref9;
dropZones = [];
_ref8 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref8.length; _i < _len; i = ++_i) {
locator = _ref8[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref9 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref9.length; _j < _len1; i = ++_j) {
locator = _ref9[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref8, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref8 = this.model.foundations.length; 0 <= _ref8 ? _i < _ref8 : _i > _ref8; foundationIndex = 0 <= _ref8 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref8 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref8;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref9 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref9;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref10, _ref11;
_ref10 = [this.size.width, this.size.height], width = _ref10[0], height = _ref10[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref11 = [2 * width, 4 * height], left = _ref11[0], top = _ref11[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref10, _results;
_results = [];
for (i = _i = 0, _ref10 = this.model.numberOfFoundations; 0 <= _ref10 ? _i < _ref10 : _i > _ref10; i = 0 <= _ref10 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref10, _results;
_results = [];
for (i = _i = 0, _ref10 = this.model.numberOfTableauPiles; 0 <= _ref10 ? _i < _ref10 : _i > _ref10; i = 0 <= _ref10 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref10, _ref11,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref10 = this.model.numberOfFoundations; 0 <= _ref10 ? _i < _ref10 : _i > _ref10; i = 0 <= _ref10 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref11 = this.model.numberOfTableauPiles; 0 <= _ref11 ? _j < _ref11 : _j > _ref11; i = 0 <= _ref11 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref10, _ref11;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref10 = this.cardControllers;
for (id in _ref10) {
controller = _ref10[id];
controller.destroy();
}
this.cardControllers = {};
_ref11 = this.model.deck;
for (_i = 0, _len = _ref11.length; _i < _len; _i++) {
card = _ref11[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref10, _ref11, _ref12, _ref13, _ref14, _results;
zIndex = 1000;
_ref10 = this.model.stock;
for (_i = 0, _len = _ref10.length; _i < _len; _i++) {
card = _ref10[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref11 = this.model.waste;
for (index = _j = 0, _len1 = _ref11.length; _j < _len1; index = ++_j) {
card = _ref11[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref12 = this.model.foundations;
for (index = _k = 0, _len2 = _ref12.length; _k < _len2; index = ++_k) {
foundation = _ref12[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref13 = this.model.faceDownTableauPiles.length; 0 <= _ref13 ? _m < _ref13 : _m > _ref13; i = 0 <= _ref13 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref14 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref14.length; _n < _len4; _n++) {
card = _ref14[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref15, _results1;
_ref15 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref15.length; _o < _len5; _o++) {
card = _ref15[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref10;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref10 = this.model.waste.length) && _ref10 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref10, _ref11, _ref12, _ref13, _ref14, _ref15, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref10 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref10.length; _i < _len; _i++) {
controller = _ref10[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref11, _results;
_ref11 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref11.length; _j < _len1; _j++) {
c = _ref11[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref11 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref11.length; _j < _len1; _j++) {
controller = _ref11[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref12 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref12.length; _k < _len2; _k++) {
controller = _ref12[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref13 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref13.length; _l < _len3; _l++) {
controller = _ref13[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref14 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref14.length; _m < _len4; _m++) {
controller = _ref14[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref15 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref15.length; _n < _len5; _n++) {
controller = _ref15[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref10,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref10 = [['waste']].concat(__slice.call((function() {
var _j, _ref10, _results;
_results = [];
for (i = _j = 0, _ref10 = this.model.faceUpTableauPiles.length; 0 <= _ref10 ? _j < _ref10 : _j > _ref10; i = 0 <= _ref10 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref10.length; _i < _len; _i++) {
locator = _ref10[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref10, _ref11, _ref12, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref10 = _this.dragState.cards) != null ? _ref10 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref11, _results;
_ref11 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref11.length; _i < _len; _i++) {
c = _ref11[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref11, _results;
_ref11 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref11.length; _i < _len; _i++) {
el = _ref11[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref11 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref11.length; _i < _len; _i++) {
el = _ref11[_i];
_results.push($(el).css({
zIndex: parseInt((_ref12 = $(el).css('zIndex')) != null ? _ref12 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref10, _results;
_ref10 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref10.length; _i < _len; i = ++_i) {
el = _ref10[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref10, _ref11, _ref12, _results, _results1;
if (!_this.dragState.cards) {
_ref10 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref10.length; _i < _len; i = ++_i) {
el = _ref10[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref11, _results1;
_ref11 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref11.length; _j < _len1; _j++) {
e = _ref11[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref11 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref11.length; _j < _len1; _j++) {
dropZone = _ref11[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref12 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref12.length; _k < _len2; _k++) {
controller = _ref12[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref10, _ref11;
dropZones = [];
_ref10 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref10.length; _i < _len; i = ++_i) {
locator = _ref10[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref11 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref11.length; _j < _len1; i = ++_j) {
locator = _ref11[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref10, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref10 = this.model.foundations.length; 0 <= _ref10 ? _i < _ref10 : _i > _ref10; foundationIndex = 0 <= _ref10 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref10 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref10;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref11 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref11;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref12, _ref13;
_ref12 = [this.size.width, this.size.height], width = _ref12[0], height = _ref12[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref13 = [2 * width, 4 * height], left = _ref13[0], top = _ref13[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref12, _results;
_results = [];
for (i = _i = 0, _ref12 = this.model.numberOfFoundations; 0 <= _ref12 ? _i < _ref12 : _i > _ref12; i = 0 <= _ref12 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref12, _results;
_results = [];
for (i = _i = 0, _ref12 = this.model.numberOfTableauPiles; 0 <= _ref12 ? _i < _ref12 : _i > _ref12; i = 0 <= _ref12 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref12, _ref13,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref12 = this.model.numberOfFoundations; 0 <= _ref12 ? _i < _ref12 : _i > _ref12; i = 0 <= _ref12 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref13 = this.model.numberOfTableauPiles; 0 <= _ref13 ? _j < _ref13 : _j > _ref13; i = 0 <= _ref13 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref12, _ref13;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref12 = this.cardControllers;
for (id in _ref12) {
controller = _ref12[id];
controller.destroy();
}
this.cardControllers = {};
_ref13 = this.model.deck;
for (_i = 0, _len = _ref13.length; _i < _len; _i++) {
card = _ref13[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref12, _ref13, _ref14, _ref15, _ref16, _results;
zIndex = 1000;
_ref12 = this.model.stock;
for (_i = 0, _len = _ref12.length; _i < _len; _i++) {
card = _ref12[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref13 = this.model.waste;
for (index = _j = 0, _len1 = _ref13.length; _j < _len1; index = ++_j) {
card = _ref13[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref14 = this.model.foundations;
for (index = _k = 0, _len2 = _ref14.length; _k < _len2; index = ++_k) {
foundation = _ref14[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref15 = this.model.faceDownTableauPiles.length; 0 <= _ref15 ? _m < _ref15 : _m > _ref15; i = 0 <= _ref15 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref16 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref16.length; _n < _len4; _n++) {
card = _ref16[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref17, _results1;
_ref17 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref17.length; _o < _len5; _o++) {
card = _ref17[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref12;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref12 = this.model.waste.length) && _ref12 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref12, _ref13, _ref14, _ref15, _ref16, _ref17, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref12 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref12.length; _i < _len; _i++) {
controller = _ref12[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref13, _results;
_ref13 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref13.length; _j < _len1; _j++) {
c = _ref13[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref13 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref13.length; _j < _len1; _j++) {
controller = _ref13[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref14 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref14.length; _k < _len2; _k++) {
controller = _ref14[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref15 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref15.length; _l < _len3; _l++) {
controller = _ref15[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref16 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref16.length; _m < _len4; _m++) {
controller = _ref16[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref17 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref17.length; _n < _len5; _n++) {
controller = _ref17[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref12,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref12 = [['waste']].concat(__slice.call((function() {
var _j, _ref12, _results;
_results = [];
for (i = _j = 0, _ref12 = this.model.faceUpTableauPiles.length; 0 <= _ref12 ? _j < _ref12 : _j > _ref12; i = 0 <= _ref12 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref12.length; _i < _len; _i++) {
locator = _ref12[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref12, _ref13, _ref14, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref12 = _this.dragState.cards) != null ? _ref12 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref13, _results;
_ref13 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref13.length; _i < _len; _i++) {
c = _ref13[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref13, _results;
_ref13 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref13.length; _i < _len; _i++) {
el = _ref13[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref13 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref13.length; _i < _len; _i++) {
el = _ref13[_i];
_results.push($(el).css({
zIndex: parseInt((_ref14 = $(el).css('zIndex')) != null ? _ref14 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref12, _results;
_ref12 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref12.length; _i < _len; i = ++_i) {
el = _ref12[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref12, _ref13, _ref14, _results, _results1;
if (!_this.dragState.cards) {
_ref12 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref12.length; _i < _len; i = ++_i) {
el = _ref12[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref13, _results1;
_ref13 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref13.length; _j < _len1; _j++) {
e = _ref13[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref13 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref13.length; _j < _len1; _j++) {
dropZone = _ref13[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref14 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref14.length; _k < _len2; _k++) {
controller = _ref14[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref12, _ref13;
dropZones = [];
_ref12 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref12.length; _i < _len; i = ++_i) {
locator = _ref12[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref13 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref13.length; _j < _len1; i = ++_j) {
locator = _ref13[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref12, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref12 = this.model.foundations.length; 0 <= _ref12 ? _i < _ref12 : _i > _ref12; foundationIndex = 0 <= _ref12 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref12 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref12;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref13 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref13;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref14, _ref15;
_ref14 = [this.size.width, this.size.height], width = _ref14[0], height = _ref14[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref15 = [2 * width, 4 * height], left = _ref15[0], top = _ref15[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref14, _results;
_results = [];
for (i = _i = 0, _ref14 = this.model.numberOfFoundations; 0 <= _ref14 ? _i < _ref14 : _i > _ref14; i = 0 <= _ref14 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref14, _results;
_results = [];
for (i = _i = 0, _ref14 = this.model.numberOfTableauPiles; 0 <= _ref14 ? _i < _ref14 : _i > _ref14; i = 0 <= _ref14 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref14, _ref15,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref14 = this.model.numberOfFoundations; 0 <= _ref14 ? _i < _ref14 : _i > _ref14; i = 0 <= _ref14 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref15 = this.model.numberOfTableauPiles; 0 <= _ref15 ? _j < _ref15 : _j > _ref15; i = 0 <= _ref15 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref14, _ref15;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref14 = this.cardControllers;
for (id in _ref14) {
controller = _ref14[id];
controller.destroy();
}
this.cardControllers = {};
_ref15 = this.model.deck;
for (_i = 0, _len = _ref15.length; _i < _len; _i++) {
card = _ref15[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref14, _ref15, _ref16, _ref17, _ref18, _results;
zIndex = 1000;
_ref14 = this.model.stock;
for (_i = 0, _len = _ref14.length; _i < _len; _i++) {
card = _ref14[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref15 = this.model.waste;
for (index = _j = 0, _len1 = _ref15.length; _j < _len1; index = ++_j) {
card = _ref15[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref16 = this.model.foundations;
for (index = _k = 0, _len2 = _ref16.length; _k < _len2; index = ++_k) {
foundation = _ref16[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref17 = this.model.faceDownTableauPiles.length; 0 <= _ref17 ? _m < _ref17 : _m > _ref17; i = 0 <= _ref17 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref18 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref18.length; _n < _len4; _n++) {
card = _ref18[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref19, _results1;
_ref19 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref19.length; _o < _len5; _o++) {
card = _ref19[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref14;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref14 = this.model.waste.length) && _ref14 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref14, _ref15, _ref16, _ref17, _ref18, _ref19, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref14 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref14.length; _i < _len; _i++) {
controller = _ref14[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref15, _results;
_ref15 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref15.length; _j < _len1; _j++) {
c = _ref15[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref15 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref15.length; _j < _len1; _j++) {
controller = _ref15[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref16 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref16.length; _k < _len2; _k++) {
controller = _ref16[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref17 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref17.length; _l < _len3; _l++) {
controller = _ref17[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref18 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref18.length; _m < _len4; _m++) {
controller = _ref18[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref19 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref19.length; _n < _len5; _n++) {
controller = _ref19[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref14,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref14 = [['waste']].concat(__slice.call((function() {
var _j, _ref14, _results;
_results = [];
for (i = _j = 0, _ref14 = this.model.faceUpTableauPiles.length; 0 <= _ref14 ? _j < _ref14 : _j > _ref14; i = 0 <= _ref14 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref14.length; _i < _len; _i++) {
locator = _ref14[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref14, _ref15, _ref16, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref14 = _this.dragState.cards) != null ? _ref14 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref15, _results;
_ref15 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref15.length; _i < _len; _i++) {
c = _ref15[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref15, _results;
_ref15 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref15.length; _i < _len; _i++) {
el = _ref15[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref15 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref15.length; _i < _len; _i++) {
el = _ref15[_i];
_results.push($(el).css({
zIndex: parseInt((_ref16 = $(el).css('zIndex')) != null ? _ref16 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref14, _results;
_ref14 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref14.length; _i < _len; i = ++_i) {
el = _ref14[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref14, _ref15, _ref16, _results, _results1;
if (!_this.dragState.cards) {
_ref14 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref14.length; _i < _len; i = ++_i) {
el = _ref14[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref15, _results1;
_ref15 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref15.length; _j < _len1; _j++) {
e = _ref15[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref15 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref15.length; _j < _len1; _j++) {
dropZone = _ref15[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref16 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref16.length; _k < _len2; _k++) {
controller = _ref16[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref14, _ref15;
dropZones = [];
_ref14 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref14.length; _i < _len; i = ++_i) {
locator = _ref14[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref15 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref15.length; _j < _len1; i = ++_j) {
locator = _ref15[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref14, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref14 = this.model.foundations.length; 0 <= _ref14 ? _i < _ref14 : _i > _ref14; foundationIndex = 0 <= _ref14 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref14 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref14;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref15 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref15;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref16, _ref17;
_ref16 = [this.size.width, this.size.height], width = _ref16[0], height = _ref16[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref17 = [2 * width, 4 * height], left = _ref17[0], top = _ref17[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref16, _results;
_results = [];
for (i = _i = 0, _ref16 = this.model.numberOfFoundations; 0 <= _ref16 ? _i < _ref16 : _i > _ref16; i = 0 <= _ref16 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref16, _results;
_results = [];
for (i = _i = 0, _ref16 = this.model.numberOfTableauPiles; 0 <= _ref16 ? _i < _ref16 : _i > _ref16; i = 0 <= _ref16 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref16, _ref17,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref16 = this.model.numberOfFoundations; 0 <= _ref16 ? _i < _ref16 : _i > _ref16; i = 0 <= _ref16 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref17 = this.model.numberOfTableauPiles; 0 <= _ref17 ? _j < _ref17 : _j > _ref17; i = 0 <= _ref17 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref16, _ref17;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref16 = this.cardControllers;
for (id in _ref16) {
controller = _ref16[id];
controller.destroy();
}
this.cardControllers = {};
_ref17 = this.model.deck;
for (_i = 0, _len = _ref17.length; _i < _len; _i++) {
card = _ref17[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref16, _ref17, _ref18, _ref19, _ref20, _results;
zIndex = 1000;
_ref16 = this.model.stock;
for (_i = 0, _len = _ref16.length; _i < _len; _i++) {
card = _ref16[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref17 = this.model.waste;
for (index = _j = 0, _len1 = _ref17.length; _j < _len1; index = ++_j) {
card = _ref17[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref18 = this.model.foundations;
for (index = _k = 0, _len2 = _ref18.length; _k < _len2; index = ++_k) {
foundation = _ref18[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref19 = this.model.faceDownTableauPiles.length; 0 <= _ref19 ? _m < _ref19 : _m > _ref19; i = 0 <= _ref19 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref20 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref20.length; _n < _len4; _n++) {
card = _ref20[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref21, _results1;
_ref21 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref21.length; _o < _len5; _o++) {
card = _ref21[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref16;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref16 = this.model.waste.length) && _ref16 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref16, _ref17, _ref18, _ref19, _ref20, _ref21, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref16 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref16.length; _i < _len; _i++) {
controller = _ref16[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref17, _results;
_ref17 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref17.length; _j < _len1; _j++) {
c = _ref17[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref17 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref17.length; _j < _len1; _j++) {
controller = _ref17[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref18 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref18.length; _k < _len2; _k++) {
controller = _ref18[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref19 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref19.length; _l < _len3; _l++) {
controller = _ref19[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref20 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref20.length; _m < _len4; _m++) {
controller = _ref20[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref21 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref21.length; _n < _len5; _n++) {
controller = _ref21[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref16,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref16 = [['waste']].concat(__slice.call((function() {
var _j, _ref16, _results;
_results = [];
for (i = _j = 0, _ref16 = this.model.faceUpTableauPiles.length; 0 <= _ref16 ? _j < _ref16 : _j > _ref16; i = 0 <= _ref16 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref16.length; _i < _len; _i++) {
locator = _ref16[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref16, _ref17, _ref18, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref16 = _this.dragState.cards) != null ? _ref16 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref17, _results;
_ref17 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref17.length; _i < _len; _i++) {
c = _ref17[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref17, _results;
_ref17 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref17.length; _i < _len; _i++) {
el = _ref17[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref17 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref17.length; _i < _len; _i++) {
el = _ref17[_i];
_results.push($(el).css({
zIndex: parseInt((_ref18 = $(el).css('zIndex')) != null ? _ref18 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref16, _results;
_ref16 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref16.length; _i < _len; i = ++_i) {
el = _ref16[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref16, _ref17, _ref18, _results, _results1;
if (!_this.dragState.cards) {
_ref16 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref16.length; _i < _len; i = ++_i) {
el = _ref16[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref17, _results1;
_ref17 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref17.length; _j < _len1; _j++) {
e = _ref17[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref17 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref17.length; _j < _len1; _j++) {
dropZone = _ref17[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref18 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref18.length; _k < _len2; _k++) {
controller = _ref18[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref16, _ref17;
dropZones = [];
_ref16 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref16.length; _i < _len; i = ++_i) {
locator = _ref16[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref17 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref17.length; _j < _len1; i = ++_j) {
locator = _ref17[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref16, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref16 = this.model.foundations.length; 0 <= _ref16 ? _i < _ref16 : _i > _ref16; foundationIndex = 0 <= _ref16 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref16 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref16;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref17 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref17;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref18, _ref19;
_ref18 = [this.size.width, this.size.height], width = _ref18[0], height = _ref18[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref19 = [2 * width, 4 * height], left = _ref19[0], top = _ref19[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref18, _results;
_results = [];
for (i = _i = 0, _ref18 = this.model.numberOfFoundations; 0 <= _ref18 ? _i < _ref18 : _i > _ref18; i = 0 <= _ref18 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref18, _results;
_results = [];
for (i = _i = 0, _ref18 = this.model.numberOfTableauPiles; 0 <= _ref18 ? _i < _ref18 : _i > _ref18; i = 0 <= _ref18 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref18, _ref19,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref18 = this.model.numberOfFoundations; 0 <= _ref18 ? _i < _ref18 : _i > _ref18; i = 0 <= _ref18 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref19 = this.model.numberOfTableauPiles; 0 <= _ref19 ? _j < _ref19 : _j > _ref19; i = 0 <= _ref19 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref18, _ref19;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref18 = this.cardControllers;
for (id in _ref18) {
controller = _ref18[id];
controller.destroy();
}
this.cardControllers = {};
_ref19 = this.model.deck;
for (_i = 0, _len = _ref19.length; _i < _len; _i++) {
card = _ref19[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref18, _ref19, _ref20, _ref21, _ref22, _results;
zIndex = 1000;
_ref18 = this.model.stock;
for (_i = 0, _len = _ref18.length; _i < _len; _i++) {
card = _ref18[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref19 = this.model.waste;
for (index = _j = 0, _len1 = _ref19.length; _j < _len1; index = ++_j) {
card = _ref19[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref20 = this.model.foundations;
for (index = _k = 0, _len2 = _ref20.length; _k < _len2; index = ++_k) {
foundation = _ref20[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref21 = this.model.faceDownTableauPiles.length; 0 <= _ref21 ? _m < _ref21 : _m > _ref21; i = 0 <= _ref21 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref22 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref22.length; _n < _len4; _n++) {
card = _ref22[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref23, _results1;
_ref23 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref23.length; _o < _len5; _o++) {
card = _ref23[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref18;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref18 = this.model.waste.length) && _ref18 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref18, _ref19, _ref20, _ref21, _ref22, _ref23, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref18 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref18.length; _i < _len; _i++) {
controller = _ref18[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref19, _results;
_ref19 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref19.length; _j < _len1; _j++) {
c = _ref19[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref19 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref19.length; _j < _len1; _j++) {
controller = _ref19[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref20 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref20.length; _k < _len2; _k++) {
controller = _ref20[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref21 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref21.length; _l < _len3; _l++) {
controller = _ref21[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref22 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref22.length; _m < _len4; _m++) {
controller = _ref22[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref23 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref23.length; _n < _len5; _n++) {
controller = _ref23[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref18,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref18 = [['waste']].concat(__slice.call((function() {
var _j, _ref18, _results;
_results = [];
for (i = _j = 0, _ref18 = this.model.faceUpTableauPiles.length; 0 <= _ref18 ? _j < _ref18 : _j > _ref18; i = 0 <= _ref18 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref18.length; _i < _len; _i++) {
locator = _ref18[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref18, _ref19, _ref20, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref18 = _this.dragState.cards) != null ? _ref18 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref19, _results;
_ref19 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref19.length; _i < _len; _i++) {
c = _ref19[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref19, _results;
_ref19 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref19.length; _i < _len; _i++) {
el = _ref19[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref19 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref19.length; _i < _len; _i++) {
el = _ref19[_i];
_results.push($(el).css({
zIndex: parseInt((_ref20 = $(el).css('zIndex')) != null ? _ref20 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref18, _results;
_ref18 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref18.length; _i < _len; i = ++_i) {
el = _ref18[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref18, _ref19, _ref20, _results, _results1;
if (!_this.dragState.cards) {
_ref18 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref18.length; _i < _len; i = ++_i) {
el = _ref18[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref19, _results1;
_ref19 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref19.length; _j < _len1; _j++) {
e = _ref19[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref19 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref19.length; _j < _len1; _j++) {
dropZone = _ref19[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref20 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref20.length; _k < _len2; _k++) {
controller = _ref20[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref18, _ref19;
dropZones = [];
_ref18 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref18.length; _i < _len; i = ++_i) {
locator = _ref18[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref19 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref19.length; _j < _len1; i = ++_j) {
locator = _ref19[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref18, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref18 = this.model.foundations.length; 0 <= _ref18 ? _i < _ref18 : _i > _ref18; foundationIndex = 0 <= _ref18 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref18 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref18;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref19 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref19;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref20, _ref21;
_ref20 = [this.size.width, this.size.height], width = _ref20[0], height = _ref20[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref21 = [2 * width, 4 * height], left = _ref21[0], top = _ref21[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref20, _results;
_results = [];
for (i = _i = 0, _ref20 = this.model.numberOfFoundations; 0 <= _ref20 ? _i < _ref20 : _i > _ref20; i = 0 <= _ref20 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref20, _results;
_results = [];
for (i = _i = 0, _ref20 = this.model.numberOfTableauPiles; 0 <= _ref20 ? _i < _ref20 : _i > _ref20; i = 0 <= _ref20 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref20, _ref21,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref20 = this.model.numberOfFoundations; 0 <= _ref20 ? _i < _ref20 : _i > _ref20; i = 0 <= _ref20 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref21 = this.model.numberOfTableauPiles; 0 <= _ref21 ? _j < _ref21 : _j > _ref21; i = 0 <= _ref21 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref20, _ref21;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref20 = this.cardControllers;
for (id in _ref20) {
controller = _ref20[id];
controller.destroy();
}
this.cardControllers = {};
_ref21 = this.model.deck;
for (_i = 0, _len = _ref21.length; _i < _len; _i++) {
card = _ref21[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref20, _ref21, _ref22, _ref23, _ref24, _results;
zIndex = 1000;
_ref20 = this.model.stock;
for (_i = 0, _len = _ref20.length; _i < _len; _i++) {
card = _ref20[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref21 = this.model.waste;
for (index = _j = 0, _len1 = _ref21.length; _j < _len1; index = ++_j) {
card = _ref21[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref22 = this.model.foundations;
for (index = _k = 0, _len2 = _ref22.length; _k < _len2; index = ++_k) {
foundation = _ref22[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref23 = this.model.faceDownTableauPiles.length; 0 <= _ref23 ? _m < _ref23 : _m > _ref23; i = 0 <= _ref23 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref24 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref24.length; _n < _len4; _n++) {
card = _ref24[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref25, _results1;
_ref25 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref25.length; _o < _len5; _o++) {
card = _ref25[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref20;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref20 = this.model.waste.length) && _ref20 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref20, _ref21, _ref22, _ref23, _ref24, _ref25, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref20 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref20.length; _i < _len; _i++) {
controller = _ref20[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref21, _results;
_ref21 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref21.length; _j < _len1; _j++) {
c = _ref21[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref21 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref21.length; _j < _len1; _j++) {
controller = _ref21[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref22 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref22.length; _k < _len2; _k++) {
controller = _ref22[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref23 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref23.length; _l < _len3; _l++) {
controller = _ref23[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref24 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref24.length; _m < _len4; _m++) {
controller = _ref24[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref25 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref25.length; _n < _len5; _n++) {
controller = _ref25[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref20,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref20 = [['waste']].concat(__slice.call((function() {
var _j, _ref20, _results;
_results = [];
for (i = _j = 0, _ref20 = this.model.faceUpTableauPiles.length; 0 <= _ref20 ? _j < _ref20 : _j > _ref20; i = 0 <= _ref20 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref20.length; _i < _len; _i++) {
locator = _ref20[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref20, _ref21, _ref22, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref20 = _this.dragState.cards) != null ? _ref20 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref21, _results;
_ref21 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref21.length; _i < _len; _i++) {
c = _ref21[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref21, _results;
_ref21 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref21.length; _i < _len; _i++) {
el = _ref21[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref21 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref21.length; _i < _len; _i++) {
el = _ref21[_i];
_results.push($(el).css({
zIndex: parseInt((_ref22 = $(el).css('zIndex')) != null ? _ref22 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref20, _results;
_ref20 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref20.length; _i < _len; i = ++_i) {
el = _ref20[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref20, _ref21, _ref22, _results, _results1;
if (!_this.dragState.cards) {
_ref20 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref20.length; _i < _len; i = ++_i) {
el = _ref20[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref21, _results1;
_ref21 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref21.length; _j < _len1; _j++) {
e = _ref21[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref21 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref21.length; _j < _len1; _j++) {
dropZone = _ref21[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref22 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref22.length; _k < _len2; _k++) {
controller = _ref22[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref20, _ref21;
dropZones = [];
_ref20 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref20.length; _i < _len; i = ++_i) {
locator = _ref20[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref21 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref21.length; _j < _len1; i = ++_j) {
locator = _ref21[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref20, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref20 = this.model.foundations.length; 0 <= _ref20 ? _i < _ref20 : _i > _ref20; foundationIndex = 0 <= _ref20 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref20 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref20;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref21 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref21;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref22, _ref23;
_ref22 = [this.size.width, this.size.height], width = _ref22[0], height = _ref22[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref23 = [2 * width, 4 * height], left = _ref23[0], top = _ref23[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref22, _results;
_results = [];
for (i = _i = 0, _ref22 = this.model.numberOfFoundations; 0 <= _ref22 ? _i < _ref22 : _i > _ref22; i = 0 <= _ref22 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref22, _results;
_results = [];
for (i = _i = 0, _ref22 = this.model.numberOfTableauPiles; 0 <= _ref22 ? _i < _ref22 : _i > _ref22; i = 0 <= _ref22 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref22, _ref23,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref22 = this.model.numberOfFoundations; 0 <= _ref22 ? _i < _ref22 : _i > _ref22; i = 0 <= _ref22 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref23 = this.model.numberOfTableauPiles; 0 <= _ref23 ? _j < _ref23 : _j > _ref23; i = 0 <= _ref23 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref22, _ref23;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref22 = this.cardControllers;
for (id in _ref22) {
controller = _ref22[id];
controller.destroy();
}
this.cardControllers = {};
_ref23 = this.model.deck;
for (_i = 0, _len = _ref23.length; _i < _len; _i++) {
card = _ref23[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref22, _ref23, _ref24, _ref25, _ref26, _results;
zIndex = 1000;
_ref22 = this.model.stock;
for (_i = 0, _len = _ref22.length; _i < _len; _i++) {
card = _ref22[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref23 = this.model.waste;
for (index = _j = 0, _len1 = _ref23.length; _j < _len1; index = ++_j) {
card = _ref23[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref24 = this.model.foundations;
for (index = _k = 0, _len2 = _ref24.length; _k < _len2; index = ++_k) {
foundation = _ref24[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref25 = this.model.faceDownTableauPiles.length; 0 <= _ref25 ? _m < _ref25 : _m > _ref25; i = 0 <= _ref25 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref26 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref26.length; _n < _len4; _n++) {
card = _ref26[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref27, _results1;
_ref27 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref27.length; _o < _len5; _o++) {
card = _ref27[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref22;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref22 = this.model.waste.length) && _ref22 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref22, _ref23, _ref24, _ref25, _ref26, _ref27, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref22 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref22.length; _i < _len; _i++) {
controller = _ref22[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref23, _results;
_ref23 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref23.length; _j < _len1; _j++) {
c = _ref23[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref23 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref23.length; _j < _len1; _j++) {
controller = _ref23[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref24 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref24.length; _k < _len2; _k++) {
controller = _ref24[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref25 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref25.length; _l < _len3; _l++) {
controller = _ref25[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref26 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref26.length; _m < _len4; _m++) {
controller = _ref26[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref27 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref27.length; _n < _len5; _n++) {
controller = _ref27[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref22,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref22 = [['waste']].concat(__slice.call((function() {
var _j, _ref22, _results;
_results = [];
for (i = _j = 0, _ref22 = this.model.faceUpTableauPiles.length; 0 <= _ref22 ? _j < _ref22 : _j > _ref22; i = 0 <= _ref22 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref22.length; _i < _len; _i++) {
locator = _ref22[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref22, _ref23, _ref24, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref22 = _this.dragState.cards) != null ? _ref22 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref23, _results;
_ref23 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref23.length; _i < _len; _i++) {
c = _ref23[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref23, _results;
_ref23 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref23.length; _i < _len; _i++) {
el = _ref23[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref23 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref23.length; _i < _len; _i++) {
el = _ref23[_i];
_results.push($(el).css({
zIndex: parseInt((_ref24 = $(el).css('zIndex')) != null ? _ref24 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref22, _results;
_ref22 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref22.length; _i < _len; i = ++_i) {
el = _ref22[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref22, _ref23, _ref24, _results, _results1;
if (!_this.dragState.cards) {
_ref22 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref22.length; _i < _len; i = ++_i) {
el = _ref22[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref23, _results1;
_ref23 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref23.length; _j < _len1; _j++) {
e = _ref23[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref23 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref23.length; _j < _len1; _j++) {
dropZone = _ref23[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref24 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref24.length; _k < _len2; _k++) {
controller = _ref24[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref22, _ref23;
dropZones = [];
_ref22 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref22.length; _i < _len; i = ++_i) {
locator = _ref22[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref23 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref23.length; _j < _len1; i = ++_j) {
locator = _ref23[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref22, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref22 = this.model.foundations.length; 0 <= _ref22 ? _i < _ref22 : _i > _ref22; foundationIndex = 0 <= _ref22 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref22 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref22;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref23 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref23;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref24, _ref25;
_ref24 = [this.size.width, this.size.height], width = _ref24[0], height = _ref24[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref25 = [2 * width, 4 * height], left = _ref25[0], top = _ref25[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref24, _results;
_results = [];
for (i = _i = 0, _ref24 = this.model.numberOfFoundations; 0 <= _ref24 ? _i < _ref24 : _i > _ref24; i = 0 <= _ref24 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref24, _results;
_results = [];
for (i = _i = 0, _ref24 = this.model.numberOfTableauPiles; 0 <= _ref24 ? _i < _ref24 : _i > _ref24; i = 0 <= _ref24 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref24, _ref25,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref24 = this.model.numberOfFoundations; 0 <= _ref24 ? _i < _ref24 : _i > _ref24; i = 0 <= _ref24 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref25 = this.model.numberOfTableauPiles; 0 <= _ref25 ? _j < _ref25 : _j > _ref25; i = 0 <= _ref25 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref24, _ref25;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref24 = this.cardControllers;
for (id in _ref24) {
controller = _ref24[id];
controller.destroy();
}
this.cardControllers = {};
_ref25 = this.model.deck;
for (_i = 0, _len = _ref25.length; _i < _len; _i++) {
card = _ref25[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref24, _ref25, _ref26, _ref27, _ref28, _results;
zIndex = 1000;
_ref24 = this.model.stock;
for (_i = 0, _len = _ref24.length; _i < _len; _i++) {
card = _ref24[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref25 = this.model.waste;
for (index = _j = 0, _len1 = _ref25.length; _j < _len1; index = ++_j) {
card = _ref25[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref26 = this.model.foundations;
for (index = _k = 0, _len2 = _ref26.length; _k < _len2; index = ++_k) {
foundation = _ref26[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref27 = this.model.faceDownTableauPiles.length; 0 <= _ref27 ? _m < _ref27 : _m > _ref27; i = 0 <= _ref27 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref28 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref28.length; _n < _len4; _n++) {
card = _ref28[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref29, _results1;
_ref29 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref29.length; _o < _len5; _o++) {
card = _ref29[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref24;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref24 = this.model.waste.length) && _ref24 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref24, _ref25, _ref26, _ref27, _ref28, _ref29, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref24 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref24.length; _i < _len; _i++) {
controller = _ref24[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref25, _results;
_ref25 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref25.length; _j < _len1; _j++) {
c = _ref25[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref25 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref25.length; _j < _len1; _j++) {
controller = _ref25[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref26 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref26.length; _k < _len2; _k++) {
controller = _ref26[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref27 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref27.length; _l < _len3; _l++) {
controller = _ref27[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref28 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref28.length; _m < _len4; _m++) {
controller = _ref28[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref29 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref29.length; _n < _len5; _n++) {
controller = _ref29[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref24,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref24 = [['waste']].concat(__slice.call((function() {
var _j, _ref24, _results;
_results = [];
for (i = _j = 0, _ref24 = this.model.faceUpTableauPiles.length; 0 <= _ref24 ? _j < _ref24 : _j > _ref24; i = 0 <= _ref24 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref24.length; _i < _len; _i++) {
locator = _ref24[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref24, _ref25, _ref26, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref24 = _this.dragState.cards) != null ? _ref24 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref25, _results;
_ref25 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref25.length; _i < _len; _i++) {
c = _ref25[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref25, _results;
_ref25 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref25.length; _i < _len; _i++) {
el = _ref25[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref25 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref25.length; _i < _len; _i++) {
el = _ref25[_i];
_results.push($(el).css({
zIndex: parseInt((_ref26 = $(el).css('zIndex')) != null ? _ref26 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref24, _results;
_ref24 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref24.length; _i < _len; i = ++_i) {
el = _ref24[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref24, _ref25, _ref26, _results, _results1;
if (!_this.dragState.cards) {
_ref24 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref24.length; _i < _len; i = ++_i) {
el = _ref24[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref25, _results1;
_ref25 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref25.length; _j < _len1; _j++) {
e = _ref25[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref25 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref25.length; _j < _len1; _j++) {
dropZone = _ref25[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref26 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref26.length; _k < _len2; _k++) {
controller = _ref26[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref24, _ref25;
dropZones = [];
_ref24 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref24.length; _i < _len; i = ++_i) {
locator = _ref24[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref25 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref25.length; _j < _len1; i = ++_j) {
locator = _ref25[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref24, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref24 = this.model.foundations.length; 0 <= _ref24 ? _i < _ref24 : _i > _ref24; foundationIndex = 0 <= _ref24 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref24 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref24;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref25 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref25;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref26, _ref27;
_ref26 = [this.size.width, this.size.height], width = _ref26[0], height = _ref26[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref27 = [2 * width, 4 * height], left = _ref27[0], top = _ref27[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref26, _results;
_results = [];
for (i = _i = 0, _ref26 = this.model.numberOfFoundations; 0 <= _ref26 ? _i < _ref26 : _i > _ref26; i = 0 <= _ref26 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref26, _results;
_results = [];
for (i = _i = 0, _ref26 = this.model.numberOfTableauPiles; 0 <= _ref26 ? _i < _ref26 : _i > _ref26; i = 0 <= _ref26 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref26, _ref27,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref26 = this.model.numberOfFoundations; 0 <= _ref26 ? _i < _ref26 : _i > _ref26; i = 0 <= _ref26 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref27 = this.model.numberOfTableauPiles; 0 <= _ref27 ? _j < _ref27 : _j > _ref27; i = 0 <= _ref27 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref26, _ref27;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref26 = this.cardControllers;
for (id in _ref26) {
controller = _ref26[id];
controller.destroy();
}
this.cardControllers = {};
_ref27 = this.model.deck;
for (_i = 0, _len = _ref27.length; _i < _len; _i++) {
card = _ref27[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref26, _ref27, _ref28, _ref29, _ref30, _results;
zIndex = 1000;
_ref26 = this.model.stock;
for (_i = 0, _len = _ref26.length; _i < _len; _i++) {
card = _ref26[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref27 = this.model.waste;
for (index = _j = 0, _len1 = _ref27.length; _j < _len1; index = ++_j) {
card = _ref27[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref28 = this.model.foundations;
for (index = _k = 0, _len2 = _ref28.length; _k < _len2; index = ++_k) {
foundation = _ref28[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref29 = this.model.faceDownTableauPiles.length; 0 <= _ref29 ? _m < _ref29 : _m > _ref29; i = 0 <= _ref29 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref30 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref30.length; _n < _len4; _n++) {
card = _ref30[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref31, _results1;
_ref31 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref31.length; _o < _len5; _o++) {
card = _ref31[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref26;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref26 = this.model.waste.length) && _ref26 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref26, _ref27, _ref28, _ref29, _ref30, _ref31, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref26 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref26.length; _i < _len; _i++) {
controller = _ref26[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref27, _results;
_ref27 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref27.length; _j < _len1; _j++) {
c = _ref27[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref27 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref27.length; _j < _len1; _j++) {
controller = _ref27[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref28 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref28.length; _k < _len2; _k++) {
controller = _ref28[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref29 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref29.length; _l < _len3; _l++) {
controller = _ref29[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref30 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref30.length; _m < _len4; _m++) {
controller = _ref30[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref31 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref31.length; _n < _len5; _n++) {
controller = _ref31[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref26,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref26 = [['waste']].concat(__slice.call((function() {
var _j, _ref26, _results;
_results = [];
for (i = _j = 0, _ref26 = this.model.faceUpTableauPiles.length; 0 <= _ref26 ? _j < _ref26 : _j > _ref26; i = 0 <= _ref26 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref26.length; _i < _len; _i++) {
locator = _ref26[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref26, _ref27, _ref28, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref26 = _this.dragState.cards) != null ? _ref26 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref27, _results;
_ref27 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref27.length; _i < _len; _i++) {
c = _ref27[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref27, _results;
_ref27 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref27.length; _i < _len; _i++) {
el = _ref27[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref27 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref27.length; _i < _len; _i++) {
el = _ref27[_i];
_results.push($(el).css({
zIndex: parseInt((_ref28 = $(el).css('zIndex')) != null ? _ref28 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref26, _results;
_ref26 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref26.length; _i < _len; i = ++_i) {
el = _ref26[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref26, _ref27, _ref28, _results, _results1;
if (!_this.dragState.cards) {
_ref26 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref26.length; _i < _len; i = ++_i) {
el = _ref26[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref27, _results1;
_ref27 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref27.length; _j < _len1; _j++) {
e = _ref27[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref27 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref27.length; _j < _len1; _j++) {
dropZone = _ref27[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref28 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref28.length; _k < _len2; _k++) {
controller = _ref28[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref26, _ref27;
dropZones = [];
_ref26 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref26.length; _i < _len; i = ++_i) {
locator = _ref26[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref27 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref27.length; _j < _len1; i = ++_j) {
locator = _ref27[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref26, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref26 = this.model.foundations.length; 0 <= _ref26 ? _i < _ref26 : _i > _ref26; foundationIndex = 0 <= _ref26 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref26 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref26;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref27 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref27;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref28, _ref29;
_ref28 = [this.size.width, this.size.height], width = _ref28[0], height = _ref28[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref29 = [2 * width, 4 * height], left = _ref29[0], top = _ref29[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref28, _results;
_results = [];
for (i = _i = 0, _ref28 = this.model.numberOfFoundations; 0 <= _ref28 ? _i < _ref28 : _i > _ref28; i = 0 <= _ref28 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref28, _results;
_results = [];
for (i = _i = 0, _ref28 = this.model.numberOfTableauPiles; 0 <= _ref28 ? _i < _ref28 : _i > _ref28; i = 0 <= _ref28 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref28, _ref29,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref28 = this.model.numberOfFoundations; 0 <= _ref28 ? _i < _ref28 : _i > _ref28; i = 0 <= _ref28 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref29 = this.model.numberOfTableauPiles; 0 <= _ref29 ? _j < _ref29 : _j > _ref29; i = 0 <= _ref29 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref28, _ref29;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref28 = this.cardControllers;
for (id in _ref28) {
controller = _ref28[id];
controller.destroy();
}
this.cardControllers = {};
_ref29 = this.model.deck;
for (_i = 0, _len = _ref29.length; _i < _len; _i++) {
card = _ref29[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref28, _ref29, _ref30, _ref31, _ref32, _results;
zIndex = 1000;
_ref28 = this.model.stock;
for (_i = 0, _len = _ref28.length; _i < _len; _i++) {
card = _ref28[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref29 = this.model.waste;
for (index = _j = 0, _len1 = _ref29.length; _j < _len1; index = ++_j) {
card = _ref29[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref30 = this.model.foundations;
for (index = _k = 0, _len2 = _ref30.length; _k < _len2; index = ++_k) {
foundation = _ref30[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref31 = this.model.faceDownTableauPiles.length; 0 <= _ref31 ? _m < _ref31 : _m > _ref31; i = 0 <= _ref31 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref32 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref32.length; _n < _len4; _n++) {
card = _ref32[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref33, _results1;
_ref33 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref33.length; _o < _len5; _o++) {
card = _ref33[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref28;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref28 = this.model.waste.length) && _ref28 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref28, _ref29, _ref30, _ref31, _ref32, _ref33, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref28 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref28.length; _i < _len; _i++) {
controller = _ref28[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref29, _results;
_ref29 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref29.length; _j < _len1; _j++) {
c = _ref29[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref29 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref29.length; _j < _len1; _j++) {
controller = _ref29[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref30 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref30.length; _k < _len2; _k++) {
controller = _ref30[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref31 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref31.length; _l < _len3; _l++) {
controller = _ref31[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref32 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref32.length; _m < _len4; _m++) {
controller = _ref32[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref33 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref33.length; _n < _len5; _n++) {
controller = _ref33[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref28,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref28 = [['waste']].concat(__slice.call((function() {
var _j, _ref28, _results;
_results = [];
for (i = _j = 0, _ref28 = this.model.faceUpTableauPiles.length; 0 <= _ref28 ? _j < _ref28 : _j > _ref28; i = 0 <= _ref28 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref28.length; _i < _len; _i++) {
locator = _ref28[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref28, _ref29, _ref30, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref28 = _this.dragState.cards) != null ? _ref28 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref29, _results;
_ref29 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref29.length; _i < _len; _i++) {
c = _ref29[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref29, _results;
_ref29 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref29.length; _i < _len; _i++) {
el = _ref29[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref29 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref29.length; _i < _len; _i++) {
el = _ref29[_i];
_results.push($(el).css({
zIndex: parseInt((_ref30 = $(el).css('zIndex')) != null ? _ref30 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref28, _results;
_ref28 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref28.length; _i < _len; i = ++_i) {
el = _ref28[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref28, _ref29, _ref30, _results, _results1;
if (!_this.dragState.cards) {
_ref28 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref28.length; _i < _len; i = ++_i) {
el = _ref28[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref29, _results1;
_ref29 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref29.length; _j < _len1; _j++) {
e = _ref29[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref29 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref29.length; _j < _len1; _j++) {
dropZone = _ref29[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref30 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref30.length; _k < _len2; _k++) {
controller = _ref30[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref28, _ref29;
dropZones = [];
_ref28 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref28.length; _i < _len; i = ++_i) {
locator = _ref28[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref29 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref29.length; _j < _len1; i = ++_j) {
locator = _ref29[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref28, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref28 = this.model.foundations.length; 0 <= _ref28 ? _i < _ref28 : _i > _ref28; foundationIndex = 0 <= _ref28 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref28 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref28;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref29 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref29;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref30, _ref31;
_ref30 = [this.size.width, this.size.height], width = _ref30[0], height = _ref30[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref31 = [2 * width, 4 * height], left = _ref31[0], top = _ref31[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref30, _results;
_results = [];
for (i = _i = 0, _ref30 = this.model.numberOfFoundations; 0 <= _ref30 ? _i < _ref30 : _i > _ref30; i = 0 <= _ref30 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref30, _results;
_results = [];
for (i = _i = 0, _ref30 = this.model.numberOfTableauPiles; 0 <= _ref30 ? _i < _ref30 : _i > _ref30; i = 0 <= _ref30 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref30, _ref31,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref30 = this.model.numberOfFoundations; 0 <= _ref30 ? _i < _ref30 : _i > _ref30; i = 0 <= _ref30 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref31 = this.model.numberOfTableauPiles; 0 <= _ref31 ? _j < _ref31 : _j > _ref31; i = 0 <= _ref31 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref30, _ref31;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref30 = this.cardControllers;
for (id in _ref30) {
controller = _ref30[id];
controller.destroy();
}
this.cardControllers = {};
_ref31 = this.model.deck;
for (_i = 0, _len = _ref31.length; _i < _len; _i++) {
card = _ref31[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref30, _ref31, _ref32, _ref33, _ref34, _results;
zIndex = 1000;
_ref30 = this.model.stock;
for (_i = 0, _len = _ref30.length; _i < _len; _i++) {
card = _ref30[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref31 = this.model.waste;
for (index = _j = 0, _len1 = _ref31.length; _j < _len1; index = ++_j) {
card = _ref31[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref32 = this.model.foundations;
for (index = _k = 0, _len2 = _ref32.length; _k < _len2; index = ++_k) {
foundation = _ref32[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref33 = this.model.faceDownTableauPiles.length; 0 <= _ref33 ? _m < _ref33 : _m > _ref33; i = 0 <= _ref33 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref34 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref34.length; _n < _len4; _n++) {
card = _ref34[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref35, _results1;
_ref35 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref35.length; _o < _len5; _o++) {
card = _ref35[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref30;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref30 = this.model.waste.length) && _ref30 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref30, _ref31, _ref32, _ref33, _ref34, _ref35, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref30 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref30.length; _i < _len; _i++) {
controller = _ref30[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref31, _results;
_ref31 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref31.length; _j < _len1; _j++) {
c = _ref31[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref31 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref31.length; _j < _len1; _j++) {
controller = _ref31[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref32 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref32.length; _k < _len2; _k++) {
controller = _ref32[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref33 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref33.length; _l < _len3; _l++) {
controller = _ref33[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref34 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref34.length; _m < _len4; _m++) {
controller = _ref34[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref35 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref35.length; _n < _len5; _n++) {
controller = _ref35[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref30,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref30 = [['waste']].concat(__slice.call((function() {
var _j, _ref30, _results;
_results = [];
for (i = _j = 0, _ref30 = this.model.faceUpTableauPiles.length; 0 <= _ref30 ? _j < _ref30 : _j > _ref30; i = 0 <= _ref30 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref30.length; _i < _len; _i++) {
locator = _ref30[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref30, _ref31, _ref32, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref30 = _this.dragState.cards) != null ? _ref30 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref31, _results;
_ref31 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref31.length; _i < _len; _i++) {
c = _ref31[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref31, _results;
_ref31 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref31.length; _i < _len; _i++) {
el = _ref31[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref31 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref31.length; _i < _len; _i++) {
el = _ref31[_i];
_results.push($(el).css({
zIndex: parseInt((_ref32 = $(el).css('zIndex')) != null ? _ref32 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref30, _results;
_ref30 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref30.length; _i < _len; i = ++_i) {
el = _ref30[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref30, _ref31, _ref32, _results, _results1;
if (!_this.dragState.cards) {
_ref30 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref30.length; _i < _len; i = ++_i) {
el = _ref30[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref31, _results1;
_ref31 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref31.length; _j < _len1; _j++) {
e = _ref31[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref31 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref31.length; _j < _len1; _j++) {
dropZone = _ref31[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref32 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref32.length; _k < _len2; _k++) {
controller = _ref32[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref30, _ref31;
dropZones = [];
_ref30 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref30.length; _i < _len; i = ++_i) {
locator = _ref30[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref31 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref31.length; _j < _len1; i = ++_j) {
locator = _ref31[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref30, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref30 = this.model.foundations.length; 0 <= _ref30 ? _i < _ref30 : _i > _ref30; foundationIndex = 0 <= _ref30 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref30 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref30;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref31 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref31;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref32, _ref33;
_ref32 = [this.size.width, this.size.height], width = _ref32[0], height = _ref32[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref33 = [2 * width, 4 * height], left = _ref33[0], top = _ref33[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref32, _results;
_results = [];
for (i = _i = 0, _ref32 = this.model.numberOfFoundations; 0 <= _ref32 ? _i < _ref32 : _i > _ref32; i = 0 <= _ref32 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref32, _results;
_results = [];
for (i = _i = 0, _ref32 = this.model.numberOfTableauPiles; 0 <= _ref32 ? _i < _ref32 : _i > _ref32; i = 0 <= _ref32 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref32, _ref33,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref32 = this.model.numberOfFoundations; 0 <= _ref32 ? _i < _ref32 : _i > _ref32; i = 0 <= _ref32 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref33 = this.model.numberOfTableauPiles; 0 <= _ref33 ? _j < _ref33 : _j > _ref33; i = 0 <= _ref33 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref32, _ref33;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref32 = this.cardControllers;
for (id in _ref32) {
controller = _ref32[id];
controller.destroy();
}
this.cardControllers = {};
_ref33 = this.model.deck;
for (_i = 0, _len = _ref33.length; _i < _len; _i++) {
card = _ref33[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref32, _ref33, _ref34, _ref35, _ref36, _results;
zIndex = 1000;
_ref32 = this.model.stock;
for (_i = 0, _len = _ref32.length; _i < _len; _i++) {
card = _ref32[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref33 = this.model.waste;
for (index = _j = 0, _len1 = _ref33.length; _j < _len1; index = ++_j) {
card = _ref33[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref34 = this.model.foundations;
for (index = _k = 0, _len2 = _ref34.length; _k < _len2; index = ++_k) {
foundation = _ref34[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref35 = this.model.faceDownTableauPiles.length; 0 <= _ref35 ? _m < _ref35 : _m > _ref35; i = 0 <= _ref35 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref36 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref36.length; _n < _len4; _n++) {
card = _ref36[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref37, _results1;
_ref37 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref37.length; _o < _len5; _o++) {
card = _ref37[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref32;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref32 = this.model.waste.length) && _ref32 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref32, _ref33, _ref34, _ref35, _ref36, _ref37, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref32 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref32.length; _i < _len; _i++) {
controller = _ref32[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref33, _results;
_ref33 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref33.length; _j < _len1; _j++) {
c = _ref33[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref33 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref33.length; _j < _len1; _j++) {
controller = _ref33[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref34 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref34.length; _k < _len2; _k++) {
controller = _ref34[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref35 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref35.length; _l < _len3; _l++) {
controller = _ref35[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref36 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref36.length; _m < _len4; _m++) {
controller = _ref36[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref37 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref37.length; _n < _len5; _n++) {
controller = _ref37[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref32,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref32 = [['waste']].concat(__slice.call((function() {
var _j, _ref32, _results;
_results = [];
for (i = _j = 0, _ref32 = this.model.faceUpTableauPiles.length; 0 <= _ref32 ? _j < _ref32 : _j > _ref32; i = 0 <= _ref32 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref32.length; _i < _len; _i++) {
locator = _ref32[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref32, _ref33, _ref34, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref32 = _this.dragState.cards) != null ? _ref32 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref33, _results;
_ref33 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref33.length; _i < _len; _i++) {
c = _ref33[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref33, _results;
_ref33 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref33.length; _i < _len; _i++) {
el = _ref33[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref33 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref33.length; _i < _len; _i++) {
el = _ref33[_i];
_results.push($(el).css({
zIndex: parseInt((_ref34 = $(el).css('zIndex')) != null ? _ref34 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref32, _results;
_ref32 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref32.length; _i < _len; i = ++_i) {
el = _ref32[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref32, _ref33, _ref34, _results, _results1;
if (!_this.dragState.cards) {
_ref32 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref32.length; _i < _len; i = ++_i) {
el = _ref32[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref33, _results1;
_ref33 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref33.length; _j < _len1; _j++) {
e = _ref33[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref33 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref33.length; _j < _len1; _j++) {
dropZone = _ref33[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref34 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref34.length; _k < _len2; _k++) {
controller = _ref34[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref32, _ref33;
dropZones = [];
_ref32 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref32.length; _i < _len; i = ++_i) {
locator = _ref32[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref33 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref33.length; _j < _len1; i = ++_j) {
locator = _ref33[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref32, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref32 = this.model.foundations.length; 0 <= _ref32 ? _i < _ref32 : _i > _ref32; foundationIndex = 0 <= _ref32 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref32 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref32;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref33 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref33;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref34, _ref35;
_ref34 = [this.size.width, this.size.height], width = _ref34[0], height = _ref34[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref35 = [2 * width, 4 * height], left = _ref35[0], top = _ref35[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref34, _results;
_results = [];
for (i = _i = 0, _ref34 = this.model.numberOfFoundations; 0 <= _ref34 ? _i < _ref34 : _i > _ref34; i = 0 <= _ref34 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref34, _results;
_results = [];
for (i = _i = 0, _ref34 = this.model.numberOfTableauPiles; 0 <= _ref34 ? _i < _ref34 : _i > _ref34; i = 0 <= _ref34 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref34, _ref35,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref34 = this.model.numberOfFoundations; 0 <= _ref34 ? _i < _ref34 : _i > _ref34; i = 0 <= _ref34 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref35 = this.model.numberOfTableauPiles; 0 <= _ref35 ? _j < _ref35 : _j > _ref35; i = 0 <= _ref35 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref34, _ref35;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref34 = this.cardControllers;
for (id in _ref34) {
controller = _ref34[id];
controller.destroy();
}
this.cardControllers = {};
_ref35 = this.model.deck;
for (_i = 0, _len = _ref35.length; _i < _len; _i++) {
card = _ref35[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref34, _ref35, _ref36, _ref37, _ref38, _results;
zIndex = 1000;
_ref34 = this.model.stock;
for (_i = 0, _len = _ref34.length; _i < _len; _i++) {
card = _ref34[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref35 = this.model.waste;
for (index = _j = 0, _len1 = _ref35.length; _j < _len1; index = ++_j) {
card = _ref35[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref36 = this.model.foundations;
for (index = _k = 0, _len2 = _ref36.length; _k < _len2; index = ++_k) {
foundation = _ref36[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref37 = this.model.faceDownTableauPiles.length; 0 <= _ref37 ? _m < _ref37 : _m > _ref37; i = 0 <= _ref37 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref38 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref38.length; _n < _len4; _n++) {
card = _ref38[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref39, _results1;
_ref39 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref39.length; _o < _len5; _o++) {
card = _ref39[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref34;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref34 = this.model.waste.length) && _ref34 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref34, _ref35, _ref36, _ref37, _ref38, _ref39, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref34 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref34.length; _i < _len; _i++) {
controller = _ref34[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref35, _results;
_ref35 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref35.length; _j < _len1; _j++) {
c = _ref35[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref35 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref35.length; _j < _len1; _j++) {
controller = _ref35[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref36 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref36.length; _k < _len2; _k++) {
controller = _ref36[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref37 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref37.length; _l < _len3; _l++) {
controller = _ref37[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref38 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref38.length; _m < _len4; _m++) {
controller = _ref38[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref39 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref39.length; _n < _len5; _n++) {
controller = _ref39[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref34,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref34 = [['waste']].concat(__slice.call((function() {
var _j, _ref34, _results;
_results = [];
for (i = _j = 0, _ref34 = this.model.faceUpTableauPiles.length; 0 <= _ref34 ? _j < _ref34 : _j > _ref34; i = 0 <= _ref34 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref34.length; _i < _len; _i++) {
locator = _ref34[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref34, _ref35, _ref36, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref34 = _this.dragState.cards) != null ? _ref34 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref35, _results;
_ref35 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref35.length; _i < _len; _i++) {
c = _ref35[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref35, _results;
_ref35 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref35.length; _i < _len; _i++) {
el = _ref35[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref35 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref35.length; _i < _len; _i++) {
el = _ref35[_i];
_results.push($(el).css({
zIndex: parseInt((_ref36 = $(el).css('zIndex')) != null ? _ref36 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref34, _results;
_ref34 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref34.length; _i < _len; i = ++_i) {
el = _ref34[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref34, _ref35, _ref36, _results, _results1;
if (!_this.dragState.cards) {
_ref34 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref34.length; _i < _len; i = ++_i) {
el = _ref34[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref35, _results1;
_ref35 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref35.length; _j < _len1; _j++) {
e = _ref35[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref35 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref35.length; _j < _len1; _j++) {
dropZone = _ref35[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref36 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref36.length; _k < _len2; _k++) {
controller = _ref36[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref34, _ref35;
dropZones = [];
_ref34 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref34.length; _i < _len; i = ++_i) {
locator = _ref34[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref35 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref35.length; _j < _len1; i = ++_j) {
locator = _ref35[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref34, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref34 = this.model.foundations.length; 0 <= _ref34 ? _i < _ref34 : _i > _ref34; foundationIndex = 0 <= _ref34 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref34 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref34;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref35 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref35;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref36, _ref37;
_ref36 = [this.size.width, this.size.height], width = _ref36[0], height = _ref36[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref37 = [2 * width, 4 * height], left = _ref37[0], top = _ref37[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref36, _results;
_results = [];
for (i = _i = 0, _ref36 = this.model.numberOfFoundations; 0 <= _ref36 ? _i < _ref36 : _i > _ref36; i = 0 <= _ref36 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref36, _results;
_results = [];
for (i = _i = 0, _ref36 = this.model.numberOfTableauPiles; 0 <= _ref36 ? _i < _ref36 : _i > _ref36; i = 0 <= _ref36 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref36, _ref37,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref36 = this.model.numberOfFoundations; 0 <= _ref36 ? _i < _ref36 : _i > _ref36; i = 0 <= _ref36 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref37 = this.model.numberOfTableauPiles; 0 <= _ref37 ? _j < _ref37 : _j > _ref37; i = 0 <= _ref37 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref36, _ref37;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref36 = this.cardControllers;
for (id in _ref36) {
controller = _ref36[id];
controller.destroy();
}
this.cardControllers = {};
_ref37 = this.model.deck;
for (_i = 0, _len = _ref37.length; _i < _len; _i++) {
card = _ref37[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref36, _ref37, _ref38, _ref39, _ref40, _results;
zIndex = 1000;
_ref36 = this.model.stock;
for (_i = 0, _len = _ref36.length; _i < _len; _i++) {
card = _ref36[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref37 = this.model.waste;
for (index = _j = 0, _len1 = _ref37.length; _j < _len1; index = ++_j) {
card = _ref37[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref38 = this.model.foundations;
for (index = _k = 0, _len2 = _ref38.length; _k < _len2; index = ++_k) {
foundation = _ref38[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref39 = this.model.faceDownTableauPiles.length; 0 <= _ref39 ? _m < _ref39 : _m > _ref39; i = 0 <= _ref39 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref40 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref40.length; _n < _len4; _n++) {
card = _ref40[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref41, _results1;
_ref41 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref41.length; _o < _len5; _o++) {
card = _ref41[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref36;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref36 = this.model.waste.length) && _ref36 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref36, _ref37, _ref38, _ref39, _ref40, _ref41, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref36 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref36.length; _i < _len; _i++) {
controller = _ref36[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref37, _results;
_ref37 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref37.length; _j < _len1; _j++) {
c = _ref37[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref37 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref37.length; _j < _len1; _j++) {
controller = _ref37[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref38 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref38.length; _k < _len2; _k++) {
controller = _ref38[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref39 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref39.length; _l < _len3; _l++) {
controller = _ref39[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref40 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref40.length; _m < _len4; _m++) {
controller = _ref40[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref41 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref41.length; _n < _len5; _n++) {
controller = _ref41[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref36,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref36 = [['waste']].concat(__slice.call((function() {
var _j, _ref36, _results;
_results = [];
for (i = _j = 0, _ref36 = this.model.faceUpTableauPiles.length; 0 <= _ref36 ? _j < _ref36 : _j > _ref36; i = 0 <= _ref36 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref36.length; _i < _len; _i++) {
locator = _ref36[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref36, _ref37, _ref38, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref36 = _this.dragState.cards) != null ? _ref36 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref37, _results;
_ref37 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref37.length; _i < _len; _i++) {
c = _ref37[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref37, _results;
_ref37 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref37.length; _i < _len; _i++) {
el = _ref37[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref37 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref37.length; _i < _len; _i++) {
el = _ref37[_i];
_results.push($(el).css({
zIndex: parseInt((_ref38 = $(el).css('zIndex')) != null ? _ref38 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref36, _results;
_ref36 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref36.length; _i < _len; i = ++_i) {
el = _ref36[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref36, _ref37, _ref38, _results, _results1;
if (!_this.dragState.cards) {
_ref36 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref36.length; _i < _len; i = ++_i) {
el = _ref36[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref37, _results1;
_ref37 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref37.length; _j < _len1; _j++) {
e = _ref37[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref37 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref37.length; _j < _len1; _j++) {
dropZone = _ref37[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref38 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref38.length; _k < _len2; _k++) {
controller = _ref38[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref36, _ref37;
dropZones = [];
_ref36 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref36.length; _i < _len; i = ++_i) {
locator = _ref36[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref37 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref37.length; _j < _len1; i = ++_j) {
locator = _ref37[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref36, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref36 = this.model.foundations.length; 0 <= _ref36 ? _i < _ref36 : _i > _ref36; foundationIndex = 0 <= _ref36 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref36 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref36;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref37 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref37;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref38, _ref39;
_ref38 = [this.size.width, this.size.height], width = _ref38[0], height = _ref38[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref39 = [2 * width, 4 * height], left = _ref39[0], top = _ref39[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref38, _results;
_results = [];
for (i = _i = 0, _ref38 = this.model.numberOfFoundations; 0 <= _ref38 ? _i < _ref38 : _i > _ref38; i = 0 <= _ref38 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref38, _results;
_results = [];
for (i = _i = 0, _ref38 = this.model.numberOfTableauPiles; 0 <= _ref38 ? _i < _ref38 : _i > _ref38; i = 0 <= _ref38 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref38, _ref39,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref38 = this.model.numberOfFoundations; 0 <= _ref38 ? _i < _ref38 : _i > _ref38; i = 0 <= _ref38 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref39 = this.model.numberOfTableauPiles; 0 <= _ref39 ? _j < _ref39 : _j > _ref39; i = 0 <= _ref39 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref38, _ref39;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref38 = this.cardControllers;
for (id in _ref38) {
controller = _ref38[id];
controller.destroy();
}
this.cardControllers = {};
_ref39 = this.model.deck;
for (_i = 0, _len = _ref39.length; _i < _len; _i++) {
card = _ref39[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref38, _ref39, _ref40, _ref41, _ref42, _results;
zIndex = 1000;
_ref38 = this.model.stock;
for (_i = 0, _len = _ref38.length; _i < _len; _i++) {
card = _ref38[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref39 = this.model.waste;
for (index = _j = 0, _len1 = _ref39.length; _j < _len1; index = ++_j) {
card = _ref39[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref40 = this.model.foundations;
for (index = _k = 0, _len2 = _ref40.length; _k < _len2; index = ++_k) {
foundation = _ref40[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref41 = this.model.faceDownTableauPiles.length; 0 <= _ref41 ? _m < _ref41 : _m > _ref41; i = 0 <= _ref41 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref42 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref42.length; _n < _len4; _n++) {
card = _ref42[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref43, _results1;
_ref43 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref43.length; _o < _len5; _o++) {
card = _ref43[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref38;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref38 = this.model.waste.length) && _ref38 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref38, _ref39, _ref40, _ref41, _ref42, _ref43, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref38 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref38.length; _i < _len; _i++) {
controller = _ref38[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref39, _results;
_ref39 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref39.length; _j < _len1; _j++) {
c = _ref39[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref39 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref39.length; _j < _len1; _j++) {
controller = _ref39[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref40 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref40.length; _k < _len2; _k++) {
controller = _ref40[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref41 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref41.length; _l < _len3; _l++) {
controller = _ref41[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref42 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref42.length; _m < _len4; _m++) {
controller = _ref42[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref43 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref43.length; _n < _len5; _n++) {
controller = _ref43[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref38,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref38 = [['waste']].concat(__slice.call((function() {
var _j, _ref38, _results;
_results = [];
for (i = _j = 0, _ref38 = this.model.faceUpTableauPiles.length; 0 <= _ref38 ? _j < _ref38 : _j > _ref38; i = 0 <= _ref38 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref38.length; _i < _len; _i++) {
locator = _ref38[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref38, _ref39, _ref40, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref38 = _this.dragState.cards) != null ? _ref38 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref39, _results;
_ref39 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref39.length; _i < _len; _i++) {
c = _ref39[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref39, _results;
_ref39 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref39.length; _i < _len; _i++) {
el = _ref39[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref39 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref39.length; _i < _len; _i++) {
el = _ref39[_i];
_results.push($(el).css({
zIndex: parseInt((_ref40 = $(el).css('zIndex')) != null ? _ref40 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref38, _results;
_ref38 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref38.length; _i < _len; i = ++_i) {
el = _ref38[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref38, _ref39, _ref40, _results, _results1;
if (!_this.dragState.cards) {
_ref38 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref38.length; _i < _len; i = ++_i) {
el = _ref38[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref39, _results1;
_ref39 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref39.length; _j < _len1; _j++) {
e = _ref39[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref39 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref39.length; _j < _len1; _j++) {
dropZone = _ref39[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref40 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref40.length; _k < _len2; _k++) {
controller = _ref40[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref38, _ref39;
dropZones = [];
_ref38 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref38.length; _i < _len; i = ++_i) {
locator = _ref38[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref39 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref39.length; _j < _len1; i = ++_j) {
locator = _ref39[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref38, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref38 = this.model.foundations.length; 0 <= _ref38 ? _i < _ref38 : _i > _ref38; foundationIndex = 0 <= _ref38 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref38 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref38;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref39 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref39;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref40, _ref41;
_ref40 = [this.size.width, this.size.height], width = _ref40[0], height = _ref40[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref41 = [2 * width, 4 * height], left = _ref41[0], top = _ref41[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref40, _results;
_results = [];
for (i = _i = 0, _ref40 = this.model.numberOfFoundations; 0 <= _ref40 ? _i < _ref40 : _i > _ref40; i = 0 <= _ref40 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref40, _results;
_results = [];
for (i = _i = 0, _ref40 = this.model.numberOfTableauPiles; 0 <= _ref40 ? _i < _ref40 : _i > _ref40; i = 0 <= _ref40 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref40, _ref41,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref40 = this.model.numberOfFoundations; 0 <= _ref40 ? _i < _ref40 : _i > _ref40; i = 0 <= _ref40 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref41 = this.model.numberOfTableauPiles; 0 <= _ref41 ? _j < _ref41 : _j > _ref41; i = 0 <= _ref41 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref40, _ref41;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref40 = this.cardControllers;
for (id in _ref40) {
controller = _ref40[id];
controller.destroy();
}
this.cardControllers = {};
_ref41 = this.model.deck;
for (_i = 0, _len = _ref41.length; _i < _len; _i++) {
card = _ref41[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref40, _ref41, _ref42, _ref43, _ref44, _results;
zIndex = 1000;
_ref40 = this.model.stock;
for (_i = 0, _len = _ref40.length; _i < _len; _i++) {
card = _ref40[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref41 = this.model.waste;
for (index = _j = 0, _len1 = _ref41.length; _j < _len1; index = ++_j) {
card = _ref41[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref42 = this.model.foundations;
for (index = _k = 0, _len2 = _ref42.length; _k < _len2; index = ++_k) {
foundation = _ref42[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref43 = this.model.faceDownTableauPiles.length; 0 <= _ref43 ? _m < _ref43 : _m > _ref43; i = 0 <= _ref43 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref44 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref44.length; _n < _len4; _n++) {
card = _ref44[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref45, _results1;
_ref45 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref45.length; _o < _len5; _o++) {
card = _ref45[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref40;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref40 = this.model.waste.length) && _ref40 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref40, _ref41, _ref42, _ref43, _ref44, _ref45, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref40 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref40.length; _i < _len; _i++) {
controller = _ref40[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref41, _results;
_ref41 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref41.length; _j < _len1; _j++) {
c = _ref41[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref41 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref41.length; _j < _len1; _j++) {
controller = _ref41[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref42 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref42.length; _k < _len2; _k++) {
controller = _ref42[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref43 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref43.length; _l < _len3; _l++) {
controller = _ref43[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref44 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref44.length; _m < _len4; _m++) {
controller = _ref44[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref45 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref45.length; _n < _len5; _n++) {
controller = _ref45[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref40,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref40 = [['waste']].concat(__slice.call((function() {
var _j, _ref40, _results;
_results = [];
for (i = _j = 0, _ref40 = this.model.faceUpTableauPiles.length; 0 <= _ref40 ? _j < _ref40 : _j > _ref40; i = 0 <= _ref40 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref40.length; _i < _len; _i++) {
locator = _ref40[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref40, _ref41, _ref42, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref40 = _this.dragState.cards) != null ? _ref40 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref41, _results;
_ref41 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref41.length; _i < _len; _i++) {
c = _ref41[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref41, _results;
_ref41 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref41.length; _i < _len; _i++) {
el = _ref41[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref41 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref41.length; _i < _len; _i++) {
el = _ref41[_i];
_results.push($(el).css({
zIndex: parseInt((_ref42 = $(el).css('zIndex')) != null ? _ref42 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref40, _results;
_ref40 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref40.length; _i < _len; i = ++_i) {
el = _ref40[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref40, _ref41, _ref42, _results, _results1;
if (!_this.dragState.cards) {
_ref40 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref40.length; _i < _len; i = ++_i) {
el = _ref40[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref41, _results1;
_ref41 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref41.length; _j < _len1; _j++) {
e = _ref41[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref41 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref41.length; _j < _len1; _j++) {
dropZone = _ref41[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref42 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref42.length; _k < _len2; _k++) {
controller = _ref42[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref40, _ref41;
dropZones = [];
_ref40 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref40.length; _i < _len; i = ++_i) {
locator = _ref40[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref41 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref41.length; _j < _len1; i = ++_j) {
locator = _ref41[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref40, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref40 = this.model.foundations.length; 0 <= _ref40 ? _i < _ref40 : _i > _ref40; foundationIndex = 0 <= _ref40 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref40 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref40;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref41 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref41;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref42, _ref43;
_ref42 = [this.size.width, this.size.height], width = _ref42[0], height = _ref42[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref43 = [2 * width, 4 * height], left = _ref43[0], top = _ref43[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref42, _results;
_results = [];
for (i = _i = 0, _ref42 = this.model.numberOfFoundations; 0 <= _ref42 ? _i < _ref42 : _i > _ref42; i = 0 <= _ref42 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref42, _results;
_results = [];
for (i = _i = 0, _ref42 = this.model.numberOfTableauPiles; 0 <= _ref42 ? _i < _ref42 : _i > _ref42; i = 0 <= _ref42 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref42, _ref43,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref42 = this.model.numberOfFoundations; 0 <= _ref42 ? _i < _ref42 : _i > _ref42; i = 0 <= _ref42 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref43 = this.model.numberOfTableauPiles; 0 <= _ref43 ? _j < _ref43 : _j > _ref43; i = 0 <= _ref43 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref42, _ref43;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref42 = this.cardControllers;
for (id in _ref42) {
controller = _ref42[id];
controller.destroy();
}
this.cardControllers = {};
_ref43 = this.model.deck;
for (_i = 0, _len = _ref43.length; _i < _len; _i++) {
card = _ref43[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref42, _ref43, _ref44, _ref45, _ref46, _results;
zIndex = 1000;
_ref42 = this.model.stock;
for (_i = 0, _len = _ref42.length; _i < _len; _i++) {
card = _ref42[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref43 = this.model.waste;
for (index = _j = 0, _len1 = _ref43.length; _j < _len1; index = ++_j) {
card = _ref43[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref44 = this.model.foundations;
for (index = _k = 0, _len2 = _ref44.length; _k < _len2; index = ++_k) {
foundation = _ref44[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref45 = this.model.faceDownTableauPiles.length; 0 <= _ref45 ? _m < _ref45 : _m > _ref45; i = 0 <= _ref45 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref46 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref46.length; _n < _len4; _n++) {
card = _ref46[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref47, _results1;
_ref47 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref47.length; _o < _len5; _o++) {
card = _ref47[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref42;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref42 = this.model.waste.length) && _ref42 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref42, _ref43, _ref44, _ref45, _ref46, _ref47, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref42 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref42.length; _i < _len; _i++) {
controller = _ref42[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref43, _results;
_ref43 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref43.length; _j < _len1; _j++) {
c = _ref43[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref43 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref43.length; _j < _len1; _j++) {
controller = _ref43[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref44 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref44.length; _k < _len2; _k++) {
controller = _ref44[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref45 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref45.length; _l < _len3; _l++) {
controller = _ref45[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref46 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref46.length; _m < _len4; _m++) {
controller = _ref46[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref47 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref47.length; _n < _len5; _n++) {
controller = _ref47[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref42,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref42 = [['waste']].concat(__slice.call((function() {
var _j, _ref42, _results;
_results = [];
for (i = _j = 0, _ref42 = this.model.faceUpTableauPiles.length; 0 <= _ref42 ? _j < _ref42 : _j > _ref42; i = 0 <= _ref42 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref42.length; _i < _len; _i++) {
locator = _ref42[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref42, _ref43, _ref44, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref42 = _this.dragState.cards) != null ? _ref42 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref43, _results;
_ref43 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref43.length; _i < _len; _i++) {
c = _ref43[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref43, _results;
_ref43 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref43.length; _i < _len; _i++) {
el = _ref43[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref43 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref43.length; _i < _len; _i++) {
el = _ref43[_i];
_results.push($(el).css({
zIndex: parseInt((_ref44 = $(el).css('zIndex')) != null ? _ref44 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref42, _results;
_ref42 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref42.length; _i < _len; i = ++_i) {
el = _ref42[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref42, _ref43, _ref44, _results, _results1;
if (!_this.dragState.cards) {
_ref42 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref42.length; _i < _len; i = ++_i) {
el = _ref42[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref43, _results1;
_ref43 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref43.length; _j < _len1; _j++) {
e = _ref43[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref43 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref43.length; _j < _len1; _j++) {
dropZone = _ref43[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref44 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref44.length; _k < _len2; _k++) {
controller = _ref44[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref42, _ref43;
dropZones = [];
_ref42 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref42.length; _i < _len; i = ++_i) {
locator = _ref42[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref43 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref43.length; _j < _len1; i = ++_j) {
locator = _ref43[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref42, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref42 = this.model.foundations.length; 0 <= _ref42 ? _i < _ref42 : _i > _ref42; foundationIndex = 0 <= _ref42 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref42 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref42;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref43 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref43;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref44, _ref45;
_ref44 = [this.size.width, this.size.height], width = _ref44[0], height = _ref44[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref45 = [2 * width, 4 * height], left = _ref45[0], top = _ref45[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref44, _results;
_results = [];
for (i = _i = 0, _ref44 = this.model.numberOfFoundations; 0 <= _ref44 ? _i < _ref44 : _i > _ref44; i = 0 <= _ref44 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref44, _results;
_results = [];
for (i = _i = 0, _ref44 = this.model.numberOfTableauPiles; 0 <= _ref44 ? _i < _ref44 : _i > _ref44; i = 0 <= _ref44 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref44, _ref45,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref44 = this.model.numberOfFoundations; 0 <= _ref44 ? _i < _ref44 : _i > _ref44; i = 0 <= _ref44 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref45 = this.model.numberOfTableauPiles; 0 <= _ref45 ? _j < _ref45 : _j > _ref45; i = 0 <= _ref45 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref44, _ref45;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref44 = this.cardControllers;
for (id in _ref44) {
controller = _ref44[id];
controller.destroy();
}
this.cardControllers = {};
_ref45 = this.model.deck;
for (_i = 0, _len = _ref45.length; _i < _len; _i++) {
card = _ref45[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref44, _ref45, _ref46, _ref47, _ref48, _results;
zIndex = 1000;
_ref44 = this.model.stock;
for (_i = 0, _len = _ref44.length; _i < _len; _i++) {
card = _ref44[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref45 = this.model.waste;
for (index = _j = 0, _len1 = _ref45.length; _j < _len1; index = ++_j) {
card = _ref45[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref46 = this.model.foundations;
for (index = _k = 0, _len2 = _ref46.length; _k < _len2; index = ++_k) {
foundation = _ref46[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref47 = this.model.faceDownTableauPiles.length; 0 <= _ref47 ? _m < _ref47 : _m > _ref47; i = 0 <= _ref47 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref48 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref48.length; _n < _len4; _n++) {
card = _ref48[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref49, _results1;
_ref49 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref49.length; _o < _len5; _o++) {
card = _ref49[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref44;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref44 = this.model.waste.length) && _ref44 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref44, _ref45, _ref46, _ref47, _ref48, _ref49, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref44 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref44.length; _i < _len; _i++) {
controller = _ref44[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref45, _results;
_ref45 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref45.length; _j < _len1; _j++) {
c = _ref45[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref45 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref45.length; _j < _len1; _j++) {
controller = _ref45[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref46 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref46.length; _k < _len2; _k++) {
controller = _ref46[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref47 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref47.length; _l < _len3; _l++) {
controller = _ref47[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref48 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref48.length; _m < _len4; _m++) {
controller = _ref48[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref49 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref49.length; _n < _len5; _n++) {
controller = _ref49[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref44,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref44 = [['waste']].concat(__slice.call((function() {
var _j, _ref44, _results;
_results = [];
for (i = _j = 0, _ref44 = this.model.faceUpTableauPiles.length; 0 <= _ref44 ? _j < _ref44 : _j > _ref44; i = 0 <= _ref44 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref44.length; _i < _len; _i++) {
locator = _ref44[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref44, _ref45, _ref46, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref44 = _this.dragState.cards) != null ? _ref44 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref45, _results;
_ref45 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref45.length; _i < _len; _i++) {
c = _ref45[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref45, _results;
_ref45 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref45.length; _i < _len; _i++) {
el = _ref45[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref45 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref45.length; _i < _len; _i++) {
el = _ref45[_i];
_results.push($(el).css({
zIndex: parseInt((_ref46 = $(el).css('zIndex')) != null ? _ref46 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref44, _results;
_ref44 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref44.length; _i < _len; i = ++_i) {
el = _ref44[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref44, _ref45, _ref46, _results, _results1;
if (!_this.dragState.cards) {
_ref44 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref44.length; _i < _len; i = ++_i) {
el = _ref44[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref45, _results1;
_ref45 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref45.length; _j < _len1; _j++) {
e = _ref45[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref45 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref45.length; _j < _len1; _j++) {
dropZone = _ref45[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref46 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref46.length; _k < _len2; _k++) {
controller = _ref46[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref44, _ref45;
dropZones = [];
_ref44 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref44.length; _i < _len; i = ++_i) {
locator = _ref44[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref45 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref45.length; _j < _len1; i = ++_j) {
locator = _ref45[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref44, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref44 = this.model.foundations.length; 0 <= _ref44 ? _i < _ref44 : _i > _ref44; foundationIndex = 0 <= _ref44 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref44 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref44;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref45 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref45;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref46, _ref47;
_ref46 = [this.size.width, this.size.height], width = _ref46[0], height = _ref46[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref47 = [2 * width, 4 * height], left = _ref47[0], top = _ref47[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref46, _results;
_results = [];
for (i = _i = 0, _ref46 = this.model.numberOfFoundations; 0 <= _ref46 ? _i < _ref46 : _i > _ref46; i = 0 <= _ref46 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref46, _results;
_results = [];
for (i = _i = 0, _ref46 = this.model.numberOfTableauPiles; 0 <= _ref46 ? _i < _ref46 : _i > _ref46; i = 0 <= _ref46 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref46, _ref47,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref46 = this.model.numberOfFoundations; 0 <= _ref46 ? _i < _ref46 : _i > _ref46; i = 0 <= _ref46 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref47 = this.model.numberOfTableauPiles; 0 <= _ref47 ? _j < _ref47 : _j > _ref47; i = 0 <= _ref47 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref46, _ref47;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref46 = this.cardControllers;
for (id in _ref46) {
controller = _ref46[id];
controller.destroy();
}
this.cardControllers = {};
_ref47 = this.model.deck;
for (_i = 0, _len = _ref47.length; _i < _len; _i++) {
card = _ref47[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref46, _ref47, _ref48, _ref49, _ref50, _results;
zIndex = 1000;
_ref46 = this.model.stock;
for (_i = 0, _len = _ref46.length; _i < _len; _i++) {
card = _ref46[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref47 = this.model.waste;
for (index = _j = 0, _len1 = _ref47.length; _j < _len1; index = ++_j) {
card = _ref47[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref48 = this.model.foundations;
for (index = _k = 0, _len2 = _ref48.length; _k < _len2; index = ++_k) {
foundation = _ref48[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref49 = this.model.faceDownTableauPiles.length; 0 <= _ref49 ? _m < _ref49 : _m > _ref49; i = 0 <= _ref49 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref50 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref50.length; _n < _len4; _n++) {
card = _ref50[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref51, _results1;
_ref51 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref51.length; _o < _len5; _o++) {
card = _ref51[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref46;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref46 = this.model.waste.length) && _ref46 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref46, _ref47, _ref48, _ref49, _ref50, _ref51, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref46 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref46.length; _i < _len; _i++) {
controller = _ref46[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref47, _results;
_ref47 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref47.length; _j < _len1; _j++) {
c = _ref47[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref47 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref47.length; _j < _len1; _j++) {
controller = _ref47[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref48 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref48.length; _k < _len2; _k++) {
controller = _ref48[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref49 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref49.length; _l < _len3; _l++) {
controller = _ref49[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref50 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref50.length; _m < _len4; _m++) {
controller = _ref50[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref51 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref51.length; _n < _len5; _n++) {
controller = _ref51[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref46,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref46 = [['waste']].concat(__slice.call((function() {
var _j, _ref46, _results;
_results = [];
for (i = _j = 0, _ref46 = this.model.faceUpTableauPiles.length; 0 <= _ref46 ? _j < _ref46 : _j > _ref46; i = 0 <= _ref46 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref46.length; _i < _len; _i++) {
locator = _ref46[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref46, _ref47, _ref48, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref46 = _this.dragState.cards) != null ? _ref46 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref47, _results;
_ref47 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref47.length; _i < _len; _i++) {
c = _ref47[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref47, _results;
_ref47 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref47.length; _i < _len; _i++) {
el = _ref47[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref47 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref47.length; _i < _len; _i++) {
el = _ref47[_i];
_results.push($(el).css({
zIndex: parseInt((_ref48 = $(el).css('zIndex')) != null ? _ref48 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref46, _results;
_ref46 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref46.length; _i < _len; i = ++_i) {
el = _ref46[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref46, _ref47, _ref48, _results, _results1;
if (!_this.dragState.cards) {
_ref46 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref46.length; _i < _len; i = ++_i) {
el = _ref46[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref47, _results1;
_ref47 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref47.length; _j < _len1; _j++) {
e = _ref47[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref47 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref47.length; _j < _len1; _j++) {
dropZone = _ref47[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref48 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref48.length; _k < _len2; _k++) {
controller = _ref48[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref46, _ref47;
dropZones = [];
_ref46 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref46.length; _i < _len; i = ++_i) {
locator = _ref46[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref47 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref47.length; _j < _len1; i = ++_j) {
locator = _ref47[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref46, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref46 = this.model.foundations.length; 0 <= _ref46 ? _i < _ref46 : _i > _ref46; foundationIndex = 0 <= _ref46 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref46 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref46;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref47 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref47;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref48, _ref49;
_ref48 = [this.size.width, this.size.height], width = _ref48[0], height = _ref48[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref49 = [2 * width, 4 * height], left = _ref49[0], top = _ref49[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref48, _results;
_results = [];
for (i = _i = 0, _ref48 = this.model.numberOfFoundations; 0 <= _ref48 ? _i < _ref48 : _i > _ref48; i = 0 <= _ref48 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref48, _results;
_results = [];
for (i = _i = 0, _ref48 = this.model.numberOfTableauPiles; 0 <= _ref48 ? _i < _ref48 : _i > _ref48; i = 0 <= _ref48 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref48, _ref49,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref48 = this.model.numberOfFoundations; 0 <= _ref48 ? _i < _ref48 : _i > _ref48; i = 0 <= _ref48 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref49 = this.model.numberOfTableauPiles; 0 <= _ref49 ? _j < _ref49 : _j > _ref49; i = 0 <= _ref49 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref48, _ref49;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref48 = this.cardControllers;
for (id in _ref48) {
controller = _ref48[id];
controller.destroy();
}
this.cardControllers = {};
_ref49 = this.model.deck;
for (_i = 0, _len = _ref49.length; _i < _len; _i++) {
card = _ref49[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref48, _ref49, _ref50, _ref51, _ref52, _results;
zIndex = 1000;
_ref48 = this.model.stock;
for (_i = 0, _len = _ref48.length; _i < _len; _i++) {
card = _ref48[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref49 = this.model.waste;
for (index = _j = 0, _len1 = _ref49.length; _j < _len1; index = ++_j) {
card = _ref49[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref50 = this.model.foundations;
for (index = _k = 0, _len2 = _ref50.length; _k < _len2; index = ++_k) {
foundation = _ref50[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref51 = this.model.faceDownTableauPiles.length; 0 <= _ref51 ? _m < _ref51 : _m > _ref51; i = 0 <= _ref51 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref52 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref52.length; _n < _len4; _n++) {
card = _ref52[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref53, _results1;
_ref53 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref53.length; _o < _len5; _o++) {
card = _ref53[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref48;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref48 = this.model.waste.length) && _ref48 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref48, _ref49, _ref50, _ref51, _ref52, _ref53, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref48 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref48.length; _i < _len; _i++) {
controller = _ref48[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref49, _results;
_ref49 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref49.length; _j < _len1; _j++) {
c = _ref49[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref49 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref49.length; _j < _len1; _j++) {
controller = _ref49[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref50 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref50.length; _k < _len2; _k++) {
controller = _ref50[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref51 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref51.length; _l < _len3; _l++) {
controller = _ref51[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref52 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref52.length; _m < _len4; _m++) {
controller = _ref52[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref53 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref53.length; _n < _len5; _n++) {
controller = _ref53[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref48,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref48 = [['waste']].concat(__slice.call((function() {
var _j, _ref48, _results;
_results = [];
for (i = _j = 0, _ref48 = this.model.faceUpTableauPiles.length; 0 <= _ref48 ? _j < _ref48 : _j > _ref48; i = 0 <= _ref48 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref48.length; _i < _len; _i++) {
locator = _ref48[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref48, _ref49, _ref50, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref48 = _this.dragState.cards) != null ? _ref48 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref49, _results;
_ref49 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref49.length; _i < _len; _i++) {
c = _ref49[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref49, _results;
_ref49 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref49.length; _i < _len; _i++) {
el = _ref49[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref49 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref49.length; _i < _len; _i++) {
el = _ref49[_i];
_results.push($(el).css({
zIndex: parseInt((_ref50 = $(el).css('zIndex')) != null ? _ref50 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref48, _results;
_ref48 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref48.length; _i < _len; i = ++_i) {
el = _ref48[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref48, _ref49, _ref50, _results, _results1;
if (!_this.dragState.cards) {
_ref48 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref48.length; _i < _len; i = ++_i) {
el = _ref48[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref49, _results1;
_ref49 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref49.length; _j < _len1; _j++) {
e = _ref49[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref49 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref49.length; _j < _len1; _j++) {
dropZone = _ref49[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref50 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref50.length; _k < _len2; _k++) {
controller = _ref50[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref48, _ref49;
dropZones = [];
_ref48 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref48.length; _i < _len; i = ++_i) {
locator = _ref48[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref49 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref49.length; _j < _len1; i = ++_j) {
locator = _ref49[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref48, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref48 = this.model.foundations.length; 0 <= _ref48 ? _i < _ref48 : _i > _ref48; foundationIndex = 0 <= _ref48 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref48 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref48;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref49 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref49;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref50, _ref51;
_ref50 = [this.size.width, this.size.height], width = _ref50[0], height = _ref50[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref51 = [2 * width, 4 * height], left = _ref51[0], top = _ref51[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref50, _results;
_results = [];
for (i = _i = 0, _ref50 = this.model.numberOfFoundations; 0 <= _ref50 ? _i < _ref50 : _i > _ref50; i = 0 <= _ref50 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref50, _results;
_results = [];
for (i = _i = 0, _ref50 = this.model.numberOfTableauPiles; 0 <= _ref50 ? _i < _ref50 : _i > _ref50; i = 0 <= _ref50 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref50, _ref51,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref50 = this.model.numberOfFoundations; 0 <= _ref50 ? _i < _ref50 : _i > _ref50; i = 0 <= _ref50 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref51 = this.model.numberOfTableauPiles; 0 <= _ref51 ? _j < _ref51 : _j > _ref51; i = 0 <= _ref51 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref50, _ref51;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref50 = this.cardControllers;
for (id in _ref50) {
controller = _ref50[id];
controller.destroy();
}
this.cardControllers = {};
_ref51 = this.model.deck;
for (_i = 0, _len = _ref51.length; _i < _len; _i++) {
card = _ref51[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref50, _ref51, _ref52, _ref53, _ref54, _results;
zIndex = 1000;
_ref50 = this.model.stock;
for (_i = 0, _len = _ref50.length; _i < _len; _i++) {
card = _ref50[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref51 = this.model.waste;
for (index = _j = 0, _len1 = _ref51.length; _j < _len1; index = ++_j) {
card = _ref51[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref52 = this.model.foundations;
for (index = _k = 0, _len2 = _ref52.length; _k < _len2; index = ++_k) {
foundation = _ref52[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref53 = this.model.faceDownTableauPiles.length; 0 <= _ref53 ? _m < _ref53 : _m > _ref53; i = 0 <= _ref53 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref54 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref54.length; _n < _len4; _n++) {
card = _ref54[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref55, _results1;
_ref55 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref55.length; _o < _len5; _o++) {
card = _ref55[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref50;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref50 = this.model.waste.length) && _ref50 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref50, _ref51, _ref52, _ref53, _ref54, _ref55, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref50 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref50.length; _i < _len; _i++) {
controller = _ref50[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref51, _results;
_ref51 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref51.length; _j < _len1; _j++) {
c = _ref51[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref51 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref51.length; _j < _len1; _j++) {
controller = _ref51[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref52 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref52.length; _k < _len2; _k++) {
controller = _ref52[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref53 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref53.length; _l < _len3; _l++) {
controller = _ref53[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref54 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref54.length; _m < _len4; _m++) {
controller = _ref54[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref55 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref55.length; _n < _len5; _n++) {
controller = _ref55[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref50,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref50 = [['waste']].concat(__slice.call((function() {
var _j, _ref50, _results;
_results = [];
for (i = _j = 0, _ref50 = this.model.faceUpTableauPiles.length; 0 <= _ref50 ? _j < _ref50 : _j > _ref50; i = 0 <= _ref50 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref50.length; _i < _len; _i++) {
locator = _ref50[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref50, _ref51, _ref52, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref50 = _this.dragState.cards) != null ? _ref50 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref51, _results;
_ref51 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref51.length; _i < _len; _i++) {
c = _ref51[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref51, _results;
_ref51 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref51.length; _i < _len; _i++) {
el = _ref51[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref51 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref51.length; _i < _len; _i++) {
el = _ref51[_i];
_results.push($(el).css({
zIndex: parseInt((_ref52 = $(el).css('zIndex')) != null ? _ref52 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref50, _results;
_ref50 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref50.length; _i < _len; i = ++_i) {
el = _ref50[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref50, _ref51, _ref52, _results, _results1;
if (!_this.dragState.cards) {
_ref50 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref50.length; _i < _len; i = ++_i) {
el = _ref50[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref51, _results1;
_ref51 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref51.length; _j < _len1; _j++) {
e = _ref51[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref51 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref51.length; _j < _len1; _j++) {
dropZone = _ref51[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref52 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref52.length; _k < _len2; _k++) {
controller = _ref52[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref50, _ref51;
dropZones = [];
_ref50 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref50.length; _i < _len; i = ++_i) {
locator = _ref50[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref51 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref51.length; _j < _len1; i = ++_j) {
locator = _ref51[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref50, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref50 = this.model.foundations.length; 0 <= _ref50 ? _i < _ref50 : _i > _ref50; foundationIndex = 0 <= _ref50 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref50 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref50;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref51 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref51;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref52, _ref53;
_ref52 = [this.size.width, this.size.height], width = _ref52[0], height = _ref52[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref53 = [2 * width, 4 * height], left = _ref53[0], top = _ref53[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref52, _results;
_results = [];
for (i = _i = 0, _ref52 = this.model.numberOfFoundations; 0 <= _ref52 ? _i < _ref52 : _i > _ref52; i = 0 <= _ref52 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref52, _results;
_results = [];
for (i = _i = 0, _ref52 = this.model.numberOfTableauPiles; 0 <= _ref52 ? _i < _ref52 : _i > _ref52; i = 0 <= _ref52 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref52, _ref53,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref52 = this.model.numberOfFoundations; 0 <= _ref52 ? _i < _ref52 : _i > _ref52; i = 0 <= _ref52 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref53 = this.model.numberOfTableauPiles; 0 <= _ref53 ? _j < _ref53 : _j > _ref53; i = 0 <= _ref53 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref52, _ref53;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref52 = this.cardControllers;
for (id in _ref52) {
controller = _ref52[id];
controller.destroy();
}
this.cardControllers = {};
_ref53 = this.model.deck;
for (_i = 0, _len = _ref53.length; _i < _len; _i++) {
card = _ref53[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref52, _ref53, _ref54, _ref55, _ref56, _results;
zIndex = 1000;
_ref52 = this.model.stock;
for (_i = 0, _len = _ref52.length; _i < _len; _i++) {
card = _ref52[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref53 = this.model.waste;
for (index = _j = 0, _len1 = _ref53.length; _j < _len1; index = ++_j) {
card = _ref53[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref54 = this.model.foundations;
for (index = _k = 0, _len2 = _ref54.length; _k < _len2; index = ++_k) {
foundation = _ref54[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref55 = this.model.faceDownTableauPiles.length; 0 <= _ref55 ? _m < _ref55 : _m > _ref55; i = 0 <= _ref55 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref56 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref56.length; _n < _len4; _n++) {
card = _ref56[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref57, _results1;
_ref57 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref57.length; _o < _len5; _o++) {
card = _ref57[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref52;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref52 = this.model.waste.length) && _ref52 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref52, _ref53, _ref54, _ref55, _ref56, _ref57, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref52 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref52.length; _i < _len; _i++) {
controller = _ref52[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref53, _results;
_ref53 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref53.length; _j < _len1; _j++) {
c = _ref53[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref53 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref53.length; _j < _len1; _j++) {
controller = _ref53[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref54 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref54.length; _k < _len2; _k++) {
controller = _ref54[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref55 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref55.length; _l < _len3; _l++) {
controller = _ref55[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref56 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref56.length; _m < _len4; _m++) {
controller = _ref56[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref57 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref57.length; _n < _len5; _n++) {
controller = _ref57[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref52,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref52 = [['waste']].concat(__slice.call((function() {
var _j, _ref52, _results;
_results = [];
for (i = _j = 0, _ref52 = this.model.faceUpTableauPiles.length; 0 <= _ref52 ? _j < _ref52 : _j > _ref52; i = 0 <= _ref52 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref52.length; _i < _len; _i++) {
locator = _ref52[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref52, _ref53, _ref54, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref52 = _this.dragState.cards) != null ? _ref52 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref53, _results;
_ref53 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref53.length; _i < _len; _i++) {
c = _ref53[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref53, _results;
_ref53 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref53.length; _i < _len; _i++) {
el = _ref53[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref53 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref53.length; _i < _len; _i++) {
el = _ref53[_i];
_results.push($(el).css({
zIndex: parseInt((_ref54 = $(el).css('zIndex')) != null ? _ref54 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref52, _results;
_ref52 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref52.length; _i < _len; i = ++_i) {
el = _ref52[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref52, _ref53, _ref54, _results, _results1;
if (!_this.dragState.cards) {
_ref52 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref52.length; _i < _len; i = ++_i) {
el = _ref52[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref53, _results1;
_ref53 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref53.length; _j < _len1; _j++) {
e = _ref53[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref53 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref53.length; _j < _len1; _j++) {
dropZone = _ref53[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref54 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref54.length; _k < _len2; _k++) {
controller = _ref54[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref52, _ref53;
dropZones = [];
_ref52 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref52.length; _i < _len; i = ++_i) {
locator = _ref52[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref53 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref53.length; _j < _len1; i = ++_j) {
locator = _ref53[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref52, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref52 = this.model.foundations.length; 0 <= _ref52 ? _i < _ref52 : _i > _ref52; foundationIndex = 0 <= _ref52 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref52 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref52;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref53 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref53;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref54, _ref55;
_ref54 = [this.size.width, this.size.height], width = _ref54[0], height = _ref54[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref55 = [2 * width, 4 * height], left = _ref55[0], top = _ref55[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref54, _results;
_results = [];
for (i = _i = 0, _ref54 = this.model.numberOfFoundations; 0 <= _ref54 ? _i < _ref54 : _i > _ref54; i = 0 <= _ref54 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref54, _results;
_results = [];
for (i = _i = 0, _ref54 = this.model.numberOfTableauPiles; 0 <= _ref54 ? _i < _ref54 : _i > _ref54; i = 0 <= _ref54 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref54, _ref55,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref54 = this.model.numberOfFoundations; 0 <= _ref54 ? _i < _ref54 : _i > _ref54; i = 0 <= _ref54 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref55 = this.model.numberOfTableauPiles; 0 <= _ref55 ? _j < _ref55 : _j > _ref55; i = 0 <= _ref55 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref54, _ref55;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref54 = this.cardControllers;
for (id in _ref54) {
controller = _ref54[id];
controller.destroy();
}
this.cardControllers = {};
_ref55 = this.model.deck;
for (_i = 0, _len = _ref55.length; _i < _len; _i++) {
card = _ref55[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref54, _ref55, _ref56, _ref57, _ref58, _results;
zIndex = 1000;
_ref54 = this.model.stock;
for (_i = 0, _len = _ref54.length; _i < _len; _i++) {
card = _ref54[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref55 = this.model.waste;
for (index = _j = 0, _len1 = _ref55.length; _j < _len1; index = ++_j) {
card = _ref55[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref56 = this.model.foundations;
for (index = _k = 0, _len2 = _ref56.length; _k < _len2; index = ++_k) {
foundation = _ref56[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref57 = this.model.faceDownTableauPiles.length; 0 <= _ref57 ? _m < _ref57 : _m > _ref57; i = 0 <= _ref57 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref58 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref58.length; _n < _len4; _n++) {
card = _ref58[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref59, _results1;
_ref59 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref59.length; _o < _len5; _o++) {
card = _ref59[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref54;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref54 = this.model.waste.length) && _ref54 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref54, _ref55, _ref56, _ref57, _ref58, _ref59, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref54 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref54.length; _i < _len; _i++) {
controller = _ref54[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref55, _results;
_ref55 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref55.length; _j < _len1; _j++) {
c = _ref55[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref55 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref55.length; _j < _len1; _j++) {
controller = _ref55[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref56 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref56.length; _k < _len2; _k++) {
controller = _ref56[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref57 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref57.length; _l < _len3; _l++) {
controller = _ref57[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref58 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref58.length; _m < _len4; _m++) {
controller = _ref58[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref59 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref59.length; _n < _len5; _n++) {
controller = _ref59[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref54,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref54 = [['waste']].concat(__slice.call((function() {
var _j, _ref54, _results;
_results = [];
for (i = _j = 0, _ref54 = this.model.faceUpTableauPiles.length; 0 <= _ref54 ? _j < _ref54 : _j > _ref54; i = 0 <= _ref54 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref54.length; _i < _len; _i++) {
locator = _ref54[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref54, _ref55, _ref56, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref54 = _this.dragState.cards) != null ? _ref54 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref55, _results;
_ref55 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref55.length; _i < _len; _i++) {
c = _ref55[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
}).appendTo(_this.rootElement);
_this.dragState.elements = clone;
}
_this.dragState.originalElementPositions = (function() {
var _i, _len, _ref55, _results;
_ref55 = this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref55.length; _i < _len; _i++) {
el = _ref55[_i];
_results.push($(el).position());
}
return _results;
}).call(_this);
_ref55 = _this.dragState.elements;
_results = [];
for (_i = 0, _len = _ref55.length; _i < _len; _i++) {
el = _ref55[_i];
_results.push($(el).css({
zIndex: parseInt((_ref56 = $(el).css('zIndex')) != null ? _ref56 : '0') + 2000
}));
}
return _results;
},
mouseDrag: function(e) {
var el, i, _i, _len, _ref54, _results;
_ref54 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref54.length; _i < _len; i = ++_i) {
el = _ref54[i];
_results.push($(el).css({
left: _this.dragState.originalElementPositions[i].left + (e.pageX - _this.dragState.startPagePosition.left),
top: _this.dragState.originalElementPositions[i].top + (e.pageY - _this.dragState.startPagePosition.top)
}));
}
return _results;
},
mouseStop: function(e) {
var controller, dropZone, el, extent, i, mapEl, maxOverlapArea, overlap, targetDropZone, _i, _j, _k, _len, _len1, _len2, _ref54, _ref55, _ref56, _results, _results1;
if (!_this.dragState.cards) {
_ref54 = _this.dragState.elements;
_results = [];
for (i = _i = 0, _len = _ref54.length; _i < _len; i = ++_i) {
el = _ref54[i];
_results.push($(el).animate({
left: _this.dragState.originalElementPositions[i].left,
top: _this.dragState.originalElementPositions[i].top
}, _({}).extend(_this.speeds.snapBack, {
complete: function() {
return $(this).remove();
}
})));
}
return _results;
} else {
mapEl = function(c) {
var _j, _len1, _ref55, _results1;
_ref55 = _this.dragState.elements;
_results1 = [];
for (_j = 0, _len1 = _ref55.length; _j < _len1; _j++) {
e = _ref55[_j];
_results1.push(c($(e)));
}
return _results1;
};
extent = {
minLeft: Math.min.apply(Math, mapEl(function(e) {
return e.offset().left;
})),
minTop: Math.min.apply(Math, mapEl(function(e) {
return e.offset().top;
})),
maxLeft: Math.max.apply(Math, mapEl(function(e) {
return e.offset().left + e.width();
})),
maxTop: Math.max.apply(Math, mapEl(function(e) {
return e.offset().top + e.height();
}))
};
maxOverlapArea = 0;
targetDropZone = null;
_ref55 = _this._getDropZones(_this.dragState.cards);
for (_j = 0, _len1 = _ref55.length; _j < _len1; _j++) {
dropZone = _ref55[_j];
overlap = {};
overlap.left = Math.max(dropZone.left, extent.minLeft);
overlap.width = Math.max(Math.min(dropZone.left + dropZone.width, extent.maxLeft) - overlap.left, 0);
overlap.top = Math.max(dropZone.top, extent.minTop);
overlap.height = Math.max(Math.min(dropZone.top + dropZone.height, extent.maxTop) - overlap.top, 0);
overlap.area = overlap.width * overlap.height;
if (overlap.area > maxOverlapArea) {
maxOverlapArea = overlap.area;
targetDropZone = dropZone;
}
}
if (targetDropZone) {
return _this.move(_this.dragState.cards, targetDropZone.locator);
} else {
_ref56 = _this.dragState.controllers;
_results1 = [];
for (_k = 0, _len2 = _ref56.length; _k < _len2; _k++) {
controller = _ref56[_k];
_results1.push(controller.animateToRestingPosition(_this.speeds.snapBack));
}
return _results1;
}
}
}
});
};
Klondike.prototype._getDropZones = function(cards) {
var dropZones, i, locator, tableauPileLength, _i, _j, _len, _len1, _ref54, _ref55;
dropZones = [];
_ref54 = this.model.locators.foundations;
for (i = _i = 0, _len = _ref54.length; _i < _len; i = ++_i) {
locator = _ref54[i];
if (this.model.foundationAccepts(i, cards)) {
dropZones.push(_({
locator: locator
}).extend(this.positions.foundations[i], this.sizes.card));
}
}
_ref55 = this.model.locators.faceUpTableauPiles;
for (i = _j = 0, _len1 = _ref55.length; _j < _len1; i = ++_j) {
locator = _ref55[i];
if (this.model.tableauPileAccepts(i, cards)) {
tableauPileLength = this.model.faceDownTableauPiles[i].length + this.model.faceUpTableauPiles[i].length;
if (tableauPileLength) {
tableauPileLength--;
}
dropZones.push({
locator: locator,
top: this.positions.tableauPiles[i].top + tableauPileLength * this.positions.tableauFanningOffset,
left: this.positions.tableauPiles[i].left,
width: this.sizes.card.width,
height: this.sizes.card.height
});
}
}
return dropZones;
};
Klondike.prototype._drawVisualization = function(rect) {
return $('<div class="visualization"></div>').css(rect).appendTo(this.rootElement);
};
Klondike.prototype.turnStock = function() {
return this.processUserCommand(new App.Models.Command({
action: 'turnStock'
}));
};
Klondike.prototype.redeal = function() {
return this.processUserCommand(new App.Models.Command({
action: 'redeal'
}));
};
Klondike.prototype.playToAnyFoundation = function(src) {
var card, collection, foundationIndex, _i, _ref54, _results;
collection = this.model.getCollection(src);
card = _(collection).last();
_assert(card);
_results = [];
for (foundationIndex = _i = 0, _ref54 = this.model.foundations.length; 0 <= _ref54 ? _i < _ref54 : _i > _ref54; foundationIndex = 0 <= _ref54 ? ++_i : --_i) {
if (this.model.foundationAccepts(foundationIndex, [card])) {
this.processUserCommand(new App.Models.Command({
action: 'move',
src: src,
dest: ['foundations', foundationIndex],
numberOfCards: 1
}));
break;
} else {
_results.push(void 0);
}
}
return _results;
};
Klondike.prototype.move = function(cards, dest) {
this.model._assertLocator(dest);
_assert(cards instanceof Array);
if (dest[0] !== 'faceUpTableauPiles') {
_assert(cards.length === 1, dest, cards);
}
return this.processUserCommand(new App.Models.Command({
action: 'move',
src: this.model.getLocator(cards[0]),
dest: dest,
numberOfCards: cards.length,
guiAction: 'drag'
}));
};
Klondike.prototype.youWin = function() {
var _this = this;
$('.youWin').show();
$('.overlayContainer').fadeIn();
return $('.youWin').off().on('click', '.playAgainButton', function() {
$('.overlayContainer').hide();
return _this.newGame();
});
};
Klondike.prototype.dump = function() {
return "App.gameController.load('" + (JSON.stringify(this.model.dumpHash())) + "');";
};
Klondike.prototype.load = function(s) {
this.model.loadHash(JSON.parse(s));
this.renderAfterCommand(null);
return this.registerEventHandlers();
};
return Klondike;
})();
App.Controllers.KlondikeTurnOne = (function(_super) {
__extends(KlondikeTurnOne, _super);
function KlondikeTurnOne() {
_ref54 = KlondikeTurnOne.__super__.constructor.apply(this, arguments);
return _ref54;
}
KlondikeTurnOne.prototype.createModel = function() {
return new App.Models.KlondikeTurnOne;
};
return KlondikeTurnOne;
})(App.Controllers.Klondike);
App.Controllers.KlondikeTurnThree = (function(_super) {
__extends(KlondikeTurnThree, _super);
function KlondikeTurnThree() {
_ref55 = KlondikeTurnThree.__super__.constructor.apply(this, arguments);
return _ref55;
}
KlondikeTurnThree.prototype.createModel = function() {
return new App.Models.KlondikeTurnThree;
};
return KlondikeTurnThree;
})(App.Controllers.Klondike);
$.widget('ui.rawdraggable', $.ui.mouse, {
widgetEventPrefix: 'rawdraggable',
options: {
mouseStart: function(e) {},
mouseDrag: function(e) {},
mouseStop: function(e) {},
mouseCapture: function(e) {
return true;
}
},
_init: function() {
return this._mouseInit();
},
_create: function() {
return this.element.addClass('ui-rawdraggable');
},
_destroy: function() {
this._mouseDestroy();
return this.element.removeClass('ui-rawdraggable');
},
_mouseStart: function(e) {
return this.options.mouseStart(e);
},
_mouseDrag: function(e) {
return this.options.mouseDrag(e);
},
_mouseStop: function(e) {
return this.options.mouseStop(e);
},
_mouseCapture: function(e) {
return this.options.mouseCapture(e);
}
});
if (window.App == null) {
window.App = {};
}
if (App.Controllers == null) {
App.Controllers = {};
}
App.rootElement = '#solitaireCanvas';
App.Controllers.Card = (function() {
Card.prototype.size = {
width: 79,
height: 123
};
Card.prototype.element = null;
function Card(model) {
this.model = model;
}
Card.prototype.appendTo = function(rootElement) {
this.element = document.createElement('div');
this.element.className = 'card';
this.element.id = this.model.id;
$(this.element).css(this.size);
return $(rootElement).append(this.element);
};
Card.prototype.destroy = function() {
return $(this.element).remove();
};
Card.prototype.setRestingState = function(pos, zIndex, faceUp) {
return this.restingState = {
position: _.clone(pos),
zIndex: zIndex,
faceUp: faceUp
};
};
Card.prototype.jumpToRestingPosition = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
}).css(currentState.position);
return next();
});
};
Card.prototype.animateToRestingPosition = function(options, liftoff) {
var currentState,
_this = this;
if (liftoff == null) {
liftoff = true;
}
currentState = _(this.restingState).clone();
$(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex + (liftoff ? 1000 : 0)
});
return next();
});
$(this.element).animate(currentState.position, options);
return $(this.element).queue(function(next) {
$(_this.element).css({
zIndex: currentState.zIndex
});
return next();
});
};
Card.prototype.jumpToRestingFace = function() {
var currentState,
_this = this;
currentState = _(this.restingState).clone();
return $(this.element).queue(function(next) {
$(_this.element).css({
backgroundPosition: _this._getBackgroundPosition(currentState.faceUp)
});
return next();
});
};
Card.prototype.animateToRestingFace = function(options) {
$(this.element).animate({
scale: 1.08
}, {
duration: options.duration / 9,
easing: 'linear'
});
$(this.element).animate({
scaleX: 0
}, {
duration: options.duration * 3 / 9,
easing: 'linear'
});
this.jumpToRestingFace();
$(this.element).animate({
scaleX: 1
}, {
duration: options.duration * 4 / 9,
easing: 'linear'
});
return $(this.element).animate({
scale: 1
}, {
duration: options.duration / 9,
easing: 'linear'
});
};
Card.prototype._getBackgroundPosition = function(faceUp) {
var height, left, top, width, _ref56, _ref57;
_ref56 = [this.size.width, this.size.height], width = _ref56[0], height = _ref56[1];
if (faceUp) {
left = this.model.rank.value * width;
top = 'CDHS'.indexOf(this.model.suit.letter()) * height;
} else {
_ref57 = [2 * width, 4 * height], left = _ref57[0], top = _ref57[1];
}
return "-" + left + "px -" + top + "px";
};
return Card;
})();
App.Controllers.Klondike = (function() {
Klondike.prototype.createModel = function() {};
Klondike.prototype.model = null;
function Klondike() {
this.load = __bind(this.load, this);
this.dump = __bind(this.dump, this);
this.youWin = __bind(this.youWin, this);
this.move = __bind(this.move, this);
this.playToAnyFoundation = __bind(this.playToAnyFoundation, this);
this.redeal = __bind(this.redeal, this);
this.turnStock = __bind(this.turnStock, this);
this.undo = __bind(this.undo, this);
this.cardControllers = {};
this.rootElement = $(App.rootElement)[0];
this.newGame();
}
Klondike.setupGame = function() {
var _this = this;
return $(function() {
return App.gameController = new _this;
});
};
Klondike.prototype.speeds = {
snap: {
duration: 50,
easing: 'linear'
},
snapBack: {
duration: 300,
easing: 'easeOutCubic'
},
playToFoundation: {
duration: 450,
easing: 'swing'
},
undoMove: {
duration: 300,
easing: 'swing'
},
turn: {
duration: 200,
easing: 'swing'
},
shift: {
duration: 200,
easing: 'linear'
},
flip: {
duration: 200
}
};
Klondike.prototype.calculateGeometry = function() {
var columnOffset, firstColumn, firstRow, i, secondRow;
this.sizes = {
card: App.Controllers.Card.prototype.size,
button: {
width: App.Controllers.Card.prototype.size.width,
height: App.Controllers.Card.prototype.size.height / 3
}
};
firstColumn = 20;
columnOffset = this.sizes.card.width + 20;
firstRow = 20;
secondRow = 180;
return this.positions = {
undealtCards: {
left: 0,
top: 0
},
stock: {
left: firstColumn,
top: firstRow
},
waste: {
left: firstColumn + columnOffset,
top: firstRow
},
wasteFanningOffset: 20,
foundations: (function() {
var _i, _ref56, _results;
_results = [];
for (i = _i = 0, _ref56 = this.model.numberOfFoundations; 0 <= _ref56 ? _i < _ref56 : _i > _ref56; i = 0 <= _ref56 ? ++_i : --_i) {
_results.push({
left: firstColumn + (3 + i) * columnOffset,
top: firstRow
});
}
return _results;
}).call(this),
tableauPiles: (function() {
var _i, _ref56, _results;
_results = [];
for (i = _i = 0, _ref56 = this.model.numberOfTableauPiles; 0 <= _ref56 ? _i < _ref56 : _i > _ref56; i = 0 <= _ref56 ? ++_i : --_i) {
_results.push({
left: firstColumn + i * columnOffset,
top: secondRow
});
}
return _results;
}).call(this),
tableauFanningOffset: 20,
undoButton: {
left: firstColumn + columnOffset * this.model.numberOfTableauPiles,
top: firstRow
}
};
};
Klondike.prototype.appendBaseElements = function() {
var baseContainer, dummy, i, makeBaseCardElement, overlayContainer, _i, _j, _ref56, _ref57,
_this = this;
baseContainer = document.createElement('div');
baseContainer.className = 'baseContainer';
makeBaseCardElement = function(className, id, position, spriteOffset) {
var e;
if (spriteOffset == null) {
spriteOffset = 3;
}
e = document.createElement('div');
e.className = "" + className + " baseCardElement";
if (id) {
e.id = id;
}
e.style.cssText = ("left: " + position.left + "px; top: " + position.top + "px;") + ("width: " + _this.sizes.card.width + "px; height: " + _this.sizes.card.height + "px;") + ("background-position: -" + (spriteOffset * _this.sizes.card.width) + "px -" + (4 * _this.sizes.card.height) + "px;");
return $(baseContainer).append(e);
};
makeBaseCardElement('redealImage', 'redealImage', this.positions.stock, 4);
makeBaseCardElement('exhaustedImage', 'exhaustedImage', this.positions.stock, 5);
for (i = _i = 0, _ref56 = this.model.numberOfFoundations; 0 <= _ref56 ? _i < _ref56 : _i > _ref56; i = 0 <= _ref56 ? ++_i : --_i) {
makeBaseCardElement('foundationBase', "foundationBase" + i, this.positions.foundations[i]);
}
for (i = _j = 0, _ref57 = this.model.numberOfTableauPiles; 0 <= _ref57 ? _j < _ref57 : _j > _ref57; i = 0 <= _ref57 ? ++_j : --_j) {
makeBaseCardElement('tableauPileBase', "tableauPileBase" + i, this.positions.tableauPiles[i]);
}
$('<div class="button gray undoButton">Undo</div>').css(this.positions.undoButton).appendTo(baseContainer);
$(this.rootElement).append(baseContainer);
overlayContainer = document.createElement('div');
overlayContainer.className = 'overlayContainer';
overlayContainer.innerHTML = '<div class="youWin"><h2>You win!</h2><div class="button green playAgainButton">Deal New Cards</div></div>';
$(this.rootElement).append(overlayContainer);
dummy = document.createElement('div');
dummy.className = 'dummy';
$(this.rootElement).append(dummy);
return $(dummy).css({
scale: 1
});
};
Klondike.prototype.getCardController = function(cardOrId) {
return this.cardControllers[cardOrId instanceof App.Models.Card ? cardOrId.id : cardOrId];
};
Klondike.prototype.getCardControllers = function(cardsOrIds) {
var c, _i, _len, _results;
_results = [];
for (_i = 0, _len = cardsOrIds.length; _i < _len; _i++) {
c = cardsOrIds[_i];
_results.push(this.getCardController(c));
}
return _results;
};
Klondike.prototype.newGame = function() {
var card, controller, id, _i, _len, _ref56, _ref57;
this.model = this.createModel();
this.calculateGeometry();
this.appendBaseElements();
this.model.deal();
_ref56 = this.cardControllers;
for (id in _ref56) {
controller = _ref56[id];
controller.destroy();
}
this.cardControllers = {};
_ref57 = this.model.deck;
for (_i = 0, _len = _ref57.length; _i < _len; _i++) {
card = _ref57[_i];
this.cardControllers[card.id] = new App.Controllers.Card(card);
this.cardControllers[card.id].appendTo(this.rootElement);
}
this.renderAfterCommand('deal');
return this.registerEventHandlers();
};
Klondike.prototype.processUserCommand = function(cmd) {
var nextCmd,
_this = this;
this.removeEventHandlers();
if (!this.model.hasBegun) {
this.model.hasBegun = true;
App.Events.beginGame();
}
this.processCommand(cmd);
if (nextCmd = this.model.nextAutoCommand()) {
return setTimeout((function() {
return _this.processUserCommand(nextCmd);
}), this.nextAnimationDelay(cmd));
} else if (this.model.isWon()) {
return setTimeout(this.youWin, this.nextAnimationDelay(cmd));
} else {
return this.registerEventHandlers();
}
};
Klondike.prototype.processCommand = function(cmd) {
this.model.executeCommand(cmd);
return this.renderAfterCommand(cmd);
};
Klondike.prototype.undo = function() {
var cmd, commandList;
if (this.model.undoStack.length === 0) {
return;
}
commandList = _(this.model.undoStack).last();
this.removeEventHandlers();
cmd = commandList.pop();
this.processCommand(cmd);
if (commandList.length) {
return setTimeout(this.undo, this.nextAnimationDelay(cmd));
} else {
this.model.undoStack.pop();
return this.registerEventHandlers();
}
};
Klondike.prototype.renderAfterCommand = function(cmd) {
this.updateRestingStates();
this.updateWidgets();
return this.animateCards(cmd);
};
Klondike.prototype.updateRestingStates = function() {
var card, foundation, i, index, pos, zIndex, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _ref56, _ref57, _ref58, _ref59, _ref60, _results;
zIndex = 1000;
_ref56 = this.model.stock;
for (_i = 0, _len = _ref56.length; _i < _len; _i++) {
card = _ref56[_i];
this.getCardController(card.id).setRestingState(this.positions.stock, zIndex++, false);
}
zIndex = 1000;
_ref57 = this.model.waste;
for (index = _j = 0, _len1 = _ref57.length; _j < _len1; index = ++_j) {
card = _ref57[index];
pos = _.clone(this.positions.waste);
pos.left += Math.max(index + Math.min(this.model.waste.length, this.model.cardsToTurn) - this.model.waste.length, 0) * this.positions.wasteFanningOffset;
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
}
_ref58 = this.model.foundations;
for (index = _k = 0, _len2 = _ref58.length; _k < _len2; index = ++_k) {
foundation = _ref58[index];
zIndex = 1000;
for (_l = 0, _len3 = foundation.length; _l < _len3; _l++) {
card = foundation[_l];
this.getCardController(card.id).setRestingState(this.positions.foundations[index], zIndex++, true);
}
}
_results = [];
for (i = _m = 0, _ref59 = this.model.faceDownTableauPiles.length; 0 <= _ref59 ? _m < _ref59 : _m > _ref59; i = 0 <= _ref59 ? ++_m : --_m) {
zIndex = 1000;
pos = _.clone(this.positions.tableauPiles[i]);
_ref60 = this.model.faceDownTableauPiles[i];
for (_n = 0, _len4 = _ref60.length; _n < _len4; _n++) {
card = _ref60[_n];
this.getCardController(card.id).setRestingState(pos, zIndex++, false);
pos.top += this.positions.tableauFanningOffset;
}
_results.push((function() {
var _len5, _o, _ref61, _results1;
_ref61 = this.model.faceUpTableauPiles[i];
_results1 = [];
for (_o = 0, _len5 = _ref61.length; _o < _len5; _o++) {
card = _ref61[_o];
this.getCardController(card.id).setRestingState(pos, zIndex++, true);
_results1.push(pos.top += this.positions.tableauFanningOffset);
}
return _results1;
}).call(this));
}
return _results;
};
Klondike.prototype.updateWidgets = function() {
var exhausted, setVisibility, _ref56;
setVisibility = function(element, visible) {
if (visible) {
return $(element).show();
} else {
return $(element).hide();
}
};
exhausted = (this.model.stock.length === (_ref56 = this.model.waste.length) && _ref56 === 0);
setVisibility('.exhaustedImage', exhausted);
setVisibility('.redealImage', !exhausted);
if ($.browser.msie) {
return $('body').find(':not(input)').attr('unselectable', 'on');
}
};
Klondike.prototype.animateCards = function(cmd) {
var c, card, controller, movedCards, previousFannedCards, shiftingCards, speed, turnedCards, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref56, _ref57, _ref58, _ref59, _ref60, _ref61, _results;
switch (cmd != null ? cmd.action : void 0) {
case 'move':
speed = cmd.direction === 'undo' ? this.speeds.undoMove : cmd.guiAction === 'drag' ? this.speeds.snap : this.speeds.playToFoundation;
movedCards = this.model.getCollection(cmd.direction === 'do' ? cmd.dest : cmd.src).slice(-cmd.numberOfCards);
_ref56 = this.getCardControllers(movedCards);
for (_i = 0, _len = _ref56.length; _i < _len; _i++) {
controller = _ref56[_i];
controller.animateToRestingPosition(speed);
}
if (cmd.src[0] === 'waste' || cmd.dest[0] === 'waste') {
shiftingCards = (function() {
var _j, _len1, _ref57, _results;
_ref57 = this.model.waste.slice(-this.model.cardsToTurn);
_results = [];
for (_j = 0, _len1 = _ref57.length; _j < _len1; _j++) {
c = _ref57[_j];
if (__indexOf.call(movedCards, c) < 0) {
_results.push(c);
}
}
return _results;
}).call(this);
_ref57 = this.getCardControllers(shiftingCards);
for (_j = 0, _len1 = _ref57.length; _j < _len1; _j++) {
controller = _ref57[_j];
controller.animateToRestingPosition(this.speeds.shift, false);
}
}
break;
case 'flip':
if (cmd.direction === 'do') {
_assert(this.model.faceUpTableauPiles[cmd.tableauPileIndex].length === 1);
card = this.model.faceUpTableauPiles[cmd.tableauPileIndex][0];
} else {
card = _(this.model.faceDownTableauPiles[cmd.tableauPileIndex]).last();
}
this.getCardController(card).animateToRestingFace(this.speeds.flip);
break;
case 'turnStock':
if (cmd.direction === 'do') {
turnedCards = this.model.waste.slice(-this.model.cardsToTurn);
_ref58 = this.getCardControllers(turnedCards);
for (_k = 0, _len2 = _ref58.length; _k < _len2; _k++) {
controller = _ref58[_k];
controller.animateToRestingPosition(this.speeds.turn);
}
previousFannedCards = this.model.waste.slice(-this.model.cardsToTurn * 2 + 1, -this.model.cardsToTurn);
_ref59 = this.getCardControllers(previousFannedCards);
for (_l = 0, _len3 = _ref59.length; _l < _len3; _l++) {
controller = _ref59[_l];
$(controller.element).delay(this.speeds.turn.duration);
}
} else {
turnedCards = this.model.stock.slice(-cmd.cardsTurned);
_ref60 = this.getCardControllers(turnedCards);
for (_m = 0, _len4 = _ref60.length; _m < _len4; _m++) {
controller = _ref60[_m];
controller.jumpToRestingFace();
controller.animateToRestingPosition(this.speeds.turn);
}
}
break;
case 'redeal':
null;
}
_ref61 = _(this.cardControllers).values();
_results = [];
for (_n = 0, _len5 = _ref61.length; _n < _len5; _n++) {
controller = _ref61[_n];
controller.jumpToRestingPosition();
_results.push(controller.jumpToRestingFace());
}
return _results;
};
Klondike.prototype.nextAnimationDelay = function(cmd) {
switch (cmd != null ? cmd.action : void 0) {
case 'move':
if (cmd.direction === 'undo') {
return this.speeds.undoMove.duration / 2;
} else if (cmd.guiAction === 'drag') {
return this.speeds.snap.duration / 2;
} else {
return this.speeds.playToFoundation.duration / 2;
}
break;
case 'flip':
return this.speeds.flip.duration / (cmd.direction === 'do' ? 3 : 2);
case 'turnStock':
return this.speeds.turn.duration / 2;
default:
return 0;
}
};
Klondike.prototype.removeEventHandlers = function() {
$(this.rootElement).rawdraggable('destroy');
return $(this.rootElement).off();
};
Klondike.prototype.registerEventHandlers = function() {
var i, locator, stockCard, topMostCard, _i, _len, _ref56,
_this = this;
this.removeEventHandlers();
$(this.rootElement).on('click', '.undoButton', this.undo);
if (this.model.stock.length) {
stockCard = _(this.model.stock).last();
$(this.rootElement).on('click', "#" + stockCard.id, this.turnStock);
} else if (this.model.waste.length) {
$(this.rootElement).on('click', "#redealImage", this.redeal);
}
_ref56 = [['waste']].concat(__slice.call((function() {
var _j, _ref56, _results;
_results = [];
for (i = _j = 0, _ref56 = this.model.faceUpTableauPiles.length; 0 <= _ref56 ? _j < _ref56 : _j > _ref56; i = 0 <= _ref56 ? ++_j : --_j) {
_results.push(['faceUpTableauPiles', i]);
}
return _results;
}).call(this)));
for (_i = 0, _len = _ref56.length; _i < _len; _i++) {
locator = _ref56[_i];
if (topMostCard = _(this.model.getCollection(locator)).last()) {
(function(locator) {
return $(_this.rootElement).on('dblclick', "#" + topMostCard.id, function(e) {
if (!(locator[0] === 'waste' && $(e.target).is(':animated'))) {
return _this.playToAnyFoundation(locator);
}
});
})(locator);
}
}
return this._registerDragAndDrop();
};
Klondike.prototype._registerDragAndDrop = function() {
var _this = this;
return $(this.rootElement).rawdraggable({
distance: 3,
mouseCapture: function(e) {
var element, isRestingCard;
_this.dragState = {};
element = document.elementFromPoint(e.clientX, e.clientY);
isRestingCard = $(element).hasClass('card') && element.id && !$(element).is(':animated');
_this.dragState.startController = isRestingCard && _this.getCardController(element.id);
return isRestingCard;
},
mouseStart: function(e) {
var c, clone, el, _i, _len, _ref56, _ref57, _ref58, _results;
_this.dragState.startPagePosition = {
left: e.pageX,
top: e.pageY
};
_this.dragState.cards = _this.model.movedWithCard(_this.dragState.startController.model);
_this.dragState.controllers = _this.getCardControllers((_ref56 = _this.dragState.cards) != null ? _ref56 : []);
if (_this.dragState.cards) {
_this.dragState.elements = (function() {
var _i, _len, _ref57, _results;
_ref57 = this.dragState.controllers;
_results = [];
for (_i = 0, _len = _ref57.length; _i < _len; _i++) {
c = _ref57[_i];
_results.push(c.element);
}
return _results;
}).call(_this);
} else {
clone = $(_this.dragState.startController.element).clone();
clone.removeAttr('id', null).css({
opacity: '0.5'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment