4
\$\begingroup\$

I have a program that will ask the user to input their grades for 4 different sections of a project, then tell them what their total mark is, what grade they got and how many marks away they were from the next grade. I managed to make a single loop for all inputs rather than having a loop for each individual one, but there are still quite a lot of if statements to determine what grade they got and how far away they were from the next one, and I can't figure out how to optimise it since I'm still very new to Java.

import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.Scanner;

public class PortfolioGrade {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String[] words = new String[]{"Analysis", "Design", "Implementation", "Evaluation"};
        int[] marks = new int[words.length];
        for(int counter = 1; counter <= words.length; counter++) {
            System.out.println("Enter your mark for the '" + words[counter - 1] + "' part of the project: ");
            while(true) {
                try {
                    Scanner reader = new Scanner(System.in);
                    marks[counter - 1] = reader.nextInt();
                    if(marks[counter - 1] < 0 || marks[counter - 1] > 25) {
                        System.out.println("Please input a number between 0 and 25.");
                        continue;
                    }
                    break;
                } catch(InputMismatchException e) {
                    System.out.println("Please input a valid integer.");
                }
            }
        }

        int totalmark = Arrays.stream(marks).sum();
        String grade = null;
        String nextgrade = null;
        Integer marksaway = null;

        if(totalmark < 2) {
            grade = "U";
            marksaway = 2 - totalmark;
            nextgrade = "1";
        } else if(totalmark >= 2 && totalmark < 4) {
            grade = "1";
            marksaway = 4 - totalmark;
            nextgrade = "2";
        } else if(totalmark >= 4 && totalmark < 13) {
            grade = "2";
            marksaway = 13 - totalmark;
            nextgrade = "3";
        } else if(totalmark >= 13 && totalmark < 22) {
            grade = "3";
            marksaway = 22 - totalmark;
            nextgrade = "4";
        } else if(totalmark >= 22 && totalmark < 31) {
            grade = "4";
            marksaway = 31 - totalmark;
            nextgrade = "5";
        } else if(totalmark >= 31 && totalmark < 41) {
            grade = "5";
            marksaway = 41 - totalmark;
            nextgrade = "6";
        } else if(totalmark >= 41 && totalmark < 54) {
            grade = "6";
            marksaway = 54 - totalmark;
            nextgrade = "7";
        } else if(totalmark >= 54 && totalmark < 67) {
            grade = "7";
            marksaway = 67 - totalmark;
            nextgrade = "8";
        } else if(totalmark >= 67 && totalmark < 80) {
            grade = "8";
            marksaway = 80 - totalmark;
            nextgrade = "9";
        } else if(totalmark >= 80) {
            grade = "9";
        }

        System.out.println("Your total mark was " + totalmark + ".");
        System.out.println("You got a Grade " + grade + ".");
        if(grade == "9") {
            System.out.println("You achieved the highest grade!");
        } else if(marksaway == 1) {
            System.out.println("You were " + marksaway + " mark away from a Grade " + nextgrade + ".");
        } else {    
            System.out.println("You were " + marksaway + " marks away from a Grade " + nextgrade + ".");
        }
    }
}
\$\endgroup\$
4
\$\begingroup\$

Because there are no holes you can simply have an array of "breakpoints".

int [] steps = new int[] { 2, 4, 13, 22, 31, 41, 54, 67, 80 };
int i;

for(i=0; i<steps.length && totalmark>=steps[i]; i++);
grade = i==0 ? "U" : ""+i;
if(i<steps.length) marksaway=steps[i]-totalmark; 
nextgrade=""+(i+1);
\$\endgroup\$
  • 1
    \$\begingroup\$ Would you mind giving me a fairly simple explanation as to how this works? \$\endgroup\$ – Gameskiller01 Dec 12 '18 at 15:18
  • 1
    \$\begingroup\$ The loop loops over the array and breaks out if toolmark greater the current array-entry. I.e. totalmark=3. First loop, i is 0 and totalmark is greater than steps[0] -> continue -- Second loop, i is 1 and totalmark is not greater than steps[1] -> break out of the loop with i=1. Set grade to "1", marksaway to steps[1]-totalmark and nextgrade to "2" \$\endgroup\$ – Holger Dec 12 '18 at 16:01
1
\$\begingroup\$

I tidied up the first section for you a bit and then implemented the technique suggested by @Holger, all seems to work perfectly after running a few tests.

import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.Scanner;

public class MarkCalculator {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    String[] words = new String[]{"Analysis", "Design", "Implementation", "Evaluation"};
    int[] steps = { 2, 4, 13, 22, 31, 41, 54, 67, 80 };
    int[] marks = new int[4];

    Scanner reader = new Scanner(System.in); // Keep instantiation of scanner outside of loop - once is enough

    int totalmark = 0; 
    int inputMark = 0;
    int marksaway = Integer.MIN_VALUE;

    String grade = "";
    String nextgrade = "";

    for(int counter = 0; counter<words.length; counter++) {
        System.out.println("Enter your mark for the '" + words[counter] + "' part of the project: ");
        try {
            do {
                inputMark = reader.nextInt();
                if(inputMark < 0 || inputMark > 25)
                    System.out.println("Please input a number between 0 and 25.");
                else
                    marks[counter] = inputMark;
            } while(inputMark < 0 || inputMark > 25);
        } catch(InputMismatchException e) {
            System.out.println("Please input a valid integer.");
            reader.nextLine();
            counter--;
        }
    }

    totalmark = Arrays.stream(marks).sum();

    for(int i=0; i<steps.length && totalmark>=steps[i]; i++) {
        grade = (i==0 ? "U" : ""+i);
        if(i < steps.length) {
            marksaway = steps[(i+1)]-totalmark; 
            nextgrade = "" + (i+1);
        }
    }

    System.out.println("Your total mark was " + totalmark + ".");
    System.out.println("You got a Grade " + grade + ".");
    if(grade == "9") {
        System.out.println("You achieved the highest grade!");
    } else if(marksaway == 1) {
        System.out.println("You were " + marksaway + " mark away from a Grade " + nextgrade + ".");
    } else {    
        System.out.println("You were " + marksaway + " marks away from a Grade " + nextgrade + ".");
    }
}

}

\$\endgroup\$
  • \$\begingroup\$ Would a while true loop not be necessary in this case in order to skip the iteration if the user enters an invalid input? \$\endgroup\$ – Gameskiller01 Dec 12 '18 at 15:38
  • 1
    \$\begingroup\$ You are totally right my mistake, my edit should fix this and avoid the ugly while(true). There is still an issue with the case when someone enters a character other than an integer, will have a look at it. \$\endgroup\$ – Mark Mc Adam Dec 12 '18 at 21:17
  • 1
    \$\begingroup\$ After reading the answers to the following question, I changed the catch block so that it consumes whatever invalid token have been inputted and then decrements counters so that it asks for the same grade again. - stackoverflow.com/questions/24414299/… \$\endgroup\$ – Mark Mc Adam Dec 12 '18 at 21:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.