Computer Science - Section D

Fix "IndexOutOfRange" exception caused by inputting a card number not in the range 1 to 5.
Click the card to flip 👆
1 / 25
Terms in this set (25)
// Changes to DifficultyCard process method
if (parsed) {
if (choiceAsInteger >= 1 && choiceAsInteger < 5) {
if (hand.getCardDescriptionAt(choiceAsInteger - 1).charAt(0) == 'K') {
Card cardToMove = hand.removeCard(hand.getCardNumberAt(choiceAsInteger - 1));
discard.addCard(cardToMove);
return;
} else {
Console.writeLine("Card selected is not a key, discarding 5 cards from the deck.");
}
} else {
Console.writeLine("Invalid card position, discarding 5 cards from the deck.");
}
}
// Changes made to Breakthrough getCardFromDeck method
Console.write("To deal with this you need to either lose a key ");
Console.write("(enter 1-4 to specify position of key) or (D)iscard five cards from the deck:> ");
String choice = Console.readLine();
Create a new card child class for a Retrieve card. If a player draws a retrieve card they are able to retrieve one card from the discard pile and return it to their hand. There should be two retrieve cards in the deck. These should be added, like the difficulty cards, after the user draws their hand.
CREATE A NEW CLASS CALLED RETRIEVECARD ...

class RetrieveCard extends Card {
protected String cardType;
public RetrieveCard() {
super();
cardType = "Ret";
}
public RetrieveCard(int cardNo) {
cardType = "Ret";
cardNumber = cardNo;
}
@Override
public String getDescription() {
return cardType;
}
@Override
public void retrieve(CardCollection hand, CardCollection discard) {
Console.writeLine(discard.getCardDisplay());
int choiceAsInt = 0;
do {
Console.writeLine("Choose a card to return to your hand:> ");
String choice = Console.readLine();
try {
choiceAsInt = Integer.parseInt(choice);
} catch (Exception e) {
Console.writeLine("Invalid card position");
Console.writeLine();
}
} while (!(choiceAsInt > 0 && choiceAsInt <= discard.getNumberOfCards()));
hand.addCard(discard.removeCard(discard.getCardNumberAt(choiceAsInt - 1)));
}
}


IN THE BREAKOUT CLASS ADD THIS

addRetrieveCardsToDeck() {
for (int i = 0; i < 2; i++) {
deck.addCard(new RetrieveCard());
}
}



IN THE GETCARDFROMDECK METHOD:

} else if (deck.getCardDescriptionAt(0).equals("Ret")) {
Card currentCard = deck.removeCard(deck.getCardNumberAt(0));
Console.writeLine("Retrieve card found!");
currentCard.retrieve(hand, discard);
}

IN THE SETUP GAME METHOD:

addDifficultyCardsToDeck();
addRetrieveCardsToDeck();
deck.shuffle();
ADDINGV TGO PLAYGAME CLASS

case "S": {
Console.writeLine("Please input the filename");
String filename = Console.readLine();
saveGame(filename);
break;
}

ADD TO GET CHOICE THE OPTION TO SAVE ON TO THE END OF DISCARD AND USE:

private String getChoice() {
Console.writeLine();
Console.write("(D)iscard inspect, (U)se card, (S)ave Game:> ");
String choice = Console.readLine().toUpperCase();
return choice;
}

CREATE NEW CLASS SAVEGAME TO SAVE:

private boolean saveGame(String fileName) {
try {
BufferedWriter myStream = new BufferedWriter(new FileWriter(fileName));
myStream.append(score + "\n");
int i = 0;
int j = 0;
for (Challenge c : currentLock.getChallenges()) {
if (i > 0 && i < currentLock.getChallenges().size()) {
myStream.append(";");
}
for (String condition : c.getCondition()) {
if (c.getCondition().size() - 1 == j) {
myStream.append(condition);
} else {
myStream.append(condition + ",");
}
j++;
}
j = 0;
i++;
}
myStream.append("\n");
i = 0;
for (Challenge c : currentLock.getChallenges()) {
if (c.getMet()) {
if (currentLock.getChallenges().size() - 1 == i) {
myStream.append("Y");
} else {
myStream.append("Y;");
}
} else {
if (currentLock.getChallenges().size() - 1 == i) {
myStream.append("N");
} else {
myStream.append("N;");
}
}
i++;
}
myStream.append("\n");
i = 0;
for (Card c : hand.getCards()) {
if (hand.getCards().size() - 1 == i) {
myStream.append(c.getDescription() + " " + c.getCardNumber());
} else {
myStream.append(c.getDescription() + " " + c.getCardNumber() + ",");
}
i++;
}
i = 0;
myStream.append("\n");
for (Card c : sequence.getCards()) {
if (sequence.getCards().size() - 1 == i) {
myStream.append(c.getDescription() + " " + c.getCardNumber());
} else {
myStream.append(c.getDescription() + " " + c.getCardNumber() + ",");
}
i++;
}
i = 0;
myStream.append("\n");
for (Card c : discard.getCards()) {
if (discard.getCards().size() - 1 == i) {
myStream.append(c.getDescription() + " " + c.getCardNumber());
} else {
myStream.append(c.getDescription() + " " + c.getCardNumber() + ",");
}
i++;
}
i = 0;
myStream.append("\n");
for (Card c : deck.getCards()) {
if (deck.getCards().size() - 1 == i) {
myStream.append(c.getDescription() + " " + c.getCardNumber());
} else {
myStream.append(c.getDescription() + " " + c.getCardNumber() + ",");
}
i++;
}
myStream.close();
return true;
} catch (Exception e) {
Console.writeLine("File not loaded");
return false;
}
}


