The Designing and Build of My Project.
Published: 2024-05-27 10:14:31

Recently I had designed and built my first Java program. This program operates based on the progress made by the user, putting them through challenges to better the user until eventually enough progress is made for the user to write their story on the hero they become.

[Source Code](https://github.com/wedward2242/MMUCode)

## Overview
This code was made entirely within Java with the use of different libraries, each implemented into the classes where they were deemed suitable.

## The 'Main' Class
This 'Main' class was the first class created. At first, the 'Main' class was to be the class in which the program was ran. All code would have been created and maintained in this class alone. 
However, this changed to a more decomposed program as time went on as the maintenance and tracking of progress on the code was becoming difficult and illegible.

The 'Main' class holds the 'template' for the objects that are to be created within the rest of the program, holding the encapsulated 'Height', 'Weight', and 'userBMI' attributes.

```
public class Main // Creates a class that is public - a template for a new object
{
    protected double Height; // Variables/Attributes
    protected double Weight;
    protected double userBMI;
    Scanner scanner = new Scanner(System.in); // Takes the Input of the User via Scanner
```

These attributes are then populated by the user through the use of a scanner to take user input and then the userBMI is calculated and stored as an attribute - The libraries used for this are `java.lang.Math` and `java.util.Scanner`.

Getter and setter methods are then used to access the values of these attributes when the user creates a new objectn using this 'Main' class before executing the 'main' method.
This object will be in use for the rest of the program until they have reached the 'CharacterDetails' class.

Initially, this program would break if any value that was not a double was entered by the user. Upon realising this, I had implemented testing to allow the user to re-enter a value until it matched the conditions of '>0' and being a double. 

From here, the user is then presented with their measurements and BMI as well as given a choice of what challenge to embark on, this being implemented using a switch case and further testing, making sure the values 1, 2, or 3 are entered.

```
        int challenge = validator.getValidChallenge(scanner);
    

       switch(challenge) // Switch Case Using the Result of the Scanner as a Condition
       {
        case 1: Challenge1.MassBuilder(); // The Case that Runs if Input is '1' - Method 'MassBuilder' for 'Challenge1' Class is Ran.
        //System.out.println("You have Points");
        break;
        case 2: Challenge2.StaminaTraining(); // The Case that Runs if Input is '2' - Method 'StaminaTraining' for 'Challenge2' Class is Ran.
        //System.out.println("You have Points");
        break;
        case 3: Challenge3.BrainTraining(); // The Case that Runs if Input is '3' - Method 'BrainTraining' for 'Challenge3' Class is Ran.
        //System.out.println("You have Points");
        break;
       }
```

['Main': Source Code](https://github.com/wedward2242/MMUCode/blob/main/Main.java)

## Challenge 1: Mass Builder
This was the first challenge for the user to work up from towards pushing them to the goal of progressing to become a hero.
I had assigned a 'points' variable ready to track the score of the user. 

```
int points = 0; // set the user points to 0
```
The first part of the challenge was purely luck based, I did this just to add some random excitement to some of the challenges.
The user would have to wait for either 1 - a fail -  or 2 - a pass - to be generated for them. The use of an 'if' statement took control of this.

```
        int randomNumber = (int) (Math.random()*2) + 1; //allow for 1 or 2 to be randomly generated
        if (randomNumber == 1) // what happens if the random number is 1
        {
            for (int i = 1; i <= 6; i ++) // loop six times
            {
                System.out.println(i+"!"); //the rep they are on 
            }
            System.out.println("YOU CAN'T DO ANYMORE! FAIL");
            System.out.println("Do 10 push-ups"); // failure message
            for (int i = 1; i <= 10; i ++) // loops 10 times
            {
                System.out.println(i+"!");
               
            }
            points = points - 1; // removes a point from the user
        }
        else
        {
            for (int i = 1; i <= 8; i ++) // loops 8 times
            {
                System.out.println(i+"!");
                
            }
            System.out.println("PASS!"); // pass message
            points = points + 1; //adds a point to the user
        }
```
A fail would result in a loss of points and a pass would result in the user gaining points.

I then gave the user a chance to guess what number would be generated by the method - originally, this was simply `int userchoice  scanner.nextInt();` but this would then mean that if the input was invalid, the whole program would crash. To prevent this I used google and the assistance of AI to integrate a test to capture user inputs and make sure that they are valid, if not, returning error messages.

```
int randomNumber3 = (int) (Math.random()*2) + 1;
        System.out.println("Enter a number, 1 or 2: "); // asks for the user to input 1 or 2

        int userchoice = InputValidator.validateUserChoice(scanner); // scanner to take in the next input from the user - Calls the validation method, shows testing
        if (randomNumber3 != userchoice) // if the user doesnt input the same value his happens
        {
            for (int i = 1; i <= 6; i ++)
            {
                System.out.println(i+"!");
                
            }
            System.out.println("YOU CAN'T DO ANYMORE! FAIL"); // failure message
            System.out.println("Do 10 push-ups");
            for (int i = 1; i <= 10; i ++)
            {
                System.out.println(i+"!");
           
            }
            points = points - 1; // remoes a point from the user
        }
        else // if they have the same value
        {
            for (int i = 1; i <= 8; i ++) 
            {
                System.out.println(i+"!");
             
            }
            System.out.println("PASS!"); // pass message
            points = points + 2; // add two points to the user
        }
```

At the end of this challenge, the user is presented with a message prompting them to choose whether they will go on to other challenges or they will exit the program. Again, I had to make sure that the user inputs where valid so I added a nested 'while' statement.

```
int challenge = scanner.nextInt(); // the user now can choose what they want to do next 
 
         if (challenge == 2) //if they choose 2
         {
             Challenge2.StaminaTraining(); //run the method
         }
         else if (challenge == 3) // if they choose 3
         {
             Challenge3.BrainTraining(); //run the method
         }
         else if (challenge == 4) //if they choose 4
         {
             System.out.println("You will now exit the games"); // exit message
             ImprovementsCheck.secondary(); // run the checking method
         }
         else
         {
             while (challenge != 2 && challenge != 3 && challenge != 4)
             {
             System.out.println("Invalid response - Enter a valid response"); // print that their is an invalid response - could make this a new method but wanted to show how While can be used to have the same logic as a testing method
             challenge = scanner.nextInt();
             }
         }
 
         scanner.close(); // close the scanner
        }
 }
```

[Challenge 1: Source code](https://github.com/wedward2242/MMUCode/blob/main/Challenge1.java)

## Challenge 2: Stamina Training
This is the next class that I had made for the challenges in the program. I had remembered that I would need a validator so I had defined a validator directly in this class using `import java.util.InputMismatchException;`.
I had decided to make a variable to hold the length the user would 'jog' and used a 'while' loop which also contained within a 'try' 'catch' block.

```
int userJog = 0; // add in a variable for the length the user will jog
        while (true) {
            try {
                System.out.print("Enter the length you will jog (It will be measured in meters and must be over 1500): ");
                userJog = IntegerCheck.getValidIntegerInput(scanner);;
                if (userJog < 1500) {
                    System.out.println("Length must be greater than or equal to 1500. Please try again.");
                } else {
                    break; // Valid input, exit loop
                }
            } catch (InputMismatchException e) {
                System.out.println("Invalid input. Please enter a valid integer value.");
                scanner.nextLine(); // Clear the input buffer
            }
        }
```

Within this, the validation method is called for when the user is to input to make sure that the values they input are valid. 

A new feature, was use of larger numbers when doing `Math.random` and defining the lower limit of what numbers can be selected. This can be seen here:
`int randomChance3 = (int) (Math.random()*50) + 15;`
The lower limit is set to 15 and the numbers can go up to 50.

```
         int randomChance3 = (int) (Math.random()*50) + 15;
```

This is used again in conjunction with a testing method and the user input later on in the challenge.

```
 int ThePassMark = (int) (Math.random()*25) + 5;
         System.out.println("Enter a number: This is how many you will do");
         int userBleeps = IntegerCheck.getValidIntegerInput(scanner);
         if (userBleeps < ThePassMark)
```
This allows for the user to enter a value of how many skips they will do and the validation method makes sure that a valid integer is input by the user. This makes sure that the pass mark is 5 or above and compares the users' entry to the pass mark.


[Challenge 2: Source Code](https://github.com/wedward2242/MMUCode/blob/main/Challenge2.java)

## Challenge 3: Brain Training
Firstly, I had imported a new library - `import java.util.ArrayList;`.
Then a fixed array of 7 elements is defined and populated by the users entries.
This can be seen below:

```
double [] userArray = new double [7];

```
        
A validation method is used to make sure that the uses entries are only going to be doubles and these are added in. 
Validation statement: `DoubleCheck.getValidDoubleInput(scanner);`.

I then used a for loop to make a counter that would add every number that was entered into the program by the user together.
the user would then have to calculate the result.

```
for(int i = 0; i<userArray.length; i++)
        {
            sum = sum + userArray[i];
            System.out.println(sum);
        }
        
```


After this, I had made use of the array list.

```
 ArrayList<String> words = new ArrayList<String>();
        
```
Here, the array list is being used to prompt the user for a word to add to the array list. After this I then made the user guess the word, randomly selected from the words they had entered, to be picked.

```
int randomNumber = (int) (Math.random()*6);
        String answer = words.get(randomNumber);
        System.out.println("Enter the word/haracter from the array that you think it is?");
        String UserAnswer = scanner.next();
        if(answer != UserAnswer)
        {
            System.out.println("You have gotten the answer incorrect, you have lost a point");
            points3 = points3 - 1;
        }
        else
        {
            System.out.println("Well done, you have got the answer correct. Have a point");
            points3 = points3 + 1;  
        }
```
I used an 'if' statement to test whether the user had entered the right word and then display the word that was selected.

[Challenge 3: Source Code](https://github.com/wedward2242/MMUCode/blob/main/Challenge3.java)

## The Validation/Testing Methods
These methods were created in order to test the user inputs ensuring they are valid. 
Invalid entries would cause the methods to throw back an error message before prompting the user to try again.
There was a total of 4 different classes including their own validation methods depending on what had to be tested. On top of this, a class holding a custom exception method was created .

```
class InvalidChoiceException extends Exception
{
    public InvalidChoiceException(String errorMessage)
    {
        super(errorMessage);
    }
}

```

This is the first class holding the custom exception method. This inherits the attributes and methods of the pre-determined exception class. Then, when called it displays the error message from method `errorMessage`.

Next we have the different class and testing/validation methods.

The classes made sure the user enters values that are valid.
The conditions tested where:
Integer value
Double value
1 or 2
Between 1 and 3
Values not matching caused an error message.

```
class InputValidator {
    static int validateUserChoice(Scanner scanner) {
        while (true) {
            try {
                int input = scanner.nextInt();
                if (input == 1 || input == 2) {
                    return input;
                } else {
                    throw new InvalidChoiceException("Invalid input. Please enter 1 or 2.");
                   //System.out.println("Invalid input. Please enter 1 or 2.");
                }
            } catch (java.util.InputMismatchException e) {
                System.out.println("Invalid input. Please enter a valid integer.");
                scanner.next(); // Consume invalid input
            }catch (InvalidChoiceException e)
            {
                System.out.println(e.getMessage()); // Display custom error message
            }
        }
    }
}



class ChallengeValidator
{
  public int getValidChallenge(Scanner scanner)
  {
      int challenge;
      do
      {
          System.out.print("Enter your choice: ");
          while (!scanner.hasNextInt()) {
              System.out.println("Invalid input! Please enter an integer.");
              scanner.next(); // Consume the non-integer token
          }
          challenge = scanner.nextInt();
      } while (challenge < 1 || challenge > 3);

      return challenge;
  }
}

class DoubleCheck
{
    static double getValidDoubleInput(Scanner scanner)
    {
        while(true)
        {
            try
            {
                String input = scanner.next();
                double value = Double.parseDouble(input);
                if (value>0)
                {
                    return value;
                }
                else
                {
                    throw new InvalidChoiceException("Invalid input, make sure it is a double.");
                   //System.out.println("Invalid make sure you are entering a double");
                }
            }   catch(NumberFormatException e)
                {
                    System.out.println("Invalid, enter a positive numerical value");
                }catch (InvalidChoiceException e) {
                    System.out.println(e.getMessage()); // Display custom error message
                }
        }

    }
}

class IntegerCheck
{
    static int getValidIntegerInput(Scanner scanner)
    {
        while(true)
        {
            try
            {
                String input = scanner.next();
                int value = Integer.parseInt(input);
                if (value>0)
                {
                    return value;
                }
                else
                {
                    throw new InvalidChoiceException("Invalid input, make sure it is a integer.");
                    //System.out.println("Invalid make sure you are entering a integer");
                }
            }   catch(NumberFormatException e)
            {
                System.out.println("Invalid, enter a positive numerical value");
            }catch (InvalidChoiceException e) {
                System.out.println(e.getMessage()); // Display custom error message
            }
        }

    }
}

```

A try - catch function is then used to do the testing and the catch holds the error exception messages to send the user to do the input again.

[Validation/Testing: Source Code](https://github.com/wedward2242/MMUCode/blob/main/InputValidator.java)

##File Input/output and Reading
There was a utilisation of file input and output to make the program more personal to the user.
I had provided the user with an opportunity to first create the file, and then from there the user was generated the start of the program which it was written to and this was then read out to the user. 

```
public static void createfile(String filename)
   {
    try(Scanner scanner = new Scanner(System.in))
    {
      File myStory = new File(filename);
      
      if (myStory.createNewFile()) 
      {
        System.out.println("File created: " + filename);
      }
       else
      {
        System.out.println("File already exists.");

      }
      
    }
```

```
public static void writeToFile(String filename)
    {
            try (Scanner scanner = new Scanner(System.in);
                 FileWriter fileWriter = new FileWriter("Your Story.txt");
                 BufferedWriter bufferedWriter = new BufferedWriter(fileWriter))
                {
                bufferedWriter.write(story.main());
                System.out.println("Successfully wrote to the file.");
                }
                catch (IOException e)
                {
                System.out.println("An error occurred.");
                e.printStackTrace();
                }
   }
```
From here, the user can now navigate to the same folder in which their program is in and edit the file to create their own story.
This takes place at the end of the user actually going through the programme.
 
The source code for all of these classes and methods can be found below.
[Read File: Source Code](https://github.com/wedward2242/MMUCode/blob/main/ReadFile.java)
[Write to File: Source Code](https://github.com/wedward2242/MMUCode/blob/main/WriteToFile.java)
[Create File: Source Code](https://github.com/wedward2242/MMUCode/blob/main/CreateFile.java)
[Story: Source Code](https://github.com/wedward2242/MMUCode/blob/main/story.java)


## Improvement Checks and Character (avatar) details
When the user had completed their time on the challenges they progress onto the improvements check stage, here they check whether or not they have done enough to go on to the next stage where they actually create their hero.

I had created the improvements check and the 'CharacterDetails' class via the use of inheritance from the 'Main' class. This called the main method within the 'CharacterDetails' class - the class holding the avatar creation.
If not progressed, they had to repeat the process until they had reached a valid BMI.

```
ublic class ImprovementsCheck extends Main
{
   
    public static void secondary()
    {
        Scanner scanner = new Scanner(System.in);
        System.out.println();
        System.out.println("We will now be checking to see if you are within a Healthy range before moving up to the next level! Enter Your Previous Measurements and then Your New Measurements \n");
        
        
        
        ImprovementsCheck growthcheck = new ImprovementsCheck();
        System.out.println("Your BMI is: " + growthcheck.getuserBMI()); // Outputs BMI, Height, and Weight on Seperate Lines
        System.out.println("Your Height is: " +  growthcheck.getHeight());
        System.out.println("Your Weight is: " + growthcheck.getWeight());
 
        if (growthcheck.userBMI >= 18.5 && growthcheck.userBMI <= 24.9)
         {
             System.out.println("You have made significant growth and will progress to the next level"); 
             CharacterDetails.main();
             scanner.close();
   
         }
         else
         {
             System.out.println("You have made insignificant growth, go back and do more!");
```

[Improvements Check: Source Code](https://github.com/wedward2242/MMUCode/blob/main/ImprovementsCheck.java)

The 'CharacterDetails' class adds onto the inheritance from the 'main' class, with extra attributes and methods to gather the hair colour, name, favourite sport and favourite colour. 

These are 'protected' attributes as encapsulation provides a more robust program. 

```
public class CharacterDetails extends ImprovementsCheck
{
    protected String HairColour;
    protected String EyeColour;
    protected String Sport;
    protected String Name;

```
 
Once these methods are carried out and the attributes are assigned values, getters are used to get these values and display to the user.
[Character Details: Source Code](https://github.com/wedward2242/MMUCode/blob/main/CharacterDetails.java)