// Note: comments about which requirements are met will be on top of the line of code that meets the requirement
// Any time super.someMethod() with someMethod() being some kind of method of the superclass, "#20 - using method from different class/interface" is satisfied.
import java.util.*; // import all java util
public class Mario extends GameCharacter { // #21 - implementing inheritance heirarchy with student-designed classes
 // #9 - Class Design instance variables
 // #11 - Class Composition (Mario has-a InventoryItem)
 // #13 - ArrayList in student-designed class
 private ArrayList
 // #3 - primitive int
 private int attackPower; // init private int attackPower
 // #9 - Class Design zero arg
 public Mario() { // zero arg
 super(0.0, "Mario");
 inventory = new ArrayList
 inventory.add(new InventoryItem(10.0, false, new String[] {"wood sword", "big stick"}));
 attackPower = 100;
 }
 // #9 - Class Design multi arg
 public Mario(double position, ArrayList
 super(position, name);
 this.inventory = inventory;
 this.attackPower = attackPower;
 }
 // #9 - Class Design setter method
 // #10 - method #1 (setter)
 public void setAttack(int attack) { // set attackPower to int attack input
 this.attackPower = attack;
 }
 // #9 - Class Design getter method
 // #10 - method #2 (getter)
 public int getAttack() { // return attackPower as int
 return this.attackPower;
 }
 // #10 - method #3 (overloaded method)
 public void addItem(InventoryItem item) { // add InventoryItem item input to inventory
 inventory.add(item);
 }
 // #10 - method #4 (overloaded method)
 public void addItem(int index, InventoryItem item) { // add InventoryItem item input to inventory at position index input
 // #2 - if-then-else statement #1 with throw error
 if (index < inventory.size()) {
 inventory.add(index, item);
 } else {
 throw new IndexOutOfBoundsException("Index cannot be greater than " + (inventory.size() - 1) + "!"); // if index is too big throw an error
 }
 }
 // #10 - method #5
 public String clearInventory() { // remove all InventoryItems from inventory and return number of items cleared
 int itemsInInventory = inventory.size();
 inventory = new ArrayList
 return ("Items cleared from inventory: " + itemsInInventory);
 }
 // #10 - method #6
 @Override
 public String getDirection() { // return position in the form of a String called direction
 String direction = super.getDirection();
 // #5 - switch statement
 switch (direction) { // set direction to a different string depending on the position of the character
 case "Middle":
 direction = super.getName() + " is in the middle of the map.";
 break;
 case "Left":
 direction = super.getName() + " is " + super.getPosition() + " units to the Left.";
 break;
 case "Right":
 direction = super.getName() + " is " + Math.abs(super.getPosition()) + " units to the right.";
 break;
 }
 return direction;
 }
 // #10 - method #7
 // #14 - method that uses a for loop to access the maximum value from an ArrayList (inventory)
 public String getItemWithMaxAttack() { // return the InventoryItem in inventory with the highest attack value in the form of a String
 double attack = 0.0;
 ArrayList
 // #4 - for loop
 // #13 - traverse and access ArrayList through for loop
 for (int index = 0; index < inventory.size(); index++) { // set attack to the highest attack found
 if (inventory.get(index).getAttack() >= attack) {
 attack = inventory.get(index).getAttack();
 }
 }
 int index = 0;
 // #4 - do while loop
 do { // find all items with that attack value
 if (inventory.get(index).getAttack() == attack) {
 itemsWithMaxAttack.add(inventory.get(index));
 }
 index++;
 } while (index < inventory.size());
 String itemsWithMaxAttackToString = "The items with the highest attack are: ";
 // #18 (extra credit) - use of a nested for loop
 for (int indexOfItemsWithMaxAttack = 0; indexOfItemsWithMaxAttack < itemsWithMaxAttack.size(); indexOfItemsWithMaxAttack++) { // traverse inventory to find InventoryItems with the highest attack
 for (int indexOfItemAliases = 0; indexOfItemAliases < itemsWithMaxAttack.get(indexOfItemsWithMaxAttack).itemAliases.length; indexOfItemAliases++) { // traverse all aliases of the InventoryItem
 if (indexOfItemAliases + 1 == itemsWithMaxAttack.get(indexOfItemsWithMaxAttack).itemAliases.length) { // add "AKA" at end of alias if it is not the last alias, do not add "AKA" at the end of alias if it is the last alias to be grammatically correct
 itemsWithMaxAttackToString += itemsWithMaxAttack.get(indexOfItemsWithMaxAttack).itemAliases[indexOfItemAliases];
 } else {
 itemsWithMaxAttackToString += itemsWithMaxAttack.get(indexOfItemsWithMaxAttack).itemAliases[indexOfItemAliases] + " AKA ";
 }
 }
 if (indexOfItemsWithMaxAttack + 1 != itemsWithMaxAttack.size()) { // if there are multiple items with the highest attack value add an "and" to prep for the next one
 itemsWithMaxAttackToString += " and ";
 }
 }
 return itemsWithMaxAttackToString; // return the String for the item(s) with highest attack value
 }
 // #9 - Class Design processor method
 public String attack(String weaponName) {
 int index = 0;
 int indexOfWeapon = 0;
 boolean weaponFound = false;
 // #4 - while loop
 while (index < inventory.size()) { // scan all InventoryItem aliases in inventory for the name the user selected
 for (String element : inventory.get(index).itemAliases) {
 // #7 - String method #1 (contains())
 if (element.toLowerCase().equals(weaponName.toLowerCase())) {
 indexOfWeapon = index;
 weaponFound = true; // if a weapon is found set weaponFound to true
 index = inventory.size(); // end the while loop early
 break; // skip the index++
 }
 }
 index++;
 }
 // #2 - if-then-else statement #2
 if (weaponFound != false) { // if weaponFound is not false (a weapon was found) attack, if not, inform user
 // #6 - call to Math.random() and Math.pow()
 int damage = (int)Math.pow(inventory.get(indexOfWeapon).getAttack()*attackPower, Math.random()); // random equation to determine attack
 return (super.getName() + " attacked, dealing " + damage + " damage to the enemy!");
 } else {
 return "No weapon was found with the alias " + weaponName + "!";
 }
 }
 // #17 - use of JScanner for user input
 public void attackWithWeapon() { // return damage dealt with a certain weapon chosen by the user, or return no weapon was found by the name the user entered
 Scanner input = new Scanner(System.in); // new Scanner input
 System.out.println("Which weapon would you like to use?"); // ask user for weapon choice
 String weaponName = input.nextLine();
 System.out.println(this.attack(weaponName));
 }
 public void attackWithStrongestWeapon() {
 String weapon = this.getItemWithMaxAttack().substring(39).split("AKA")[0].trim();
 System.out.println(this.attack(weapon));
 }
 public String giveMeAnotherName() { // rename the Mario character based on certain attributes, or rename the Mario character to a substring of the original name
 // #1 - logical operator #1
 // #7 - String method #2 (toLowerCase())
 if (Math.abs(super.getPosition()) > 9000 || super.getName().toLowerCase().equals("not an explorer")) {
 super.setName("Explorer");
 return "your new name is \"Explorer\"!";
 // #1 - logical operator #2
 } else if (attackPower > 9000 && inventory.size() > 9000) {
 super.setName("Chuck Norris");
 return "your new name is \"Chuck Norris\"!";
 } else {
 // #7 - String method #3 (substring())
 // #8 - casting
 super.setName(super.getName().substring(0, (int)(Math.random() * super.getName().length() + 1)));
 return "your new name is \"" + super.getName() + "\"!";
 }
 }
 // #9 - Class Design toString()
 public String toString() { // toString()
 System.out.println(super.getName() + "'s position is " + this.getPosition());
 System.out.println(super.getName() + " is the character's name.");
 System.out.println(attackPower + " is the character's attack power.");
 System.out.println("These are the items in " + super.getName() + "'s inventory.");
 // #4 - for-each loop
 for (InventoryItem element : inventory) {
 System.out.println(element);
 }
 return "";
 }
 // #24 - Sort ArrayList created last semester with Quicksort
 public void sortInventory() { // sorts inventory
 inventory = quickSort(inventory);
 }
 // Quicksort code
 private ArrayList
 if (list.size() <= 1) 
 return list; // Already sorted 
 ArrayList
 ArrayList
 ArrayList
 InventoryItem pivot = list.get(list.size() - 1); // Use last InventoryItem as pivot
 for (int i = 0; i < list.size() - 1; i++) // splits list into two lists to be recurisvely sorted by their position relative to pivot
 {
 // #20 - using method from different class/interface
 if (list.get(i).getAttack() > pivot.getAttack()) // sort by attack
 lesser.add(list.get(i)); 
 else
 greater.add(list.get(i)); 
 }
 // recursively sort
 lesser = quickSort(lesser);
 greater = quickSort(greater);
 lesser.add(pivot); // combine all sorted lists
 lesser.addAll(greater);
 sorted = lesser;
 return sorted; // list is now sorted
 }
} // end class