-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCard.java
More file actions
451 lines (401 loc) · 14.6 KB
/
Card.java
File metadata and controls
451 lines (401 loc) · 14.6 KB
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
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
/*A Card object represents a single card in the full deck, it contains all
information about each card such as Suit & Rank. The class can be used to
model cards across any card game, making it universally applicable*/
import java.io.*;
import java.util.*;
public class Card implements Serializable, Comparable<Card>
{
//used for version control when serializing
static final long serialVersionUID = 100239761;
//enum type for Rank
public enum Rank
{
TWO(2),
THREE(3),
FOUR(4),
FIVE(5),
SIX(6),
SEVEN(7),
EIGHT(8),
NINE(9),
TEN(10),
JACK(10),
QUEEN(10),
KING(10),
ACE(11);
//initialising local variables value, prevValue & a temporary variable
final int value;
final int prevValue;
int temp;
Rank(int x) {
value = x;
//finding prevValue
//if the current rank is TWO circle back to an ACE for previous card
if ((x - 1) == 1) {
temp = 11;
} else {
temp -= 1;
}
//value of prevValue is found using temp before being finalized
prevValue = temp;
}
//returns a randomly selected rank - used when InvalidArgumentsException is thrown in constructor
private static Rank randomRank()
{
Random random = new Random();
return values()[random.nextInt(values().length)];
}
//method for getting next rank from the rank it's called from
private static Rank[] vals = values();
public Rank next()
{
return vals[(this.ordinal() + 1) % vals.length];
}
//accessor method for value
private int getValue()
{
return value;
}
}
//enum type for Suit
public enum Suit
{
CLUBS,
DIAMONDS,
HEARTS,
SPADES;
//returns a randomly selected suit - used when InvalidArgumentsException is thrown in constructor
private static Suit randomSuit()
{
Random random = new Random();
return values()[random.nextInt(values().length)];
}
}
//attributes
private Rank rank;
private Suit suit;
/*----------CONSTRUCTOR METHODS------------*/
//NOTE - ARGUMENTS TO CONSTRUCTOR METHODS MUST BE CAPITALISED
public Card(String rankArg, String suitArg)
{
//assigning the rank attribute based on constructor arguments
try {
switch(rankArg)
{
case "TWO":
this.rank = Rank.TWO;
break;
case "THREE":
this.rank = Rank.THREE;
break;
case "FOUR":
this.rank = Rank.FOUR;
break;
case "FIVE":
this.rank = Rank.FIVE;
break;
case "SIX":
this.rank = Rank.SIX;
break;
case "SEVEN":
this.rank = Rank.SEVEN;
break;
case "EIGHT":
this.rank = Rank.EIGHT;
break;
case "NINE":
this.rank = Rank.NINE;
break;
case "TEN":
this.rank = Rank.TEN;
break;
case "JACK":
this.rank = Rank.JACK;
break;
case "QUEEN":
this.rank = Rank.QUEEN;
break;
case "KING":
this.rank = Rank.KING;
break;
case "ACE":
this.rank = Rank.ACE;
break;
//in the case of invalid arguments, a random rank and suit is selected and an exception is thrown to inform the user
default:
this.rank = Rank.randomRank();
this.suit = Suit.randomSuit();
throw new InvalidArgumentsException("An error occurred: " + rankArg + " is not a valid argument for Card. Random rank & suit selected: ", rank.name(), suit.name());
}
switch(suitArg)
{
case "SPADES":
this.suit = Suit.SPADES;
break;
case "DIAMONDS":
this.suit = Suit.DIAMONDS;
break;
case "HEARTS":
this.suit = Suit.HEARTS;
break;
case "CLUBS":
this.suit = Suit.CLUBS;
break;
//in the case of an invalid suit argument, one is selected at random and an exception is thrown to inform the user
default:
this.suit = Suit.randomSuit();
throw new InvalidArgumentsException("An error occurred: " + suitArg + " is not a valid argument for Suit. Random suit selected: ", suit.name());
}
}
catch(Exception ex)
{
System.out.println(ex.getMessage());
}
}
//alternative constructor which selects a suit at random
public Card(String rankArg)
{
try {
//assigning the rank attribute based on constructor arguments
switch (rankArg) {
case "TWO":
this.rank = Rank.TWO;
break;
case "THREE":
this.rank = Rank.THREE;
break;
case "FOUR":
this.rank = Rank.FOUR;
break;
case "FIVE":
this.rank = Rank.FIVE;
break;
case "SIX":
this.rank = Rank.SIX;
break;
case "SEVEN":
this.rank = Rank.SEVEN;
break;
case "EIGHT":
this.rank = Rank.EIGHT;
break;
case "NINE":
this.rank = Rank.NINE;
break;
case "TEN":
this.rank = Rank.TEN;
break;
case "JACK":
this.rank = Rank.JACK;
break;
case "QUEEN":
this.rank = Rank.QUEEN;
break;
case "KING":
this.rank = Rank.KING;
break;
case "ACE":
this.rank = Rank.ACE;
break;
default:
this.rank = Rank.randomRank();
this.suit = Suit.randomSuit();
throw new InvalidArgumentsException("An error occurred: " + rankArg + " is not a valid argument for Card. Random rank selected: ", rank.name());
}
//selects a random suit even in the case of no exception
this.suit = Suit.randomSuit();
System.out.println("Random suit selected: " + this.suit);
}
catch(Exception ex)
{
System.out.println(ex.getMessage());
}
}
//alternative constructor that selects rank and suit at random
public Card()
{
this.rank = Rank.randomRank();
this.suit = Suit.randomSuit();
}
/*------------CLASS METHODS------------*/
//returns the difference in value between two cards
public static int differenceValue(Card card1, Card card2)
{
int card1Value = card1.rank.getValue();
int card2Value = card2.rank.getValue();
return Math.abs(card1Value - card2Value);
}
//returns the difference in rank between two cards
public static int difference(Card card1, Card card2)
{
int card1Rank = card1.rank.ordinal();
int card2Rank = card2.rank.ordinal();
return Math.abs(card1Rank - card2Rank);
}
//uses the CompareAscending comparator class to sort in ascending order
public Card[] sortAscending(Card[] inputArray)
{
Comparator comp = new CompareAscending();
Arrays.sort(inputArray, comp);
return inputArray;
}
//uses the CompareDescending comparator class to sort in descending order
public Card[] sortDescending(Card[] inputArray)
{
Comparator comp = new CompareDescending();
Arrays.sort(inputArray, comp);
return inputArray;
}
//uses the CompareSuit comparator class to sort by suit in ascending order
public Card[] sortSuit(Card[] inputArray)
{
Comparator comp = new CompareSuit();
Arrays.sort(inputArray, comp);
return inputArray;
}
private static void selectTest(Card inputCard)
{
//initialising comparators
Comparator<Card> compSuit = new CompareSuit();
Comparator<Card> compAscending = new CompareAscending();
//initialising and populating list of random cards
ArrayList<Card> cardList = new ArrayList<Card>();
for(int i = 0; i < 4; i++)
{
cardList.add(new Card());
System.out.println("Randomly generated card #" + i+1 + ": " + cardList.get(i));
}
//iterating through cardList ArrayList
for(int i = 0; i < cardList.size(); i++)
{
//initialising lambda expressions
Comparator<Card> compRankLambda = (Card card1, Card card2)->card1.getRank().compareTo(card2.getRank());
Comparator<Card> compSuitLambda = (Card card1, Card card2)->-(card1.getSuit().compareTo(card2.getSuit()));
//applying the compare method of each Comparator & the first lambda
int suitResult = compSuit.compare(inputCard, cardList.get(i));
int ascResult = compAscending.compare(inputCard, cardList.get(i));
int lambdaResult = compRankLambda.compare(inputCard, cardList.get(i));
//if the ranks are the same, apply the lambda that compares by suit instead
if(lambdaResult == 0)
{
lambdaResult = compSuitLambda.compare(inputCard, cardList.get(i));
}
System.out.println("Comparing " + inputCard.toString() + " and " + cardList.get(i).toString());
System.out.println("CompareSuit comparison result: " + suitResult);
System.out.println("CompareAscending comparison result: " + ascResult);
System.out.println("Lambda comparison result: " + lambdaResult);
}
}
//Demonstrates all functionality of Card class
//Called from the projects main method
public void main()
{
//demonstrating different types of constructors in use
Card card1 = new Card("ACE", "SPADES");
Card card2 = new Card("TWO");
//this should throw an exception and create a random card instead
Card card3 = new Card("foo");
//cards of identical rank test if the sorting methods can sort by suit
Card card4 = new Card("TEN", "CLUBS");
Card card5 = new Card("TEN", "SPADES");
Card card6 = new Card("TEN", "HEARTS");
//default constructor should create a random card
Card card7 = new Card();
//demonstrating selectTest method
selectTest(card1);
//demonstrating difference methods
System.out.println(difference(card1, card2));
System.out.println(differenceValue(card1, card2));
//creating cardArray to be sorted by Comparator methods
Card[] cardArray = {card1, card2, card3, card4, card5, card6, card7};
//sorting in descending order
card1.sortDescending(cardArray);
System.out.println("descending order");
for(int i=0; i < cardArray.length; i++)
{
System.out.println(cardArray[i].toString());
}
//sorting in ascending order
card1.sortAscending(cardArray);
System.out.println("ascending order");
for(int i=0; i < cardArray.length; i++)
{
System.out.println(cardArray[i].toString());
}
//sorting in suit order
card1.sortSuit(cardArray);
System.out.println("suit order");
for(int i=0; i < cardArray.length; i++)
{
System.out.println(cardArray[i].toString());
}
//serializing then deserializing card1 - should print "ACE of SPADES" to console
card1.saveThisToByteCode();
card1.loadFromByteCode();
}
/*--------------ATTRIBUTE ACCESSOR METHODS---------*/
public Rank getRank()
{
return rank;
}
public Suit getSuit()
{
return suit;
}
public int getRankValue()
{
return rank.getValue();
}
//toString method returns the full name of the card as a string
public String toString()
{
return rank.name() + " of " + suit.name();
}
/*---------------SERIALIZATION METHODS------------*/
//saves the Card object the method is called from to byte code using serialization
private void saveThisToByteCode()
{
String filename = toString() + ".ser";
try{
FileOutputStream fos = new FileOutputStream(filename);
ObjectOutputStream out = new ObjectOutputStream(fos);
out.writeObject(this);
out.close();
fos.close();
System.out.println(filename + " has been serialized");
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
//loads in the Card object given by the method argument from byte code into a Card object and returns it
private Card loadFromByteCode()
{
try{
String filename = toString() + ".ser";
FileInputStream fis = new FileInputStream(filename);
ObjectInputStream in = new ObjectInputStream(fis);
Card card = (Card)in.readObject();
in.close();
fis.close();
System.out.println(filename + " has been deserialized");
//evidence that the correct card has been loaded in
System.out.println("Deserialized card: " + card.toString());
return card;
}
catch(Exception ex)
{
ex.printStackTrace();
}
//if the card is not found, a random card is returned instead
return new Card();
}
/*----------OVERRIDDEN METHODS----------*/
//overriding compareTo method to compare to other Card objects
@Override
public int compareTo(Card otherCard)
{
return this.rank.compareTo(otherCard.rank);
}
}