-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathCrazy8Driver.java
More file actions
791 lines (737 loc) · 39.1 KB
/
Crazy8Driver.java
File metadata and controls
791 lines (737 loc) · 39.1 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
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
import java.lang.IndexOutOfBoundsException;
import java.util.regex.Pattern;
public class Crazy8Driver
{
public static final int MAXRM = 3;
public static final int CHEAT = -2;
public static CrazyEightGUI gui;
public static void main(String[] args)
{
/* Here we'll instantiate a cache of of players for the program to choose from later on. There is a better way to declare a bunch of Players
* in bulk, but right now we'll just do it right here before it gets too large.
*/
ArrayList<Player> playerCache = Crazy8Driver.populatePlayerCache();
/* Establish the player list that will be playing the game. This list draws from playerCache, and calls instantiatePlayers() to fill the list.
* Uncommented due to testing and fills the list with Gul'dan and Thrall.
*/
ArrayList<Player> players = new ArrayList<Player>();
players = instantiatePlayers(playerCache);
//players.add(playerCache.get(8)); players.add(playerCache.get(4)); // --- This line is for debugging
// Let's make our new, randomly shuffled deck, using makeDeck().
// Let's also deal cards from this deck into player hands.
Deck deck = new Deck();
ArrayList<ArrayList<Card>> hands = Crazy8Driver.dealCards(deck, players.size(), players);
// The current pile of cards we'll be working with will be in the card stack.
DiscardPile cardStack = new DiscardPile();
Card firstCard = deck.pop();
cardStack.push(firstCard);
//Initiates GUI
gui = new CrazyEightGUI(cardStack.peek(), players);
// Tell the player what's going on, draw a card, and put it into play.
System.out.println("You go first.");
System.out.println("The first card drawn is a(n) " + firstCard + "\n\n");
System.out.println("Enter 'help' for assistance.");
boolean exitGame = false;
while(!exitGame)
{
gui.update(players,cardStack.peek());
for(int i = 0; i < players.size(); i++)
{
if(i == 0)
{
playerTurn(deck, players, cardStack);
}
else
{
players.get(i).behavior.play(deck, players, cardStack);
}
Crazy8Driver.pacedDialogue("", new Player());
gui.update(players,cardStack.peek());
if(players.get(i).hand.size() == 0)
{
System.out.println(players.get(i) + " has emptied their hand!");
System.out.println(players.get(i) + " has won the game!");
i = 4;
exitGame = true;
}
}
Crazy8Driver.pacedDialogue("", new Player());
}
gui.update(players,cardStack.peek());
}
/**
* This class should handle everything that goes on during a player's turn.
* @param deck The deck we might be drawing from.
* @param The list of players (their hands included) we're working with.
* @param cardStack The growing stack of cards.
*/
private static void playerTurn(Deck deck, ArrayList<Player> playerList, DiscardPile cardStack)
{
// So we don't have to repeatedly call playerList.get(0) to refer to the player, let's just make a
// variable that does that for us.
Player player = playerList.get(0);
// The following using the format method of the String class to cleanly print out a spaced out message
// that displays the top of the stack.
System.out.println("\n\n\n\n");
String currentSuit = Character.toUpperCase(cardStack.peek().suit.charAt(0)) + cardStack.peek().suit.substring(1);
String outText = String.format("%-20s %-13s %-20s %-20s\n\n", " ", "Top of stack: ", cardStack.peek(), "Current suit: " + currentSuit + "s");
System.out.println(outText);
System.out.println("Cards left in deck: "+ deck.size);
player.printHand();
// Now we're going to print out the hand size of every player.
// Hand size is formatted similarily to the hand above.
String cardCountText = "";
String isYou = " (You)"; // Print this first, and reset it. Will only display on the first iteration, which is the player.
for (Player current : playerList)
{
String handCount = "Number of Cards: " + current.hand.size();
cardCountText += String.format("%-15s %-10s %-5s", current.name + isYou, handCount, " ");
if((playerList.indexOf(current) + 1) % 2 == 0 && current != player) cardCountText += "\n"; // Print a new line for every two players.
isYou = "";
}
System.out.println(cardCountText);
// The following code handles user input. legalWords operates the exactly as it appears in .initializePlayers()
// We take decision and break decision up into an array in case we need to examine the input in multiple parts or as a whole.
// For example, the user may input "taunt Rexxar," which would mean a taunt directed at Rexxar.
// For input that will play cards, we'll use regex input.
ArrayList<String> legalWords = new ArrayList<String>();
legalWords.add("help"); legalWords.add("rules");
legalWords.add("greeting"); legalWords.add("taunt");
legalWords.add("look"); legalWords.add("draw");
legalWords.add("pass"); legalWords.add("discard");
legalWords.add("ability"); legalWords.add("hand");
// When we need to decide the audience of the player's emotes, it's useful to store the each players' name in a list
// so we can easily verify that an enterd name is a valid player.
ArrayList<String> playerNames = new ArrayList<String>();
for(Player character : playerList) playerNames.add(character.name);
int abilityUses = 0;
Scanner userIn = new Scanner(System.in);
boolean decisionReached = false;
String decision = "";
int cardsDrawn = 0;
String errorText = "Invalid input.\n"; // Print this out everytime the user enters bad input.
// General note when using scanners that take input from System.in:
// If you use scanner.hasNext() when that scaner is taking input from System.in, unless it reads en EOF (Ctrl+D),
// .hasNext() will ALWAYS return true, because the input stream from System hasn't ended.
while(!decisionReached)
{
// responseType is used to determine if the user is sending an emote, and if they are, to make sure
// that the AI responds appropriately.
gui.update(playerList,cardStack.peek());
String responseType = "none";
decision = userIn.next();
if(legalWords.contains(decision))
{
if(decision.equals("help") || decision.equals("rules"))
{
// Call the helpMenu method.
Crazy8Driver.helpMenu();
}
else if(decision.equals("hand"))
{
player.printHand();
}
else if(decision.equals("greeting"))
{
responseType = "greeting";
}
else if(decision.equals("taunt"))
{
responseType = "taunt";
}
else if(decision.equals("look"))
{
// The following using the format method of the String class to cleanly print out a spaced out message
// that displays the top of the stack.
System.out.println("\n\n\n\n");
currentSuit = Character.toUpperCase(cardStack.peek().suit.charAt(0)) + cardStack.peek().suit.substring(1);
outText = String.format("%-20s %-13s %-20s %-20s\n\n", " ", "Top of stack: ", cardStack.peek(), "Current suit: " + currentSuit + "s");
System.out.println(outText);
System.out.println("Cards left in deck: "+ deck.size);
player.printHand();
// Now we're going to print out the hand size of every player.
// Hand size is formatted similarily to the hand above.
cardCountText = "";
isYou = " (You)"; // Print this first, and reset it. Will only display on the first iteration, which is the player.
for (Player current : playerList)
{
String handCount = "Number of Cards: " + current.hand.size();
cardCountText += String.format("%-15s %-10s %-5s", current.name + isYou, handCount, " ");
if((playerList.indexOf(current) + 1) % 2 == 0 && current != player) cardCountText += "\n"; // Print a new line for every two players.
isYou = "";
}
System.out.println(cardCountText);
}
else if(decision.equals("draw"))
{
if(deck.size > 0)
{
Card drawCard = player.draw(deck);
cardsDrawn++;
System.out.println("You drew a " + drawCard);
}
else
{
System.out.println("The deck is empty, no cards drawn.");
}
}
else if(decision.equals("pass"))
{
if(cardsDrawn >= 3 || deck.size == 0)
decisionReached = true;
else
System.out.println("You can't pass until you've drawn at least three cards.");
}
else if(decision.equals("ability"))
{
if(abilityUses < player.ability.uses())
{
player.ability.use(deck, cardStack, playerList);
abilityUses++;
}
if(player.ability.endTurn()) decisionReached = true;
}
else if(decision.equals("discard"))
{
if(!Crazy8Driver.discard(userIn, player, cardStack))
{
System.out.println("No cards were discarded.");
}
else
{
System.out.println("Ending turn.\n");
decisionReached = true;
}
}
}
else
{
System.out.println(errorText);
}
// Every iteration, we check to see if there is a response that should occur from the AI DURING the players' turn
// This response, of course, only takes the form of dialogue.
if(!responseType.equals("none"))
{
// Make sure to determine an audience.
System.out.println("To who?");
decision = userIn.next();
// If it is a legal input.
if(playerNames.contains(decision))
{
Player responder = null;
String audience = decision;
// This loop iterates over the player list and finds the player that the user is sending an emote to.
// responder is set equal to that player so we can easily refer to the player that we are working with.
// Note: We've already establish that the targeted audience IS in the game, so we won't have to worry
// about not finding a matching input. The following if statements check to see if it's not null
// because a compiler error will be thrown otherwise.
for(Player playerAI : playerList)
{
if(playerAI.name.equals(audience) && !audience.equals(player.name))
responder = playerAI;
}
// Now we finally reply with an appropriate message.
if(responseType.equals("greeting") && responder != null)
{
Crazy8Driver.pacedDialogue(player.greetingText, player);
Crazy8Driver.pacedDialogue(responder.greetingText, responder);
}
else if(responseType.equals("taunt") && responder != null)
{
Crazy8Driver.pacedDialogue(player.tauntText, player);
Crazy8Driver.pacedDialogue(responder.tauntText, responder);
}
}
else
{
System.out.println(errorText);
}
}
responseType = "none";
}
}
/**
* @param userin The scanner to read from.
* @param player Our player.
* @param discardPile The growing discard pile.
* @return If a card was discarded or not.
*
* Things to work on for discard:
* Checking the validity of THREE cards in one go.
*/
private static boolean discard(Scanner userin, Player player, DiscardPile discardPile)
{
Scanner line;
boolean discarded = false;
boolean[] valid = {false,false,false}; //Store validity of cards
ArrayList<Integer> rmNum = new ArrayList<>(); //Indexes that will be removed from hand.
int cardsRemoved = 0, j = 0, count = 0, chosenCard = -1;
int maxIndex = player.hand.size();
String currentSuit = "";
Card disCard = new Card(0,"A");
//Needs to be implemented to wait until cards are discarded.
System.out.println("\nEnter the number for each card you would like to discard(max: 3).\nEnter any character to stop.");
//Asks for index input and stores it into an ArrayList.
while(count < MAXRM)
{
if(userin.hasNextInt() && count < MAXRM)
{
chosenCard = userin.nextInt();
//System.out.printf("Chosen index: %d\n", chosenCard);
if(chosenCard > -1 && chosenCard <= player.hand.size()-count)
{
rmNum.add(chosenCard-1);
count++;
}
else
{
System.out.println("That is an invalid card number.");
chosenCard = 0;
}
}
else
{
System.out.println();
break;
}
}
/*
* This section responds to the input indexes and sets the validity of the cards in
* 'valid' array.
* CHEAT = -2, and it auto-plays the first card in your hand.
*/
for(int i = 0; i < rmNum.size(); i++)
{
disCard = (rmNum.get(i) == CHEAT)? player.hand.get(0) : player.hand.get(rmNum.get(i));
if(rmNum.get(i) == CHEAT)
{
System.out.println("You're cheating! Discarding "+player.hand.get(i).toString());
valid[i] = discarded = true;
}
else if(rmNum.get(i) >= player.hand.size() || rmNum.get(i) < 0)
{
System.out.println("\n'" + disCard + "' not a valid card in your hand.");
System.out.println("Will end after 3 cards max have been discarded. \n\n\n");
valid[i] = false;
}
else
{
if(cardsRemoved == 0 && disCard.value == discardPile.EIGHT)
{
disCard.suit = Crazy8Driver.getSuit();
System.out.println("Discarding a "+player.hand.get(rmNum.get(i)).toString());
valid[i] = discarded = true;
cardsRemoved += 1;
}
else if((cardsRemoved == 0 && discardPile.peek().validPlay(disCard)) ||
(cardsRemoved > 0 && valid[i-1] && discardPile.peek().value == disCard.value))
{
System.out.println("Discarding a "+player.hand.get(rmNum.get(i)).toString());
valid[i] = discarded = true;
cardsRemoved += 1;
}
else
{
System.out.println("Cannot play "+player.hand.get(rmNum.get(i)).toString()+" from your hand. Moving on.");
valid[i] = false;
}
}
}
//Now, we remove all of the valid cards from the hand.
for(int i = 0; i < rmNum.size(); i++)
{
int offset = 0;
if(valid[i])
{
if(rmNum.get(i) == CHEAT)
discardPile.push(player.hand.remove(0));
else
{
if(i > 0 && rmNum.get(i-1) < rmNum.get(i)) offset += 1; //Increase offset if removing cards from a lower index.
if(i > 1 && rmNum.get(i-2) < rmNum.get(i)) offset += 1;
//Check to see if there is an eight in the played cards.
discardPile.discard(player.hand.remove((int)rmNum.get(i)-offset));
}
}
}
if(count > 3)
System.out.println("Could not discard the rest of the cards: Max 3 card plays in one turn.");
System.out.println("Discard phase complete.");
userin.nextLine();
return discarded;
}
//discard(...) helper method
public static String getSuit()
{
Scanner input = new Scanner(System.in);
ArrayList<String> suits = new ArrayList<>();
suits.add("diamond");
suits.add("heart");
suits.add("club");
suits.add("spade");
String temp = "";
boolean valid = false;
while(true)
{
System.out.println("What suit would you like to choose? ");
temp = input.nextLine();
if(suits.contains(temp))
return temp;
else
{
valid = false;
input.nextLine();
System.out.println("Invalid input for suit.");
System.out.println("Please use all lowercase letters and no numbers.");
}
}
}
/**
* pacedDialogue is a method we use that enters input and then tells the computer to wait. This makes it so that the player can notice and process
* the dialogue, instead of it all happening at once. Usually, .pacedDialogue() will be followed another call to this method, resembling some
* artificial pause in speech.
* @param dialogue The string to print out.
* @param character The speaker for this line of dialogue.
*/
private static void pacedDialogue(String dialogue, Player character)
{
if(!dialogue.equals("")) System.out.print(character + ": " + dialogue + "\n\n");
try
{
Thread.sleep(1000);
}
catch (Exception e)
{
Thread.currentThread().interrupt();
}
}
/**
* Print out and handle user input for a series of interactive menus that offer rules, context, and assistance to players.
*/
private static void helpMenu()
{
String menuText = String.format("\n\n This is the card game, Crazy 8's. \n Here is a table of possible inputs:\n");
menuText += String.format("%-10s %-20s\n", "rules", "For the rules of Crazy 8.");
menuText += String.format("%-10s %-20s\n", "emotes", "How to use emotes in this game.");
menuText += String.format("%-10s %-20s\n", "[misc]", "View a list of all legal commands.");
menuText += String.format("%-10s %-20s\n", "exit", "To exit this menu.");
menuText += String.format("%-10s %-20s\n", "menu", "Print this menu again.");
System.out.println(menuText);
ArrayList<String> legalWords = new ArrayList<String>();
legalWords.add("rules"); legalWords.add("emotes"); legalWords.add("exit");
Scanner userin = new Scanner(System.in);
String decision = "";
while(!decision.equals("exit"))
{
System.out.println("\n\n\n");
decision = userin.next();
if(decision.equals("rules"))
{
System.out.println("\n\nThe premise of Crazy 8s is to empty your hand before your opponents, the first to do so wins. \n"
+ "* You may only discard a card when it matches either the rank or suit of the card at the top of the pile. \n"
+ "\t To do this, enter: 'discard' followed by the index of the card you would like to discard as its presented to you\n"
+ "\t For example, to discard the 3rd card from your hand, enter: 'discard' followed by '1'.\n"
+ "* You may discard several cards of the same rank, all at once. To do this, follow the input:\n"
+ "\t discard 1 2 3 \t Where cards 1, 2, and 3 are cards of equal value."
+ "\t To exit the discard phase, enter any non-integer input. (For example: 'discard 1 2 a' will work.)\n"
+ "* You may play an 8 at any time. When an 8 is played, you can change the suit that the other plays must match.\n"
+ "* If you have no possible cards to discard, you must draw from the pile. To do this, enter 'draw.'\n"
+ "\t You can draw as many times from the deck as you would like.\n"
+ "\t Once you may have drawn at least 3 cards, you may pass your turn.\n"
+ "\t If the deck has been exhausted, and you have no available cards to play, you may also pass your turn.\n"
+ "* And lastly, every character has an ability which they can use to influence the game. To use your character's ability\n"
+ "\t enter 'ability' to use it. Take note, however, that some abilities will end your turn.\n");
}
else if(decision.equals("emotes"))
{
System.out.println("\nYou may greet or taunt your opponent. To do this, enter either 'greeting' or 'taunt.\n"
+ "You will be prompted who to greet or taunt, simply enter the name of your audience.");
}
else if(decision.equals("[misc]"))
{
System.out.println(String.format("\n%-10s %-30s", "discard", "Discard a number of cards onto the discard pile."));
System.out.println(String.format("%-10s %-30s", "draw", "Draw a card from the deck."));
System.out.println(String.format("%-10s %-30s", "pass", "Pass your turn to the next player."));
System.out.println(String.format("%-10s %-30s", "greeting", "Say a greeting to the AI."));
System.out.println(String.format("%-10s %-30s", "taunt", "Taunt the AI."));
System.out.println(String.format("%-10s %-30s", "players", "List the players in the current game."));
System.out.println(String.format("%-10s %-30s", "ability", "Use your player ability."));
System.out.println(String.format("%-10s %-30s", "look", "Reprint your hand and the state of the game."));
}
else if(decision.equals("menu")) System.out.println(menuText);
}
}
/**
* This class is used to offer the player input to select a character to play as, how many AI opponents they will face,
* and randomly select their AI opponents.
* @param playerCache The cache of players to take a character from.
* @return A list of players for the game.
*/
private static ArrayList<Player> instantiatePlayers(ArrayList<Player> playerCache)
{
// legalWords contains the names of all possible player choices. We will use this later
// to determine legal user input when selecting a character.
ArrayList<String> legalWords = new ArrayList<String>();
System.out.println("To begin, please select a character to play as.");
// menuText should be use as an easy way to print all possible choices to the player without
// the need for a for loop to print them all out manually.
String menuText = "\n\n";
// Print out all the possible characters using a simple for : each loop.
for(Player player : playerCache)
{
menuText += ((playerCache.indexOf(player) + 1) + ") " + player + "\n");
legalWords.add(player.name);
}
Scanner playerChoice = new Scanner(System.in);
int choiceID = 0; // Store the integer ID choice or
String choiceName = ""; // a String if an int is not the input.
Player playerOfChoice = null; // Store possible and the final characters in this variable. If it's not null by the end of the loop, the loop will exit.
boolean kill = false;
boolean kill2 = false;
while(!kill)
{
kill2 = false; // Make sure to reset kill2 every loop cycle.
System.out.println(menuText);
// The player can either select a character by their name or by the number they're associated with in menuText.
// Regardless, take their input and determine the player's intention--if they mean to select by ID or name. If
// by ID, this if statement handles, else handle it by name.
if(playerChoice.hasNextInt())
{
choiceID = playerChoice.nextInt() - 1;
// If we get an IndexOutOfBoundsException, the player entered illegal input, so we disregard it in the catch.
try
{
// We use playerOfChoice to handle even on final inputs so we can reuse variables, and so we can also
// give the player a moment to consider if they really want to play as the character they just selected.
playerOfChoice = playerCache.get(choiceID);
while(!kill2)
{
System.out.println("\n " + playerOfChoice);
System.out.println("Ability: " + playerOfChoice.ability.name());
System.out.println("\n" + playerOfChoice.ability + "\n");
System.out.println("Enter 'yes' to select this character, enter 'no' to go back to selection.\n");
choiceName = playerChoice.next();
if(choiceName.equals("yes")) kill2 = true;
else if(choiceName.equals("no"))
{
kill2 = true;
playerOfChoice = null;
}
}
}
catch(IndexOutOfBoundsException e)
{
System.out.println("Invalid character ID.");
}
}
else if(playerChoice.hasNext())
{
// Similar to the above if statement, but we're instead selecting by name. A simple .indexOf() method determines the
// character we want to work with.
choiceName = playerChoice.next();
if(legalWords.contains(choiceName))
{
int charIndex = legalWords.indexOf(choiceName);
playerOfChoice = playerCache.get(charIndex);
while(!kill2)
{
System.out.println("\n " + playerOfChoice);
System.out.println("Flavor text will go here.");
System.out.println("Maybe some other stuff too?");
System.out.println("Enter 'yes' to select this character, enter 'no' to go back to selection.\n");
choiceName = playerChoice.next();
if(choiceName.equals("yes")) kill2 = true;
else if(choiceName.equals("no"))
{
kill2 = true;
playerOfChoice = null;
}
}
}
}
if(playerOfChoice != null) kill = true;
}
System.out.println("\nSelected " + playerOfChoice); // Assure the player who they'll be playing as.
// Now let's instantiate the player list, since we'll now be working with it. Add our player charact to the list (whose index will ALWAYS be 0 in the list)
// and declare our numPlayers variable.
ArrayList<Player> players = new ArrayList<Player>();
players.add(playerOfChoice);
int numPlayers = 0;
// Do they enter a number between 1 and 3? Accept it and exit the loop, if not, wait until they do.
System.out.println("\n How many other players would you like to face?");
System.out.println("1 Other player.");
System.out.println("2 Other players.");
System.out.println("3 Other players.");
kill = false;
while(!kill)
{
if(playerChoice.hasNextInt())
{
choiceID = playerChoice.nextInt();
if(choiceID >= 1 && choiceID <= 3)
{
numPlayers = 1 + choiceID;
kill = true;
}
}
}
System.out.println("You'll play a " + numPlayers + " player game."); // Assure the player of how many opponents they will face.
String versusText = "\n" + players.get(0); // Let's build this String, which informs the player of their opponents, now.
for(int i = 0; i < numPlayers - 1;)
{
// Randomly select from the player cache an opponent. If the opponent has already been seleected (before in this loop or by the playeR)
// reroll for a new character. This ensures that there will be no repeats in our player list.
Random ran = new Random();
int ranNum = ran.nextInt(playerCache.size());
if(!players.contains(playerCache.get(ranNum)))
{
players.add(playerCache.get(ranNum));
versusText += " vs. " + players.get(i + 1);
i++;
}
}
Crazy8Driver.pacedDialogue(versusText, new Player());
return players;
}
/**
* @param deck A collection of cards to randomly deal cards from.
* @param players The number of players to deal a hand to.
* @param playerList The list of players to deal cards to.
* @return A collection of hands filled with 8 cards from the deck.
*
* @precondition That the deck passed into is greater than the number of players times eight.
* @postcondition That the deck passed into has decreased in size by a multiple of eight.
*/
private static ArrayList<ArrayList<Card>> dealCards(LStack<Card> deck, int players, ArrayList<Player> playerList)
{
// Instantiate a list of dealt hands. This list isn't as important as giving these actual hands to player characters
// but we might need the list of hands for some reason.
// Note: A hand's index within hands is shared by a player character in the players list. We can use this to go directly
// from a certain hand directly to that player.
ArrayList<ArrayList<Card>> hands = new ArrayList<ArrayList<Card>>();
for(int i = 0; i < players; i++) hands.add(new ArrayList<Card>()); // Make a new, empty list of cards for each player.
for(int i = 0; i < 8; i++)
{
// Now we fill those hands from the top of the deck, which should already be randomized in makeDeck().
// Because at most we'll be drawing 32 cards here, we don't need to worry about popping from an empty stack.
for(ArrayList<Card> hand : hands)
{
hand.add(deck.pop());
}
}
// And lastly, give every player a dealt hand.
for(int i = 0; i < players; i++) playerList.get(i).hand = hands.get(i);
return hands;
}
/**
* @return A new, randomly filled deck of the four suits, 1 through Ace.
*/
private static LStack<Card> makeDeck()
{
// First we need to establish the cards we are using. It's easier to just load the cards
// into suits, and then randomly pick from within the suits when we're filling the deck.
// Here, we're just declaring lists of Cards, and filling them sequentially with 14 cards.
LStack<Card> deck = new LStack<Card>();
ArrayList<Card> diamonds = new ArrayList<Card>();
ArrayList<Card> hearts = new ArrayList<Card>();
ArrayList<Card> clubs = new ArrayList<Card>();
ArrayList<Card> spades = new ArrayList<Card>();
for(int i = 2; i <= 14; i++) diamonds.add(new Card(i, "diamond"));
for(int i = 2; i <= 14; i++) hearts.add(new Card(i, "heart"));
for(int i = 2; i <= 14; i++) clubs.add(new Card(i, "club"));
for(int i = 2; i <= 14; i++) spades.add(new Card(i, "spade"));
// Now we need to randomly select from the above suits and add each one to the deck
// removing from their suit's list. We do this until all suits are empty.
boolean suitsUsed = false; // If all suits are used up, exit the loop.
Random ran = new Random();
int ranNum = 0; // This determines the random index from the suit list we'll take from.
int ranSuit = 0; // This determines the random suit we'll select.
// We'll store the suits that are currently empty, so we have a nice collection of empty suits
// as they are used up.
ArrayList<Integer> emptySuits = new ArrayList<Integer>();
while(!suitsUsed)
{
// Here, we declare which suit we'll be working with -- however, what if we recieve a
// random integer for a matching suit that is EMPTY? The following while loop examines
// what we get, and makes sure we only progress until we know we'll be working with a suit
// that is not empty.
ranSuit = ran.nextInt(4);
while(emptySuits.contains(ranSuit)) ranSuit = ran.nextInt(4);
// Here, suit will be pointing to one of the non-empty declared suits above. This way,
// we don't need to hardcode for each suit, but we can just refer to the suit we're
// working with as "suit."
ArrayList<Card> suit = new ArrayList<Card>();
switch(ranSuit)
{
case 0:
suit = diamonds;
break;
case 1:
suit = hearts;
break;
case 2:
suit = clubs;
break;
case 3:
suit = spades;
break;
}
// Currently, if we randomly select an empty suit that hasn't been added to emptySuits,
// this is where we'd add that suit to emptySuits.
//
// The first else condition is the portion of the method that actually adds a randomly
// selected card, and pushes that card into LStack deck. Once we do that, we're then sure
// to remove that card from its suit.
//
// The final else statement flips the kill condition "suitsUsed" once every suit is emptied.
if(suit.size() == 0) emptySuits.add(ranSuit);
else if(suit.size() != 0)
{
// We declare ranNum to be a number from 0 to the size of the current suit we're working with.
// This size decreases overtime as we remove cards from that particular suit, so in this way,
// we can randomly select a card from that decreasing list.
ranNum = ran.nextInt(suit.size());
deck.push(suit.get(ranNum));
suit.remove(ranNum);
}
if(diamonds.size() == 0 && hearts.size() == 0 && clubs.size() == 0 && spades.size() == 0)
suitsUsed = true;
}
return deck;
}
private static ArrayList<Player> populatePlayerCache()
{
ArrayList<Player> playerCache = new ArrayList<Player>();
playerCache.add(new Player("Anduin", "By the light!", "Greetings.", "The Light shall burn you!"));
playerCache.add(new Player("Gul'dan", "Suffer!", "I greet you.", "Your soul shall suffer!"));
playerCache.add(new Player("Valeera", "Watch. Your. Back.", "The pleasure is mine.", "I will be your death!"));
playerCache.add(new Player("Uther", "I will fight with honor!", "Well met!", "Justice demands retribution!"));
playerCache.add(new Player("Jaina", "You asked for it!", "Hello.", "My magic will tear you apart!"));
playerCache.add(new Player("Malfurion", "I must protect the wilds!", "My greetings.", "Nature will rise against you!"));
playerCache.add(new Player("Rexxar", "Let the hunt begin!", "Greetings, traveller.", "I wll hunt you down!"));
playerCache.add(new Player("Garrosh", "Victory or death!", "Heh, greetings.", "I will crush you!"));
playerCache.add(new Player("Thrall", "Elements guide me!", "Greetings, friend.", "The elements will destroy you!"));
playerCache.get(8).behavior = new AggressiveFabricate(playerCache.get(8));
playerCache.get(8).ability = new FabricateAbility(playerCache.get(8));
playerCache.get(7).behavior = new AggressiveCycle(playerCache.get(7));
playerCache.get(7).ability = new CycleAbility(playerCache.get(7));
playerCache.get(6).behavior = new AggressiveFabricate(playerCache.get(6));
playerCache.get(6).ability = new RefreshAbility(playerCache.get(6));
playerCache.get(5).behavior = new AggressiveCycle(playerCache.get(5));
playerCache.get(5).ability = new CycleAbility(playerCache.get(5));
playerCache.get(4).behavior = new AggressiveFabricate(playerCache.get(4));
playerCache.get(4).ability = new FabricateAbility(playerCache.get(4));
playerCache.get(3).behavior = new AggressiveFabricate(playerCache.get(3));
playerCache.get(3).ability = new RefreshAbility(playerCache.get(3));
playerCache.get(2).behavior = new AggressiveFabricate(playerCache.get(2));
playerCache.get(2).ability = new FabricateAbility(playerCache.get(2));
playerCache.get(1).behavior = new AggressiveCycle(playerCache.get(1));
playerCache.get(1).ability = new CycleAbility(playerCache.get(1));
playerCache.get(0).behavior = new AggressiveFabricate(playerCache.get(0));
playerCache.get(0).ability = new RefreshAbility(playerCache.get(0));
return playerCache;
}
}