Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions scripts/card.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
export default class Card {
faceUp = false;
x = 0;
y = 0;
width = 75;
height = 100;
backImg = null;
frontImg = null;
suit = null;
Expand Down
2 changes: 1 addition & 1 deletion scripts/falling_cards.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const fallingCards = (canvas, foundations) => {
movingCard = getNextFallingCard();
}

context.drawImage(movingCard.image, movingCard.x, movingCard.y);
context.drawImage(movingCard.image, movingCard.x, movingCard.y, movingCard.width, movingCard.height);

// determine next position
movingCard.x += movingCard.velocity.x;
Expand Down
4 changes: 2 additions & 2 deletions scripts/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default class Foundation extends Stack {

draw(context) {
if (!this.hasCards) {
context.drawImage(this.image, this.x, this.y);
context.drawImage(this.image, this.x, this.y, this.width, this.height);

return;
}
Expand All @@ -20,7 +20,7 @@ export default class Foundation extends Stack {
card.y = this.y;

// only draw the top-most card
context.drawImage(card.image, card.x, card.y);
context.drawImage(card.image, card.x, card.y, card.width, card.height);
}

validPlay(card) {
Expand Down
140 changes: 130 additions & 10 deletions scripts/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,36 +69,44 @@ const klondike = e => {
// (e.g. within 500ms) then the interaction counts as a double-click
let lastOnDownTimestamp = Date.now();

// stores reference to falling cards animation
let interval;

// initialize all places where a card can be placed - https://en.wikipedia.org/wiki/Glossary_of_patience_terms

// "talon" (draw pile)
// placed in the upper left hand corner
const talon = new Talon(margin, margin, IMAGES);
const talon = new Talon(0, 0, IMAGES);

// "waste" (play stack)
// placed relative to the talon
const waste = new Waste(talon.x + cardWidth + margin, talon.y);
const waste = new Waste(0, 0);

// 4 "foundations"
// aligned vertically with talon/waste, on right side of tableau
const foundations = [];
for (let i = 0; i < 4; i += 1) {
foundations.push(new Foundation(width - (cardWidth * (i + 1)) - (margin * (i + 1)), margin, IMAGES));
foundations.push(new Foundation(0, 0, IMAGES));
}

// 7 "piles"
// spans the width of the tableau, under the talon/waste/foundations
const piles = [];
for (let i = 0; i < 7; i += 1) {
piles.push(new Pile(cardWidth * i + (margin * (i + 1)), cardHeight + margin * 2));
piles.push(new Pile(0, 0));
}

// initialize deck
const DECK = [];

// list of cards, to enumerate when changing sizes
const cards = [];

SUITS.forEach(suit => {
RANKS.forEach(rank => {
DECK.push(new Card(rank, suit, IMAGES));
const card = new Card(rank, suit, IMAGES);
DECK.push(card);
cards.push(card);
});
});

Expand Down Expand Up @@ -157,7 +165,7 @@ const klondike = e => {

const draw = () => {
// clear previous contents
context.clearRect(0, 0, width, height);
context.clearRect(0, 0, canvas.width, canvas.height);

// draw card piles
talon.draw(context);
Expand Down Expand Up @@ -186,9 +194,6 @@ const klondike = e => {
});
};

// initial draw
draw();

// Event handlers
const onDown = e => {
e.preventDefault();
Expand Down Expand Up @@ -298,6 +303,9 @@ const klondike = e => {

if (!card.faceUp) {
card.faceUp = true;

// TODO: don't allow the same click to both turn over _and_ grab card
return;
}

// break the parent -> child connection so the card(s) are no longer drawn at the source
Expand All @@ -316,7 +324,7 @@ const klondike = e => {
}
});

// this should really be called `draw`
// update canvas
draw();
};

Expand All @@ -339,6 +347,13 @@ const klondike = e => {
const onUp = e => {
e.preventDefault();

if (interval) {
window.clearInterval(interval);
interval = null;

// TODO: reset game
}

let point = getCoords(e);

// if not holding a card, then there's nothing to do
Expand Down Expand Up @@ -492,6 +507,109 @@ const klondike = e => {
}
};

const onResize = () => {
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
let aspectRatio = 4 / 3;
let canvas = document.querySelector('#game');

// canvas is as large as the window;
// cards will be placed in a subset of this area
canvas.width = windowWidth;
canvas.height = windowHeight;

// playable area, where cards will be drawn
let tableauWidth;
let tableauHeight;

if (windowWidth / windowHeight > aspectRatio) {
// wider than it is tall; use the window height to calculate tableau width
tableauWidth = windowHeight * aspectRatio;
tableauHeight = windowHeight;
} else {
// taller than it is wide; use window width to calculate tableau height
tableauHeight = windowWidth / aspectRatio;
tableauWidth = windowWidth;
}

let windowMargin = (windowWidth - tableauWidth) / 2;

// tweak these values as necessary
let cardMargin = (8 / 605) * tableauWidth;
let cardOffset = cardMargin * 2.5;

let cardWidth = (77.25 / 605) * tableauWidth;
let cardHeight = (100 / 454) * tableauHeight;

// enumerate over all cards/stacks in order to set their width/height
for (let group of [grabbed, talon, waste, foundations, piles, cards]) {
if (Array.isArray(group)) {
for (let item of group) {
item.width = cardWidth;
item.height = cardHeight;
item.cardOffset = cardOffset;
}
} else {
group.width = cardWidth;
group.height = cardHeight;
group.cardOffset = cardOffset;
}
}

// TODO: option to invert orientation of tableau;
// talon/waste on right side, foundations on left side
let mirror = true;

// update positions of talon, waste, foundations, and piles
if (mirror) {
talon.x = windowWidth - windowMargin - cardMargin - cardWidth;
talon.y = cardMargin;

waste.x = talon.x - cardMargin - cardWidth;
waste.y = talon.y;

foundations.forEach((f, i) => {
f.x = windowMargin + cardMargin + (cardWidth + cardMargin) * i;
f.y = cardMargin;
});

piles.forEach((p, i) => {
p.x = talon.x - (cardWidth + cardMargin) * i;
p.y = cardHeight + cardMargin * 2;
});
} else {
talon.x = windowMargin + cardMargin;
talon.y = cardMargin;

waste.x = talon.x + cardMargin + cardWidth;
waste.y = talon.y;

foundations.forEach((f, i) => {
f.x = (windowWidth - windowMargin) - ((cardWidth + cardMargin) * (i + 1));
f.y = cardMargin;
});

piles.forEach((p, i) => {
p.x = (cardWidth + cardMargin) * i + talon.x;
p.y = cardHeight + (cardMargin * 2);
});
}


// debug
// let ctx = canvas.getContext('2d');
// ctx.fillStyle = 'red';
// ctx.fillRect(windowMargin, 0, tableauWidth, tableauHeight);

if (!interval) {
// update screen if not displaying card waterfall
draw();
}
};

// initial draw/resize
onResize();

canvas.addEventListener('mousedown', onDown);
canvas.addEventListener('mousemove', onMove);
canvas.addEventListener('mouseup', onUp);
Expand All @@ -500,6 +618,8 @@ const klondike = e => {
canvas.addEventListener('touchmove', onMove);
canvas.addEventListener('touchend', onUp);

window.addEventListener('resize', onResize);

window.addEventListener('keydown', e => {
// return unless the keypress is meta/contrl + z (for undo)
if (!(e.metaKey || e.ctrlKey) || e.key !== 'z') {
Expand Down
17 changes: 4 additions & 13 deletions scripts/stack.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export default class Stack {
width = 75;
height = 100;
child = null;

constructor(type, x, y) {
Expand Down Expand Up @@ -47,16 +45,10 @@ export default class Stack {
card.x = x;
card.y = y;

context.drawImage(card.image, card.x, card.y);

// TODO: extract this magic number; previously `overlapOffset`
let offset = 18;
context.drawImage(card.image, card.x, card.y, card.width, card.height);

// if cards in play piles are still face down, draw them closer together
if (!card.faceUp) {
// TODO: extract this magic number
offset = 3;
}
let offset = card.faceUp ? this.cardOffset : this.cardOffset / 4;

// set up for next card (if necessary)
y = y + offset;
Expand All @@ -80,11 +72,10 @@ export default class Stack {
}

let card = this;
let offset = 18;

do {
// cards under other cards only have 18px (`overlapOffset`) of touchable space
let height = card.child ? offset : card.height;
// cards under other cards only have `cardOffset` of touchable space
let height = card.child ? this.cardOffset : card.height;

if (point.x > card.x && point.x < card.x + card.width &&
point.y > card.y && point.y < card.y + height &&
Expand Down
9 changes: 4 additions & 5 deletions scripts/talon.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default class Talon extends Stack {

draw(context) {
if (!this.hasCards) {
context.drawImage(this.image, this.x, this.y);
context.drawImage(this.image, this.x, this.y, this.width, this.height);

return;
}
Expand All @@ -28,12 +28,11 @@ export default class Talon extends Stack {
card.x = this.x + offset.x;
card.y = this.y + offset.y;

context.drawImage(card.image, card.x, card.y);
context.drawImage(card.image, card.x, card.y, card.width, card.height);

// update offset for next card
// TODO: extract these magic numbers
offset.x += 2;
offset.y += 1;
offset.x += this.cardOffset / 8;
offset.y += this.cardOffset / 12;
}

count += 1;
Expand Down
10 changes: 4 additions & 6 deletions scripts/waste.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ export default class Waste extends Stack {

draw(context) {
if (!this.hasCards) {
// context.drawImage(IMAGES['backs_target'], this.x, this.y);

return;
}

Expand All @@ -26,16 +24,16 @@ export default class Waste extends Stack {
if (Math.floor(count / 8) > drawnCards) {
drawnCards += 1;

context.drawImage(card.image, card.x, card.y);
context.drawImage(card.image, card.x, card.y, card.width, card.height);

// update offset for next card
offset.x += 2;
offset.y += 1;
offset.x += this.cardOffset / 8;
offset.y += this.cardOffset / 12;
}

// ensure the last card on the stack is drawn
if (!card.child) {
context.drawImage(card.image, card.x, card.y);
context.drawImage(card.image, card.x, card.y, card.width, card.height);
}

count += 1;
Expand Down