-
Notifications
You must be signed in to change notification settings - Fork 58
/
Copy pathplayingCards.js
266 lines (252 loc) · 8.32 KB
/
playingCards.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/*jslint jquery:true */
/**
* playingCards is a standard card deck library
* This can be used to play standard card games (which will be additional rule modules attached to this set)
*
* usage: var cardDeck = new playingCards(conf);
* override defaults for playingCards() and for card() with
* playingCards.defaults
* playingCards.card.defaults
*
* @author Copyright (c) 2010 Adam Eivy (antic | atomantic)
* @license Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
if (Array.indexOf === undefined) {
// doens't exist in oldIE
/* Finds the index of the first occurence of item in the array, or -1 if not found */
Array.prototype.indexOf = function(v) {
for (var i = 0; i < this.length; ++i) {
if (this[i] === v) {
return i;
}
}
return - 1;
};
}
(function(window,document,undefined){
/**
* The playing card library core object
*
* @param obj conf Configuration option overrides
*
* @return obj an instance of the constructed library object (deck of cards)
*/
var playingCards = window.playingCards = function(conf) {
var c = objExtend(playingCards.defaults, conf);
if (! (this instanceof playingCards)) {
// in jquery mode
c.el = $(this); // capture the context (this will be the cardTable/Deck element)
return new playingCards(c);
}
this.conf = c;
this.init();
if (this.conf.startShuffled) {
this.shuffle(5);
}
return this;
};
/**
* initializer - builds the deck
*/
playingCards.prototype.init = function() {
this.cards = [];
var o = this.conf,
l,i,s,r,j;
// populate draw pile
for (i = 0; i < o.decks; i++) {
// standard
for (s in o.suits) {
for (r in o.ranks) {
l = this.cards.length;
this.cards[l] = new playingCards.card(r, o.ranks[r], s, o.suits[s]);
}
}
// jokers
for (j = 0; j < o.jokers; j++) {
l = this.cards.length;
// suit will always be 1 or 2
this.cards[l] = new playingCards.card("N", o.jokerText, (j % 2) + 1, '');
}
}
};
// TODO: create more methods:
// playingCards.prototype.order (set to out-of-box ordering)
// -- do we want other special formations (like trick deck ordering systems that deal perfect hands)?
// -- probably going to leave this as an extension option
/**
* draw a card
* @return mixed (object|null) A card object (if a card is available)
*/
playingCards.prototype.draw = function() {
return this.cards.length > 0 ? this.cards.pop() : null;
};
/**
* add a card to the top of the deck
*/
playingCards.prototype.addCard = function(card) {
this.cards.push(card);
};
/**
* get the number of cards remaining in the deck
* (easy enough just to call cardObject.cards.length but hey)
*/
playingCards.prototype.count = function() {
return this.cards.length;
};
/**
* shuffle the deck
*
* @param int n The number of times to shuffle (defaults to 5)
*/
playingCards.prototype.shuffle = function(n) {
if (!n) {
n = 5;
}
var l = this.cards.length,
r,tmp,i,j;
for (i = 0; i < n; i++) {
for (j = 0; j < l; j++) {
r = Math.floor(Math.random() * l);
tmp = this.cards[j];
this.cards[j] = this.cards[r];
this.cards[r] = tmp;
}
}
};
playingCards.prototype.orderByRank = function() {
this.cards.sort(compareRank);
}
playingCards.prototype.orderBySuit = function() {
this.init();
}
/*
* requires jquery (currently)
* TODO: put this in a UI extension pack along with all the other demo methods
*/
playingCards.prototype.spread = function(dest) {
if (!this.conf.el && !dest) {
return false;
}
var to = this.conf.el || dest,
l = this.cards.length,
i;
to.html('');
// clear (just a demo)
for (i = 0; i < l; i++) {
to.append(this.cards[i].getHTML());
}
};
/**
* configuration defaults
*/
playingCards.defaults = {
"decks": 1,
// TODO: enable 'font' option -- loading cards.ttf
"renderMode": 'css',
// For a coustom " of "-String
"ofString": " of ",
"startShuffled": true,
"jokers": 2,
"jokerText": "Joker",
"ranks": {
"2": "Two",
"3": "Three",
"4": "Four",
"5": "Five",
"6": "Six",
"7": "Seven",
"8": "Eight",
"9": "Nine",
"10": "Ten",
"J": "Jack",
"Q": "Queen",
"K": "King",
"A": "Ace"
},
"suits": {
"S": "Spades",
"D": "Diamonds",
"C": "Clubs",
"H": "Hearts"
}
};
/**
* create a playing card
*
* @param string rank The numeric or letter value of the card (short value)
* @param string rankString The full text representation of the rank (localized)
* @param string suit The letter value of the suite (short value)
* @param string suitString The full text representation of the suit (localized)
* @param obj conf Overriding configuration
*
* @return object The card object
*/
playingCards.card = function(rank, rankString, suit, suitString, conf) {
if (! (this instanceof playingCards.card)) {
return new playingCards.card(rank, rankString, suit, suitString, conf);
}
this.conf = objExtend(playingCards.card.defaults, conf);
if (suit === undefined) {
//Arguments are rank, suit
suit = rankString;
rankString = playingCards.defaults.ranks[rank];
suitString = playingCards.defaults.suits[suit];
}
this.rank = rank;
this.rankString = rankString;
this.suit = suit;
this.suitString = suitString;
return this;
};
/**
* configuration defaults
*/
playingCards.card.defaults = {
"singleFace": false
// false will use a different image for each suit/face, true will use diamond image for all
};
/**
* get the text representation of the card
*/
playingCards.card.prototype.toString = function() {
return this.suitString !== "" ? this.rankString + playingCards.defaults.ofString + this.suitString: this.rankString;
};
/**
* Simple object extend to override default settings
*/
function objExtend(o, ex) {
if (!ex) {
return o;
}
for (var p in ex) {
o[p] = ex[p];
}
return o;
}
/**
* Compare functions
*/
function compareRank(a, b) {
var intRegex = /^\d+$/;
if (a.rank == b.rank) return 0;
if (a.rank == "N") return 1;
if (b.rank == "N") return -1;
if (a.rank == "A") return 1;
if (b.rank == "A") return -1;
if (!isNaN(a.rank - b.rank)) return a.rank - b.rank;
if (a.rank == "K" && b.rank == "J") return 1;
if (a.rank == "J" && b.rank == "K") return -1;
if (a.rank == "K" && b.rank == "Q") return 1;
if (a.rank == "Q" && b.rank == "K") return -1;
if (a.rank == "Q" && b.rank == "J") return 1;
if (a.rank == "J" && b.rank == "Q") return -1;
if (a.rank == "K" && intRegex.test(b.rank)) return 1;
if (a.rank == "Q" && intRegex.test(b.rank)) return 1;
if (a.rank == "J" && intRegex.test(b.rank)) return 1;
if (intRegex.test(a.rank) && b.rank == "K") return -1;
if (intRegex.test(a.rank) && b.rank == "Q") return -1;
if (intRegex.test(a.rank) && b.rank == "J") return -1;
}
})(this,this.document);