ADD A METHOD TO CARDCOLLECTION:

public List<Card> getCards()
{
return cards;
}

ADD A METHOD TO LOCK:
public List<Challenge> getChallenges()
{
return challenges;
}
Currently no error message is displayed if the user attempts to play two consecutive cards of the same tool type. Change the code to notify the user when their card has been disallowed due to this rule. In addition, leverage a score penalty of 1 point (reduce the user's score by one) and notify the user that this has occurred in all cases except where the user's score would then become negative in which case it should be omitted.
When a lock is completed a new lock is selected from the list of locks at random. However, it could select a lock that has already been solved by the player. Adjust the method GetRandomLock() in the breakthrough class to fix this.ADD TO GET RANDOM LOCK|: ADD BENEATH DO: } while (!newLock.getLockSolved()); return newLock; }Introduce a (P)eek option. This can be used once per lock, and allows a player to peek into the deck to see the next three upcoming cards. There should be a new command in playGame that only appears if the 'deck peek' is still available. Create a new attribute in the Lock class called peekUsed. Create accessor methods to the Lock class to update and read the peekUsed attribute (get/set). Update the getChoice() method in the Breakthrough class to give the user the option to '(P)eek'. This menu option should only appear if the peekUsed attribute is false. Introduce an option to the menu in the playGame() method to accept 'P' as one of the menu choices. This menu option should only appear if the peekUsed attribute is false. Display the next three cards in the deck using the getCardDescriptionAt() method. Set the peekUsed attribute appropriately once the peek option has been chosen by the user. When the player is given a new lock, set the peekUsed attribute appropriately to allow the user to use the peek option again.ADD TO GETCHOICE ADD IF UNDER THE CONSOLE WRITE LINE: if (currentLock.getPeekUsed()) { THEN ADD ELSE BELOW THE CONSOLE WRITE LINE } else { Console.write("(D)iscard inspect, (U)se card, (P)eek:> "); } ADD TO PLAY GAME: ADD CASE P: case "P": if (!currentLock.getPeekUsed()) { Console.writeLine("The next three cards are: " + deck.getCardDescriptionAt(0) + ", " + deck.getCardDescriptionAt(1) + ", " + deck.getCardDescriptionAt(2)); currentLock.setPeekUsed(); } ADD TO LOCK CLASS: UNDER THE ARRAYLIST: private boolean peekUsed = false; public boolean getPeekUsed() { return peekUsed; } public void setPeekUsed() { peekUsed = true; }This question refers to the playCardToSequence method of the Breakthrough class. Under the rules of the game, a player cannot play two cards of the same type sequentially. Currently there is no error message warning the player when they attempt to do this, however. Modify the playCardToSequence method in the Breakthrough class to introduce an error message which tells the user that they cannot play two cards of the same type sequentially. Use the getCardDescriptionAt method to highlight to the user which card they have just tried to play and explain that it is the same as the type just played. Test the changes you have made: Run the game and show at least one turn played where the error does not get shown and one where it shows the new error message under the correct conditions of playing a duplicate tool. Make sure to show that (1) the error message is displayed and (2) the card is not played or discarded.ADD TO PLAYCARDTOSEQUENCE: BELOW SECOND IF ADD AN ELSE STATEMENT: } else { Console.writeLine("Error: The card you are trying to play(" + hand.getCardDescriptionAt (cardChoice -1) + ") is the same type as the last card in the sequence."); }Each player gets 1 'mulligan' per game where they can take all the cards in their hand, the deck, the discard pile and the sequence, put them together and shuffle up and deal again. Any difficulty cards drawn (when repopulating the player's hand) should be sent to the discard pile. The player's score and the current lock including any solved challenges will remain unchanged. Create a new attribute in the Breakthrough class called mulliganUsed which is initialised to false. If the mulliganUsed is false then display an additional (M)ulligan option each turn for the player and once the mulligan has been used, set the mulliganUsed attribute to true, which should mean that the (M)ulligan option is no longer displayed or usable. Test the changes you have made: Run the game, solve one challenge, use mulligan, play one card to the sequence, choose M (in an attempt to mulligan again despite no menu option).MAKE CHANGES TO GET CHOICE: UNDER CONSOLE.WRITELINE: if (mulliganUsed) { Console.write("(D)iscard inspect, (U)se card:> "); } else { Console.write("(D)iscard inspect, (U)se card, (M)ulligan:> "); } ADD TO THE BREAKTHROUGH CLASS: private boolean mulliganUsed = false; ADD TO PLAY GAME: ADD NEW CASE M: case "M": if (!mulliganUsed) { int loopCount; //move cards from sequence to deck loopCount = sequence.getNumberOfCards(); for (int count=0; count<loopCount;count++) { moveCard(sequence,deck,sequence.getCardNumberAt(0)); } //move cards from discard pile to deck loopCount = discard.getNumberOfCards(); for (int count=0; count<loopCount;count++) { moveCard(discard,deck,discard.getCardNumberAt(0)); } //move cards from hand to deck loopCount = hand.getNumberOfCards(); for (int count=0; count<loopCount;count++) { moveCard(hand,deck,hand.getCardNumberAt(0)); } //shuffle up and deal deck.shuffle(); for (int count=0; count<5;count++) { while (deck.getCardDescriptionAt(0)=="Dif") { moveCard(deck,discard,deck.getCardNumberAt(0)); } moveCard(deck,hand,deck.getCardNumberAt(0)); } mulliganUsed = true; } break;This question refers to the playGame and getChoice methods of the Breakthrough class. The player will have a new option in playGame to (Q)uit, and for this they will get 1 point added to their score for each card remaining in the deck. Print out their final score as they quit. Note that the code should exit cleanly/nicely without using any System.exit() type functions (although break/continue are allowed of course). Test the changes you have made: Play one turn of a game, choose quit.ADD TO GET CHOICE: UNDER CONSOLE: Console.write("(D)iscard inspect, (U)se card, (Q)uit:> "); ADD TO PLAY GAME: ADD FIRST LINE IN PLAY GAME... boolean hasQuit = false; ADD A WHILE INSIDE THE WHILE LOOP UNDER LOCKSOLVED FALSE while (!lockSolved && !gameOver && !hasQuit) { ADD A CASE Q IN THE MENU CHOICE: case "Q": hasQuit=true; break; ADD AN IF UNDERNEATH THE LOCK SOLVED MOVIN GTHE CURRENT IF THERE INTO THE ELSE: if (hasQuit) { gameOver = true; score += deck.getNumberOfCards(); Console.writeLine("Final score: " + score); } else { gameOver = checkIfPlayerHasLost(); }This question refers to the getCardFromDeck method of the Breakthrough class and the creation of a new method, displayStats, modifying two existing methods, addCard and removeCard, as well as adding three new attributes, numPicks, numFiles and numKeys, in the CardCollection class. Introduce a stats / card count to the CardCollection class which keeps track of which cards have come out of the deck and calculates the % chance that the next card tile in the deck is X type (or XYZ types). Introduce three new attributes to the CardCollection class called numPicks, numFiles and numKeys, which will be updated every time a ToolCard is added to or removed from the CardCollection. Create a new method in the CardCollection class called displayStats. This method should calculate the percentage chance of the next card being a key, pick or file based on the number of each card and the number of cards left in the deck. When the player receives a difficulty card, use the displayStats method together with the getNumberOfCards method in the CardCollection class to display the following on the screen before they choose 'lose a key or discard 5 cards from the deck'. There is a X% chance that the next card will be a key, a Y% chance that it will be a file and a Z% chance that it will be a pick. The percentages should be displayed to two decimal places. Replace X, Y and Z with the appropriate values. Note that they will not normally add up to 100% because there are also difficulty cards in the deck. Run the game until a difficulty card is drawn and show the printout of the statistics in the correct place (after the hand and before asking which card).ADD TO CARDCOLLECTION UNDER STRING NAME: private int numPicks = 0; private int numFiles = 0; private int numKeys = 0; IN ADDCARD ADD SWITCH FOR EACH TOOL: switch (c.getDescription().charAt(0)) { case 'F': numFiles++; break; case 'P': numPicks++; break; case 'K': numKeys++; break; } IN REMOVE CARD ADD SWITCH FOR EACH TOOL: switch (cardToGet.getDescription().charAt(0)) { case 'F': numFiles--; break; case 'P': numPicks--; break; case 'K': numKeys--; break; } CREATE DISPLAY STATS METHOD: public void displayStats() { float keyChance, pickChance, fileChance; keyChance = (float)numKeys/getNumberOfCards() * 100; fileChance = (float)numFiles/getNumberOfCards() * 100; pickChance = (float)numPicks/getNumberOfCards() * 100; Console.writeLine("There is a " + String.format("%.2f",keyChance) + "% chance that the next card will be a key, a " + String.format("%.2f",fileChance) + "% chance that it will be a file and a " + String.format("%.2f",pickChance) + "% chance that it will be a file."); } ADD TO GETCARDFROMDECK: deck.displayStats();This question involves the createStandardDeck, processLockSolved and playCardToSequence methods of the Breakthrough class, as well as the creation of a new setCardToolkit method in the Card, ToolCard and CardCollection classes. Introduce three new 'multi-tool' cards - a multi-pick (P m), a multi-key (K m) and a multi-file (F m). At the start of a standard game (not when loading a save game file), the deck should contain one of each of these new types of card. Multi-tool cards can be dealt to the player's hand in the same way as normal cards are. On playing a multi-tool card, the player should be given the option to choose which toolkit they want to assign the card to before it is added to the sequence, therefore allowing a multi-tool card to be applied to any lock challenge of that type. When a lock has been solved, three new multi-tool cards (one of each type) are added to the deck to be available for the next lock and the deck is reshuffled (as normal). Test the changes you have made: Play the game and show the use of at least one multi-tool card, the print screen must show the hand and sequence both before and after the multi-tool is played.ADD TO CREATE STANDARD DECK: ADD ONE OF EACH OF THESE AT THE TOP OF THE METHOD: newCard = new ToolCard("P", "m"); deck.addCard(newCard); newCard = new ToolCard("K", "m"); deck.addCard(newCard); newCard = new ToolCard("F", "m"); deck.addCard(newCard); } ADD TO PROCESS LOCKSOLVED: UNDER THE WHILE LOOP: Card newCard; newCard = new ToolCard("P", "m"); deck.addCard(newCard); newCard = new ToolCard("K", "m"); deck.addCard(newCard); newCard = new ToolCard("F", "m"); deck.addCard(newCard); ADD TO PLAY CARD TO SEQUENCE: if (hand.getCardDescriptionAt(cardChoice-1).charAt(2) == 'm') { String toolKit; Console.writeLine(); Console.write("Which toolkit would you like to choose? "); toolKit = Console.readLine(); hand.setCardToolkit(cardChoice-1,toolKit); } CREATE SETCARDTOOLKIT IN CARD COLLECTION public void setCardToolkit(int position, String toolKit) { if (cards.get(position).getDescription().charAt(2) == 'm') { cards.get(position).setCardToolkit(toolKit); } } CREATE SET CARD TOOL KIT IN TOOL CARD: @Override public void setCardToolkit(String toolKit) { kit = toolKit; } CREATE SET CARD TOOLKIT IN CARD public void setCardToolkit(String toolKit) { }This question refers to the getLockDetails method of the Lock class and playGame method of the Breakthrough class. Challenges are to be marked as 'partially met' (rather than just 'met' or 'not met') if they are partially solved. A challenge is partially met if the end of the sequence (last one or two cards) matches the start of an unsolved challenge. Modify the call to getLockDetails from playGame to pass in the sequence. Modify getLockDetails so that if the challenge is not met then it checks to see whether it is partially met. For challenges of three cards, only check the last two cards and it becomes partially met if the last card of the sequence matches the first card of the challenge or the second last card of the sequence matches the first card of the challenge and the last card of the sequence matches the second card of the challenge. In general, check N-1 cards where N is the number of cards in the challenge - meaning of course that challenges of one card cannot be partially met. You only need to solve the problem for challenges of three cards exactly. Test the changes you have made: Run the game and play one card to the sequence that doesn't match any of the challenges, then play one towards one of the three card challenges that matches the first card for that challenge, and print screen showing this entire turn. Then play a second card to the sequence that matches the second card of the three card challenge.ADD TO GET LOCK DETAILS ADDING CardCollection Sequence INTO ITS PARAMETERS public String getLockDetails(CardCollection sequence) { CHANGE ALL OF THE ELSE STATEMENT WITHIN THE CODE: List<String> condition = c.getCondition(); int sequenceLength = sequence.getNumberOfCards() - 1; switch (condition.size()) { case 3: if (sequenceLength > 0 && condition.get(1).equals(sequence.getCardDescriptionAt (sequenceLength)) && condition.get(0).equals (sequence.getCardDescriptionAt(sequenceLength - 1))) { lockDetails += "Partially Met: "; } else if (sequenceLength >= 0 && condition.get(0).equals (sequence.getCardDescriptionAt(sequenceLength))) { lockDetails += "Partially Met: "; } else { lockDetails += "Not met: "; } break; case 2: if (sequenceLength >= 0 && condition.get(0).equals (sequence.getCardDescriptionAt(sequenceLength))) { lockDetails += "Partially Met: "; } else { lockDetails += "Not met: "; } break; default: lockDetails += "Not met: "; break; } //end change } lockDetails += convertConditionToString(c.getCondition()) + System.lineSeparator(); ADD TO PLAY GAME Console.writeLine(currentLock.getLockDetails(sequence));This question refers to the playGame method of the Breakthrough class. Introduce a bonus for solving locks using fewer cards. Once the first card is played towards the sequence for a new lock, a counter starts and one is added every time a player makes a move (discarding or playing to the sequence). Once a lock is solved (all the challenges), a player receives an extra point for every point under 20 on the counter, after which it is reset. The player simply receives 0 if the counter is 20 or more. Print out a message confirming the bonus points that were awarded (including 0 if that's the case). Test the changes you have made: Run the game and play two locks, one solved in under 20 cards to show a bonus score and one solved in over 20 cards to show a bonus score of 0.ADD TO PLAY GAME: IN FIRST WHILE LOOP ADD: int bonusCounter = 0; IN CASE U ADD A BONUS COUNTER bonusCounter += 1; IN THE IF CURRENT LOCK SOLVED int bonus = Math.max(0,20-bonusCounter); score += bonus; Console.writeLine("This lock awarded you " + bonus + " bonus points."); bonusCounter = 0;This question refers to the processLockSolved, setupGame and getCardFromDeck methods as well as the creation of a new method, addGeniusCardToDeck of the Breakthrough class and the creation of a new class called GeniusCard. Introduce a new 'Genius Card' which is added to deck at the start of a lock. There should be a 25% chance of having a 'Genius Card' in a deck. A player can choose to use the 'Genius Card' when they draw it to solve a challenge instantly (it should ask which challenge) or it will be discarded and then reshuffled into the deck as normal with all the cards from the discard pile. Note that if a GeniusCard is drawn when filling up the hand it should be discarded automatically and a message should be printed to this effect. Create a method called addGeniusCardToDeck which has a 25% chance of adding one GeniusCard to the deck. This should be called from processLockSolved and setupGame. Create a new class for the GeniusCard which inherits Card with cardType equal to 'Gen' and modify the getCardFromDeck method of Breakthough to ensure that the card is processed correctly when drawn. Test the changes you have made: Run the game and play until a 'Genius Card' is drawn, then choose yes and select the last unsolved challenge in the current lock.CREATION OF ADD GENIUS CARD TO DECK: private void addGeniusCardToDeck() { deck.addCard(new GeniusCard()); } Creation of GeniusCard: class GeniusCard extends Card { protected String cardType; public GeniusCard() { super(); cardType = "Gen"; } public GeniusCard(int cardNo) { cardType = "Gen"; cardNumber = cardNo; } @Override public String getDescription() { return cardType; } } ADD TO SET UP GAME: if (rNoGen.nextInt(4) == 1) { addGeniusCardToDeck(); } ADD TO PROCESSLOCKSOLVED: UNDER THE WHILE LOOP: if (rNoGen.nextInt(4) == 1) { addGeniusCardToDeck(); } ADD TO GET CARD FROM DECK: } else if (deck.getCardDescriptionAt(0).equals("Gen")) { Card currentCard = deck.removeCard(deck.getCardNumberAt(0)); Console.writeLine(); Console.writeLine("Genius card encountered!"); Console.writeLine(hand.getCardDisplay()); Console.write("You can either use this card immediately to solve a challenge or discard it."); Console.write("Enter 1-"+currentLock.getNumberOfChallenges()+" to solve a challenge or (D)iscard it so it can come up after reshuffling:> "); String choice = Console.readLine().toUpperCase(); Console.writeLine(); if (choice.equals("D")) { discard.addCard(currentCard); } else { currentLock.setChallengeMet(Integer.parseInt(choice)-1,true); } ADD ELSE IF BETWEEN IF AND ELSE: } else if (deck.getCardDescriptionAt(0).equals("Gen")) { moveCard(deck, discard, deck.getCardNumberAt(0)); Console.writeLine("A genius card was discarded from the deck when refilling the hand.");This question refers to the addition of a new attribute in the Breakthrough class called credits and to the getCardFromDeck method of the Breakthrough class as well as the creation of a new method, printToolsAvailable, for the CardCollection class. Introduce the concept of 'Buying a tool' from the deck. Add a new attribute, credits, to the Breakthrough class which contains the number of credits the player currently has. At the start of the game, the player has 10 credits. When a player has played a card to the sequence or discarded a card, if they have at least 2 credits remaining, they should be asked if they would like to buy a tool (y/n) before their hand is refilled from the deck. If they choose 'n' then they simply draw a card as normal, but otherwise the new card will be the tool card that they purchased. Players can 'buy' a 'Key' card at the cost of 3 credits, and 'file' or 'pick' cards at the cost of 2 credits each. When the player chooses 'y' to buy a tool, they should be prompted with the following menu (items which have 0 availability should not be listed). The new printToolsAvailable method should take one parameter, keysAvailable, which is true if the player has at least 3 credits and otherwise is false. It should return an array containing the index of the first available tool card of each type; for example, if the deck contains three files from toolkit a, the first of which is at index 3 in the deck, no files from toolkit b and one file from toolkit c which is at index 12 in the deck, then the first part of the array returned would look like this: Test the changes you have made: 1. Run the game and play any card to the sequence, then choose 'y' when asked if you would like to buy a tool. Select any tool listed as available, play it to the sequence and then choose 'y' again when asked if you would like to buy a tool; show all the output produced including both menus presented and the tool card being added to the player's hand each time. 2. Continue playing the game and buying tools until you have spent a total of 8 credits (4 picks/file or 1 pick/file and 2 keys) and then show the printed list of tools available when you next choose to buy a tool.ADD THE CREDITS ATTRIBUTE UNDER THE BOOLEAN LOCKSOLVED: private int credits = 10; ADD TO GET CARDS FROM DECK: if (credits>=2) { Console.writeLine(); Console.write("Would you like to buy a tool (y/n)? "); String choice = Console.readLine().toLowerCase(); if (choice.equals("y")) { boolean keysAvailable = credits>2; List<Integer> toolList = deck.printToolsAvailable(keysAvailable); Console.write("Which tool would you like to buy? "); int cardChosen = Integer.parseInt(Console.readLine()); if (cardChosen != 10 && toolList.get(cardChosen-1) != -1) { moveCard(deck,hand,deck.getCardNumberAt(toolList.get(cardChosen-1))); if (cardChosen > 6) { credits -=3; } else { credits -=2; } } } } ADD A NEW printToolsAvailable METHOD IN CARDCOLLECTION: public List<Integer> printToolsAvailable(boolean keysAvailable) { List<String> tools = new ArrayList<>(List.of("F a", "F b", "F c", "P a", "P b", "P c", "K a", "K b", "K c")); List<Integer> toolList = new ArrayList<>(List.of(-1,-1,-1,-1,-1,-1,-1,-1,-1)); List<Integer> toolsAvailable = new ArrayList<>(List.of(0,0,0,0,0,0,0,0,0)); for (int i=0;i<getNumberOfCards()-1;i++) { switch (cards.get(i).getDescription()) { case "F a": toolsAvailable.set(0,toolsAvailable.get(0)+1); if (toolList.get(0) == -1) { toolList.set(0,i); } break; case "F b": toolsAvailable.set(1,toolsAvailable.get(1)+1); if (toolList.get(1) == -1) { toolList.set(1,i); } break; case "F c": toolsAvailable.set(2,toolsAvailable.get(2)+1); if (toolList.get(2) == -1) { toolList.set(2,i); } break; case "P a": toolsAvailable.set(3,toolsAvailable.get(3)+1); if (toolList.get(3) == -1) { toolList.set(3,i); } break; case "P b": toolsAvailable.set(4,toolsAvailable.get(4)+1); if (toolList.get(4) == -1) { toolList.set(4,i); } break; case "P c": toolsAvailable.set(5,toolsAvailable.get(5)+1); if (toolList.get(5) == -1) { toolList.set(5,i); } break; case "K a": if (keysAvailable) { toolsAvailable.set(6,toolsAvailable.get(6)+1); if (toolList.get(6) == -1) { toolList.set(6,i); } } break; case "K b": if (keysAvailable) { toolsAvailable.set(7,toolsAvailable.get(7)+1); if (toolList.get(7) == -1) { toolList.set(7,i); } } break; case "K c": if (keysAvailable) { toolsAvailable.set(8,toolsAvailable.get(8)+1); if (toolList.get(8) == -1) { toolList.set(8,i); } } break; } } for (int i=0;i<tools.size();i++) { if (toolList.get(i) >= 0) { Console.writeLine("" + (i+1) + ". " + tools.get(i) + "(" + toolsAvailable.get(i) + " available)"); } } Console.writeLine("10. No tool (buy nothing)"); return toolList; }This question refers to checkIfLockChallengeMet method of the Breakthrough class. Create an 'Advanced' mode where, for any challenge that requires three or more tool cards to solve, once the challenge is solved move the cards used to solve it from the sequence to the discard pile, exposing the previous card on the sequence, which could then possibly be used in solving another challenge. For example, if the sequence contains: Fa, Kc, Pb and the current challenge is Pb, Kb, Fb. Suppose you play Kb and Fb to the sequence; this will solve the current challenge but instead of the sequence extending to: Fa, Kc, Pb, Kb, Fb it will be contracted to: Fa, Kc and the Pb, Kb and Fb cards from the challenge that was just solved will be added to the discard pile. Test the changes you have made: Run the game and restart until you get a Lock with at least one challenge of one card and one challenge of three cards. Play until you solve the single card challenge and then play until you solve a three card challenge. The screen capture(s) should show the Lock, Sequence and Hand before you play the final card to solve the three card challenge and the Lock and Sequence after you play it.ADD TO THE IF STATEMENT CHECK IF CONDITION MET: if (sequenceAsString.length() >= 13) { for (int i=0; i<sequenceAsString.length()/4;i++) { moveCard(sequence,discard,sequence.getCardNumberAt(sequence.getNumberOfCards()-1)); } }This question refers to playGame and getChoice methods and to the creation of a new saveGame method in the Breakthrough class. It also requires the creation of new getChallengesAsString and getChallengesMetAsString methods in the Lock class. The playGame menu should have a (S)ave option which will save the game in its current state and allow it to be reloaded (from the main menu when you first start the game). In order to understand the format of the save game file, you will have to inspect the game1.txt file and the loadGame method of the Breakthrough class. Print out a suitable message stating whether the game was saved successfully or not. Test the changes you have made: 1. Take a copy of the game1.txt file and rename it backup.txt. 2. Run the game until you get a lock with at least two challenges. Solve one challenge and then save the game as 'game1.txt' (it shouldn't prompt you). Load the game and ensure that the state of it has been correctly restored. 3. Restore the original game1.txt from backup.txt.CHANGE THE CONSOLE WRITE LINE IN GET CHOICE TO GIVE SAVE OPTION: Console.write("(D)iscard inspect, (U)se card, (S)ave:> "); ADD S CASE TO PLAY GAME: case "S": saveGame(); break; ADD IMPORTS AT TOP OF PROGRAM: import java.io.FileWriter; import java.io.IOException; CREATE THE SAVE GAME METHOD: private void saveGame() { try { FileWriter myWriter = new FileWriter("game2.txt"); myWriter.write(score + "\n"); myWriter.write(currentLock.getChallengesAsString()+"\n"); myWriter.write(currentLock.getChallengesMetAsString()+"\n"); myWriter.write(hand.getCardDescriptionAt(0) + " " + hand.getCardNumberAt(0)); for (int i=1;i<hand.getNumberOfCards();i++) { myWriter.write("," + hand.getCardDescriptionAt(i) + " " + hand.getCardNumberAt(i)); } myWriter.write("\n"); myWriter.write(sequence.getCardDescriptionAt(0) + " " + sequence.getCardNumberAt(0)); for (int i=1;i<sequence.getNumberOfCards();i++) { myWriter.write("," + sequence.getCardDescriptionAt(i) + " " + sequence.getCardNumberAt(i)); } myWriter.write("\n"); myWriter.write(discard.getCardDescriptionAt(0) + " " + discard.getCardNumberAt(0)); for (int i=1;i<discard.getNumberOfCards();i++) { myWriter.write("," + discard.getCardDescriptionAt(i) + " " + discard.getCardNumberAt(i)); } myWriter.write("\n"); myWriter.write(deck.getCardDescriptionAt(0) + " " + deck.getCardNumberAt(0)); for (int i=1;i<deck.getNumberOfCards();i++) { myWriter.write("," + deck.getCardDescriptionAt(i) + " " + deck.getCardNumberAt(i)); } myWriter.close(); Console.writeLine("File saved."); } catch (IOException e) { Console.writeLine("File not saved"); } } CREATE METHOD THAT GETS CHALLENGES AND CHALLENGES MET AS A STRING public String getChallengesAsString() { String challengeStr = ""; for (Challenge c : challenges) { if (challengeStr.length()>0) { challengeStr += ";"; } challengeStr += convertConditionToString(c.getCondition()); } return challengeStr; } public String getChallengesMetAsString() { String challengeStr = ""; for (Challenge c : challenges) { if (challengeStr.length()>0) { challengeStr += ";"; } if (c.getMet()) { challengeStr += "Y"; } else { challengeStr += "N"; } } return challengeStr; }This question refers to playGame and playCardToSequence methods and the creation of a new attribute, bonusPool, in the Breakthrough class. It also requires the creation of a new public method, isPartial, in the Lock class, which takes sequence as a parameter. Introduce a bonus for playing consecutive cards to a lock that solves a challenge. More specifically, each card played in a row that goes towards solving a challenge will add 5 to the bonus pool and that bonus pool will be added to the score for each card. For example, the bonus pool is 0 and a player plays a card towards challenge 1: the bonus pool of 0 is added to their score along with their normal score and the bonus pool is increased to 5. If the player does anything except play another correct card towards challenge 1, then the bonus pool will be reset to 0; otherwise they will get the score for the card played as normal, plus the bonus pool of 5, and then the bonus pool will be increased to 10 and so on. Test the changes you have made: Run the game and keep discarding until you have all three cards required to solve a challenge, then solve it one card after another; continue playing and play a card to a challenge and then a card to the sequence that is not part of the challenge.ADD TO THE CHECK IF LOCK CHALLENGE MET: score += 5 + bonusPool; ADD A NESTED IF UNDER THE ELSE: if (currentLock.isPartial(sequence)) { bonusPool += 5; } else { bonusPool = 0; } ADD TO PLAY GAME: ADD IN THE IF LOOP IF DISCARD OR PLAY EQUALS D: bonusPool = 0; CREATE A isPartial METHOD: public boolean isPartial(CardCollection seq) { boolean part = false; for (Challenge c : challenges) { List<String> condition = c.getCondition(); if (condition.size() == 3) { int seqLen = seq.getNumberOfCards() - 1; if (seqLen > 0 && condition.get(1).equals(seq.getCardDescriptionAt(seqLen)) && condition.get(0).equals(seq.getCardDescriptionAt(seqLen-1))) { part = true; } else if (seqLen >= 0 && condition.get(0).equals(seq.getCardDescriptionAt(seqLen))) { part = true; } } } return part; } CREATE NEW BONUS POOL ATTRIBUTE private int bonusPool = 0;This question refers to the processLockSolved, getCardFromDeck and checkIfPlayerHasLost methods, and to the creation of new private generateSolubleLock and generateChallenge methods and a new private attribute finalLock in the Breakthrough class. It also requires the creation of a new public isSoluble method in the Lock class that takes the deck and hand as parameters. EXTRA FILE NEEDED: game2.txt Every lock presented must be solvable based on the cards left in the deck, even if doing so would exhaust the deck. If the lock cannot be solved, then choose a new random lock. If this happens 10 times in a row (without a suitable lock being found) then display a message 'Final Lock' to the user and generate a lock with two challenges that can be solved. Once those challenges are solved, there should be a message from checkIfPlayerHasLost that, instead of saying the player lost, prints out 'You have solved the final lock. Your final score is:' + Score. When approaching this task you should ignore the effect of Difficulty cards and it is sufficient to simply check that the deck and hand combined contain the requisite number of each type of card for the next lock. The attribute finalLock should be set to 0 at the start and then set to 1 in processLockSolved when the final lock is set. When checkIfPlayerHasLost runs, it should set finalLock to 2 if it is 1 (ensuring that the final turn is played). If finalLock is 1 and there are no cards left in the deck then the player doesn't lose until all the cards from their hand are gone. Test the changes you have made: 1. Change the game to load the file game2.txt instead of game1.txt and then run the game and load game. 2. Play the game until the message 'Final Lock' is displayed, then solve that lock and print out the final turn.ADD FINAL LOCK ATTRIBUTE UNDER BOOLEAN LOCK SOLVED: private int finalLock = 0; ADD A IF STATEMENT FOR FINAL LOCK IN CHECK IF PLAYER HAS LOST: if (finalLock == 1) { finalLock = 2; } else if (finalLock == 2) { Console.writeLine("You have solved the final lock. Your final score is: " + score); return true; GED RID OF CHECK IF PLAYER LOST ELSE AND ADD THIS ELSE IF: } else if (deck.getNumberOfCards() == 0) { Console.writeLine("You have run out of cards in your deck. Your final score is: " + score); return true; } return false; } ADD TO GET CARD FROM DECK LAST IF STATEMENT FOR GET NUMBER OF CARDS if ((deck.getNumberOfCards() == 0 && hand.getNumberOfCards() < 5 && finalLock < 1) || (hand.getNumberOfCards() == 0)) { ADD TO PROCESS LOCK SOLVED: if (finalLock < 2) { while (discard.getNumberOfCards() > 0) { moveCard(discard, deck, discard.getCardNumberAt(0)); } deck.shuffle(); int attempts = 0; while (attempts < 10) { currentLock = getRandomLock(); if (currentLock.isSoluble(deck, hand)) { break; } else { attempts++; } } if (attempts == 10) { Console.writeLine("Final Lock"); while (hand.getNumberOfCards() < 5) { moveCard(deck,hand,deck.getCardNumberAt(0)); } currentLock = generateSolubleLock(); finalLock = 1; gameOver = true; } } } Create generateSolubleLock private Lock generateSolubleLock() { List<String> cardsLeft = new ArrayList<>(); Lock newLock = new Lock(); for (int i=0;i<deck.getNumberOfCards();i++) { cardsLeft.add(deck.getCardDescriptionAt(i)); } for (int i=0;i<hand.getNumberOfCards();i++) { cardsLeft.add(hand.getCardDescriptionAt(i)); } newLock.addChallenge(generateChallenge(cardsLeft)); newLock.addChallenge(generateChallenge(cardsLeft)); return newLock; } CREATE GENERATE CHALLENGE METHOD: private List<String> generateChallenge(List<String> cards) { List<String> challng = new ArrayList<>(); int cardToRemove; int tmpRand; try { cardToRemove = rNoGen.nextInt(cards.size() -1); challng.add(cards.get(cardToRemove)); cards.remove(cardToRemove); tmpRand = rNoGen.nextInt(3); for (int i=0;i<tmpRand;i++) { cardToRemove = rNoGen.nextInt(cards.size() -1); while (cards.get(cardToRemove).charAt(0) == challng.get(challng.size() -1).charAt(0)) { cardToRemove = rNoGen.nextInt(cards.size() -1); } challng.add(cards.get(cardToRemove)); cards.remove(cardToRemove); } } catch (Exception e) { //ran out of cards so go with what we have so far } return challng; } CREATE IS SOLUBLE: public boolean isSoluble(CardCollection deck, CardCollection hand) { List<String> cardsLeft = new ArrayList<>(); List<String> challengesLeft = new ArrayList<>(); for (int i=0;i<deck.getNumberOfCards();i++) { cardsLeft.add(deck.getCardDescriptionAt(i)); } for (int i=0;i<hand.getNumberOfCards();i++) { cardsLeft.add(hand.getCardDescriptionAt(i)); } for (Challenge c : challenges) { for (String s : c.getCondition()) { challengesLeft.add(s); } } for (String s : challengesLeft) { if (cardsLeft.contains(s)) { cardsLeft.remove(s); } else { return false; } } return true; }