Skip to content

Instantly share code, notes, and snippets.

@sukima
Last active February 6, 2019 20:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sukima/156293e8b441570dee285a0ca062f768 to your computer and use it in GitHub Desktop.
Save sukima/156293e8b441570dee285a0ca062f768 to your computer and use it in GitHub Desktop.
Card Shuffle
import Component from '@ember/component';
import { computed } from '@ember/object';
import { reads } from '@ember/object/computed';
import { htmlSafe } from '@ember/string';
import { SUITS, JOKER } from '../libs/card';
const SUIT_MAP = Object.freeze({
[SUITS.CLUBS]: 'clubs',
[SUITS.DIAMONDS]: 'diams',
[SUITS.HEARTS]: 'hearts',
[SUITS.SPADES]: 'spades'
});
const JOKER_RANK_MAP = Object.freeze({
[JOKER.A]: 'big',
[JOKER.B]: 'little'
});
export default Component.extend({
tagName: 'span',
classNames: ['card'],
classNameBindings: ['rankClass', 'suitClass'],
rankClass: computed('data.{isJoker,rank}', function() {
return this.data.isJoker
? JOKER_RANK_MAP[this.data.rank]
: `rank-${this.data.rank}`;
}),
suitClass: computed('data.{isJoker,rank,suit}', function() {
return this.data.isJoker
? 'joker'
: SUIT_MAP[this.data.suit];
}),
rank: computed('data.rank', function() {
return `${this.data.rank}`.toUpperCase();
}),
suit: computed('data.{isJoker,suit}', function() {
return this.data.isJoker
? 'Joker'
: htmlSafe(`&${SUIT_MAP[this.data.suit]};`);
})
});
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import move from 'ember-animated/motions/move';
import adjustCSS from 'ember-animated/motions/adjust-css';
import { serial } from 'ember-animated';
import { task, timeout } from 'ember-concurrency';
import { orderedDeck, shuffledDeck } from '../libs/deck';
import { JOKER } from '../libs/card';
export default Controller.extend({
deck: orderedDeck(),
transition: function * (context) {
let { keptSprites } = context;
keptSprites.forEach(move);
},
jokers: computed('deck', function() {
let jokers = this.deck.filterBy('isJoker');
return jokers[0].rank === JOKER.A
? { A: jokers[0], B: jokers[1] }
: { A: jokers[1], B: jokers[0] };
}),
cryptoSequence: task(function* () {
this.move(this.jokers.A, -1);
yield timeout(1000);
this.move(this.jokers.B, -2);
yield timeout(2000);
yield this.jokerCutFlip.perform();
}).drop(),
jokerCutFlip: task(function* () {
let jokers = [];
for (let i = 0; i < this.deck.length && jokers.length < 2; i++) {
if (this.deck.objectAt(i).isJoker) jokers.push(i);
}
let [jokerA, jokerB] = jokers;
let sets = [
this.deck.slice(0, jokerA),
this.deck.slice(jokerA, jokerB + 1),
this.deck.slice(jokerB + 1)
];
this.set('deck', sets[2].concat(sets[1], sets[0]));
}).drop(),
shuffle() {
this.set('deck', shuffledDeck());
},
move(card, count) {
let len = this.deck.length;
let fromIndex = this.deck.indexOf(card);
let toIndex = (fromIndex + count + len) % len;
this.deck.splice(fromIndex, 1);
this.deck.splice(toIndex, 0, card);
this.deck.arrayContentDidChange(fromIndex, 0, 0);
}
});
import EmberObject from '@ember/object';
import { equal, or } from '@ember/object/computed';
export const SUITS = Object.freeze({
CLUBS: 1,
DIAMONDS: 2,
HEARTS: 3,
SPADES: 4
});
export const RANKS = Object.freeze({
ACE: 'a',
TWO: 2,
THREE: 3,
FOUR: 4,
FIVE: 5,
SIX: 6,
SEVEN: 7,
EIGHT: 8,
NINE: 9,
TEN: 10,
JACK: 'j',
QUEEN: 'q',
KING: 'k'
});
export const JOKER = Object.freeze({
A: '+',
B: '-'
});
export const Card = EmberObject.extend();
export const Joker = Card.extend({
isJoker: true,
suit: 'joker'
});
import { Card, Joker, SUITS, RANKS, JOKER } from './card';
export function orderedDeck() {
const { SPADES, HEARTS, DIAMONDS, CLUBS } = SUITS;
let id = 1;
let deck = [
Joker.create({ id: id++, rank: JOKER.B }),
Joker.create({ id: id++, rank: JOKER.A })
];
for (let suit of suitsBridgeOrder()) {
for (let rank of ranksBridgeOrder()) {
deck.push(Card.create({ id: id++, rank, suit }));
}
}
return deck;
}
export function shuffledDeck() {
const { floor, random } = Math;
let deck = orderedDeck();
let counter = deck.length;
while (counter > 0) {
let index = floor(random() * counter);
counter--;
let temp = deck[counter];
deck[counter] = deck[index];
deck[index] = temp;
}
return deck;
}
export function * suitsBridgeOrder() {
yield SUITS.SPADES;
yield SUITS.HEARTS;
yield SUITS.DIAMONDS;
yield SUITS.CLUBS;
}
export function * ranksBridgeOrder() {
yield RANKS.KING;
yield RANKS.QUEEN;
yield RANKS.JACK;
yield RANKS.TEN;
yield RANKS.NINE;
yield RANKS.EIGHT;
yield RANKS.SEVEN;
yield RANKS.SIX;
yield RANKS.FIVE;
yield RANKS.FOUR;
yield RANKS.THREE;
yield RANKS.TWO;
yield RANKS.ACE;
}
.full-deck {
position: relative;
height: 132px;
padding: 0;
}
.full-deck .card {
position: absolute;
width: 63px;
height: 88px;
bottom: 0px;
box-shadow: none;
}
.full-deck .card.joker,
.full-deck .card.selected {
bottom: 15px;
}
.full-deck .card:nth-child(1) { left: calc(0 * 15px); z-index: 2; }
.full-deck .card:nth-child(2) { left: calc(1 * 15px); z-index: 3; }
.full-deck .card:nth-child(3) { left: calc(2 * 15px); z-index: 4; }
.full-deck .card:nth-child(4) { left: calc(3 * 15px); z-index: 5; }
.full-deck .card:nth-child(5) { left: calc(4 * 15px); z-index: 6; }
.full-deck .card:nth-child(6) { left: calc(5 * 15px); z-index: 7; }
.full-deck .card:nth-child(7) { left: calc(6 * 15px); z-index: 8; }
.full-deck .card:nth-child(8) { left: calc(7 * 15px); z-index: 9; }
.full-deck .card:nth-child(9) { left: calc(8 * 15px); z-index: 10; }
.full-deck .card:nth-child(10) { left: calc(9 * 15px); z-index: 11; }
.full-deck .card:nth-child(11) { left: calc(10 * 15px); z-index: 12; }
.full-deck .card:nth-child(12) { left: calc(11 * 15px); z-index: 13; }
.full-deck .card:nth-child(13) { left: calc(12 * 15px); z-index: 14; }
.full-deck .card:nth-child(14) { left: calc(13 * 15px); z-index: 15; }
.full-deck .card:nth-child(15) { left: calc(14 * 15px); z-index: 16; }
.full-deck .card:nth-child(16) { left: calc(15 * 15px); z-index: 17; }
.full-deck .card:nth-child(17) { left: calc(16 * 15px); z-index: 18; }
.full-deck .card:nth-child(18) { left: calc(17 * 15px); z-index: 19; }
.full-deck .card:nth-child(19) { left: calc(18 * 15px); z-index: 20; }
.full-deck .card:nth-child(20) { left: calc(19 * 15px); z-index: 21; }
.full-deck .card:nth-child(21) { left: calc(20 * 15px); z-index: 22; }
.full-deck .card:nth-child(22) { left: calc(21 * 15px); z-index: 23; }
.full-deck .card:nth-child(23) { left: calc(22 * 15px); z-index: 24; }
.full-deck .card:nth-child(24) { left: calc(23 * 15px); z-index: 25; }
.full-deck .card:nth-child(25) { left: calc(24 * 15px); z-index: 26; }
.full-deck .card:nth-child(26) { left: calc(25 * 15px); z-index: 27; }
.full-deck .card:nth-child(27) { left: calc(26 * 15px); z-index: 28; }
.full-deck .card:nth-child(28) { left: calc(27 * 15px); z-index: 29; }
.full-deck .card:nth-child(29) { left: calc(28 * 15px); z-index: 30; }
.full-deck .card:nth-child(30) { left: calc(29 * 15px); z-index: 31; }
.full-deck .card:nth-child(31) { left: calc(30 * 15px); z-index: 32; }
.full-deck .card:nth-child(32) { left: calc(31 * 15px); z-index: 33; }
.full-deck .card:nth-child(33) { left: calc(32 * 15px); z-index: 34; }
.full-deck .card:nth-child(34) { left: calc(33 * 15px); z-index: 35; }
.full-deck .card:nth-child(35) { left: calc(34 * 15px); z-index: 36; }
.full-deck .card:nth-child(36) { left: calc(35 * 15px); z-index: 37; }
.full-deck .card:nth-child(37) { left: calc(36 * 15px); z-index: 38; }
.full-deck .card:nth-child(38) { left: calc(37 * 15px); z-index: 39; }
.full-deck .card:nth-child(39) { left: calc(38 * 15px); z-index: 40; }
.full-deck .card:nth-child(40) { left: calc(39 * 15px); z-index: 41; }
.full-deck .card:nth-child(41) { left: calc(40 * 15px); z-index: 42; }
.full-deck .card:nth-child(42) { left: calc(41 * 15px); z-index: 43; }
.full-deck .card:nth-child(43) { left: calc(42 * 15px); z-index: 44; }
.full-deck .card:nth-child(44) { left: calc(43 * 15px); z-index: 45; }
.full-deck .card:nth-child(45) { left: calc(44 * 15px); z-index: 46; }
.full-deck .card:nth-child(46) { left: calc(45 * 15px); z-index: 47; }
.full-deck .card:nth-child(47) { left: calc(46 * 15px); z-index: 48; }
.full-deck .card:nth-child(48) { left: calc(47 * 15px); z-index: 49; }
.full-deck .card:nth-child(49) { left: calc(48 * 15px); z-index: 50; }
.full-deck .card:nth-child(50) { left: calc(49 * 15px); z-index: 51; }
.full-deck .card:nth-child(51) { left: calc(50 * 15px); z-index: 52; }
.full-deck .card:nth-child(52) { left: calc(51 * 15px); z-index: 53; }
.full-deck .card:nth-child(53) { left: calc(52 * 15px); z-index: 54; }
.full-deck .card:nth-child(54) { left: calc(53 * 15px); z-index: 55; }
<div>
<button {{action this.shuffle}}>Shuffle</button>
<button {{action this.move this.jokers.A -1}}>&lt;&lt;</button>
<button {{action this.move this.jokers.A 1}}>&gt;&gt;</button>
<button onclick={{perform this.jokerCutFlip}}>Joker Cut &amp; Flip</button>
<button onclick={{perform this.cryptoSequence}}>Crypto Seq</button>
</div>
{{#animated-container}}
<div class="playingCards faceImages full-deck">
{{#animated-each this.tempDeck key="id" use=this.transition as |carddata|}}
<CardFace @data={{carddata}}/>
{{/animated-each}}
<div class="clear"></div>
</div>
<div class="playingCards faceImages full-deck">
{{#animated-each this.deck key="id" use=this.transition as |carddata|}}
<CardFace @data={{carddata}}/>
{{/animated-each}}
<div class="clear"></div>
</div>
{{/animated-container}}
<span class="rank">{{this.rank}}</span>
<span class="suit">{{this.suit}}</span>
{
"version": "0.15.1",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"cards_css": "https://selfthinker.github.io/CSS-Playing-Cards/cards.css",
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js",
"ember": "3.4.3",
"ember-template-compiler": "3.4.3",
"ember-testing": "3.4.3"
},
"addons": {
"ember-animated": "0.4.1",
"ember-concurrency": "0.8.27"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment