Created
January 24, 2014 17:46
-
-
Save joliss/8602333 to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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