100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Java Mastery
50 minintermediate

Foundation Practice: Calculator and Number Games

What You'll Build

In this exercise you will build two small but complete console programs that exercise everything from Module 1: a cricket-themed calculator that performs arithmetic on match statistics, and a number-guessing game where the program picks a secret and the player homes in on it. Together they put variables and types, operators and type promotion, control flow, and all four loop forms to work in programs that actually run and respond to input.

Rather than learning each construct in isolation, you will see how they combine: the calculator uses a menu-driven loop with a switch to select operations and careful type handling for correct arithmetic, while the guessing game uses a condition-driven loop, comparisons, and feedback to drive interaction. By the end you will have written, compiled, and run real Java programs that read input, make decisions, repeat work, and produce correct results, consolidating the foundation before the course moves into object-oriented programming.

Analogy🏏Cricket
🏏 Think of it like cricket: after drilling individual skills in the nets, batting, bowling, fielding, a player finally puts them together in a full practice match where the skills must work in combination under live conditions. Just as the practice match reveals whether the separately-drilled skills actually cohere into a performance, these two programs reveal whether your separately-learned constructs, types, operators, branches, loops, actually cohere into working software. Just as the match is where a player first feels how the pieces fit, the exercise is where you first feel how the language fits together. Just as a coach moves players from drills to matches once the basics are sound, the course moves you from concepts to construction once the fundamentals are in place. The insight is that fundamentals only become capability when you assemble them into something complete that runs.

Prerequisites

  • Completion of lessons 01 through 04, or equivalent familiarity with Java types, operators, control flow, and loops.
  • A JDK installed (version 17 or 21 recommended), with javac and java available on the command line; verify with java -version.
  • A text editor or IDE for writing .java files, and comfort compiling with javac and running with java from a terminal.
  • Understanding of integer versus floating-point division and the need to cast for decimal results, from lesson 02.
  • Familiarity with reading console input, which this exercise introduces via the Scanner class from the standard library.

Setup & Project Structure

You will create two standalone programs, each a single Java file with a public class and a main method, the simplest structure for console applications at this stage. Keeping each program in its own clearly-named file follows the one-public-class-per-file rule from lesson 01 and keeps the two exercises independent.

Analogy🏏Cricket
🏏 Think of it like cricket: setting up these two programs is like preparing two separate match fixtures, each with its own scorecard and playing eleven. Just as each fixture is self-contained — its own teams, its own result, no shared state that could tangle the outcomes — each program lives in its own clearly-named Java file with a single public class and a main method, the simplest structure for a console app. Just as the Laws require a clear team sheet before play begins so everyone knows who is on the field, the one-public-class-per-file rule keeps each program's entry point unambiguous. And just as scheduling two independent matches means a problem in one never delays the other, keeping the calculator and the number game in separate files keeps the exercises independent. The payoff: clean, isolated structure that lets you build, run, and reason about each program without the other getting in the way.

Both will use the Scanner class to read input from the keyboard, which you import from java.util. Lay out the files and confirm your toolchain compiles and runs a trivial program before building the full logic, so any environment problem surfaces immediately rather than being mistaken for a bug in your code later.

bash
# Create the exercise files and confirm the toolchain works.
mkdir foundation-practice && cd foundation-practice

# Two standalone programs, each its own public class in its own file:
#   CricketCalculator.java   -- menu-driven arithmetic on match stats
#   GuessTheRuns.java        -- a number-guessing game

# Sanity-check the toolchain with a trivial program first:
cat > Hello.java <<'EOF'
public class Hello {
    public static void main(String[] args) {
        System.out.println("Toolchain OK");
    }
}
EOF
javac Hello.java     # compiles Hello.java -> Hello.class (bytecode)
java Hello           # runs on the JVM -> prints 'Toolchain OK'

# With the toolchain confirmed, build the two programs below, compiling and
# running each the same way: javac <File>.java  then  java <ClassName>

Step 1 — Foundation

Step 1 builds the skeleton of the calculator: reading input with Scanner and a menu-driven loop that keeps offering operations until the user chooses to quit. The concept here is combining a loop with input and a switch, the loop repeats the interaction, Scanner reads the user's choice, and a switch dispatches to the chosen operation. A do-while fits naturally because the menu should display at least once before checking whether to continue.

Getting this skeleton right means the program's interaction structure is sound before any arithmetic is added, so you separate the concern of 'how the program flows' from 'what each operation computes', the same separation that keeps larger programs manageable.

Analogy🏏Cricket
🏏 Think of it like cricket: before drilling specific shots, a batter establishes their basic routine at the crease, take guard, face the ball, decide, repeat, the rhythm that frames every delivery. Just as that repeating routine frames each shot before the shot itself is chosen, the menu loop frames each operation before the operation is computed. Just as the batter always takes guard at least once before deciding whether to continue the innings, the do-while shows the menu at least once before checking whether to quit. Just as a sound routine lets the batter focus on each delivery cleanly, a sound interaction loop lets you focus on each operation cleanly. The insight is that establishing the repeating interaction structure first gives every later piece a clean frame to slot into.
java
// CricketCalculator.java -- Step 1: Scanner input + a do-while menu loop + switch.
import java.util.Scanner;

public class CricketCalculator {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);   // reads keyboard input
        int choice;

        do {                                    // show the menu at least once
            System.out.println("\n--- Cricket Calculator ---");
            System.out.println("1) Strike rate   2) Batting average");
            System.out.println("3) Run rate      0) Quit");
            System.out.print("Choose: ");
            choice = in.nextInt();              // read the user's menu choice

            switch (choice) {                   // dispatch to the chosen operation
                case 1 -> System.out.println("(strike rate -- added in Step 2)");
                case 2 -> System.out.println("(batting average -- added in Step 2)");
                case 3 -> System.out.println("(run rate -- added in Step 2)");
                case 0 -> System.out.println("Goodbye!");
                default -> System.out.println("Invalid choice, try again.");
            }
        } while (choice != 0);                  // repeat until the user quits

        in.close();
    }
}

Step 2 — Core Logic

Step 2 fills in the calculator's arithmetic, the heart of the program, where type promotion from lesson 02 becomes essential. Each operation reads its inputs and computes a result, and the recurring trap is integer division: a strike rate or average computed from two ints will truncate unless you cast to double first, and every division must guard against a zero denominator.

This step is the core because it is where correctness lives, the menu can be perfect, but if the arithmetic truncates or divides by zero the program is wrong. You will implement each operation as a focused method that takes its inputs and returns a correctly-typed result, applying the casting and guarding habits that prevent the classic numeric bugs.

Analogy🏏Cricket
🏏 Think of it like cricket: the routine at the crease means nothing if the actual shots are mistimed, the core skill is making clean contact, and a batter who plays down the wrong line gets out no matter how good their routine. Just as clean contact is where runs are actually scored, correct arithmetic is where the calculator actually works. Just as misjudging the line of the ball, the equivalent of integer division truncating, produces a wrong result despite a good setup, forgetting to cast to double produces a wrong number despite a good menu. Just as a batter carefully watches for the ball that could dismiss them, you carefully guard against the zero denominator that would crash the calculation. The insight is that the core computation must be exactly right, because no amount of surrounding structure rescues a wrong result.
java
// CricketCalculator.java -- Step 2: the arithmetic, with casting + zero guards.
// Replace the placeholder switch arms from Step 1 with calls to these methods.

// Strike rate = (runs / balls) * 100 -- cast to double to avoid integer truncation.
static double strikeRate(int runs, int balls) {
    if (balls == 0) return 0.0;                 // guard: no division by zero
    return ((double) runs / balls) * 100;       // promote BEFORE dividing
}

// Batting average = runs / dismissals (a not-out innings is not counted as a dismissal).
static double battingAverage(int runs, int dismissals) {
    if (dismissals == 0) return runs;           // not out: average is the runs total
    return (double) runs / dismissals;          // cast for a decimal result
}

// Run rate = runs / overs (overs is itself fractional, so use double inputs).
static double runRate(int runs, double overs) {
    if (overs == 0) return 0.0;                 // guard against zero overs
    return runs / overs;                        // overs is double -> double division
}

// Example switch arms wiring input to these methods (inside the do-while loop):
//   case 1 -> {
//       System.out.print("runs balls: "); int r = in.nextInt(), b = in.nextInt();
//       System.out.printf("Strike rate: %.2f%n", strikeRate(r, b));
//   }
//   case 2 -> { ... battingAverage(r, d) ... }
//   case 3 -> { ... runRate(r, oversDouble) ... }

Step 3 — Integration & Enhancement

Step 3 builds the second program, the number-guessing game, integrating loops, comparisons, and feedback into an interactive whole. The game picks a secret number (a target score) and repeatedly reads the player's guess, using a while loop that continues until the guess is correct, and if-else comparisons to tell the player whether to aim higher or lower.

This enhances your toolkit by combining a condition-driven loop (the game runs an unknown number of rounds), relational operators, and a guard against running forever, and it introduces simple random number generation. Building this alongside the calculator shows two different interaction shapes, the calculator's menu-dispatch loop and the game's guess-until-correct loop, reinforcing how the same constructs assemble into different programs.

Analogy🏏Cricket
🏏 Think of it like cricket: a bowler searching for the right length to dismiss a batter does not know in advance how many balls it will take, they bowl, observe whether the ball was too short or too full, adjust, and repeat until they get it right. Just as the bowler loops an unknown number of times, adjusting from feedback each ball, the guessing game loops until correct, adjusting from higher/lower feedback each round. Just as 'too short, pitch it up' guides the bowler's next delivery, 'too low, guess higher' guides the player's next guess. Just as the bowler is guaranteed to eventually find the length, the game must guarantee the loop can end. The insight is that feedback-driven repetition of unknown length, the while loop's natural shape, models exactly this kind of iterative homing-in.
java
// GuessTheRuns.java -- Step 3: a while-loop guessing game with higher/lower feedback.
import java.util.Scanner;
import java.util.Random;

public class GuessTheRuns {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int target = new Random().nextInt(100) + 1;   // secret score 1..100
        int guess = -1;
        int attempts = 0;

        System.out.println("Guess the target score (1-100):");

        // Condition-driven loop: runs an unknown number of times, until correct.
        while (guess != target) {
            System.out.print("Your guess: ");
            guess = in.nextInt();
            attempts++;

            if (guess < target) {
                System.out.println("Too low -- aim higher.");      // feedback
            } else if (guess > target) {
                System.out.println("Too high -- aim lower.");
            } else {
                System.out.println("Correct! Target was " + target
                        + " in " + attempts + " attempts.");
            }
        }
        in.close();
    }
}

Step 4 — Testing & Verification

Verify both programs behave correctly across normal and edge cases. For the calculator, confirm each operation returns a correct decimal result, not a truncated integer, and that the zero-denominator guards prevent crashes; test strike rate, average, and run rate with known values you can check by hand. For the game, confirm the higher/lower feedback is correct and that guessing the exact target ends the loop. Compile and run each, exercising the cases below, and compare the output to the expected results to confirm the type handling and control flow are correct.

Analogy🏏Cricket
🏏 Think of it like cricket: verifying your programs is like checking a scorecard against the video before it's official. Just as a scorer confirms a strike rate is a true decimal — 150.00, not a truncated 150 — you check each calculator operation returns a real decimal result, not an integer that silently drops the fraction. Just as the Laws guard against computing an economy rate for a bowler who hasn't bowled a single over, your zero-denominator guards prevent a divide-by-zero crash. Just as you'd test average, strike rate, and run rate with a known innings you can total by hand, you verify with values you can check yourself. And just as an umpire confirms a decision at the exact edge — level scores, an exact target — you test the higher/lower game's boundary where the guess equals the target. The payoff: normal and edge cases both proven correct, so the result stands up to scrutiny.
bash
# Compile and run both programs, exercising normal and edge cases.
javac CricketCalculator.java && javac GuessTheRuns.java

# --- Calculator checks (enter the inputs at each prompt) ---
java CricketCalculator
#  choice 1, runs=82 balls=53  -> Strike rate: 154.72   (NOT 100 -- proves no truncation)
#  choice 2, runs=250 dismissals=5 -> Batting average: 50.00
#  choice 2, runs=40 dismissals=0  -> Batting average: 40.00 (not-out guard, no crash)
#  choice 3, runs=180 overs=20.0   -> Run rate: 9.00
#  choice 1, runs=10 balls=0       -> Strike rate: 0.00     (zero guard, no crash)
#  choice 0                         -> Goodbye! (loop ends)

# --- Guessing game checks ---
java GuessTheRuns
#  guess below target -> 'Too low -- aim higher.'
#  guess above target -> 'Too high -- aim lower.'
#  guess == target    -> 'Correct! ...' and the loop ends

# If strike rate ever prints 100 for 82/53, you forgot the (double) cast (Step 2).

Warning: Reading input with Scanner has a common pitfall: nextInt() reads a number but leaves the newline character in the buffer, so a following nextLine() returns an empty string unexpectedly. In these number-only programs it is not an issue, but the moment you mix nextInt() and nextLine() it bites. Also, nextInt() throws an InputMismatchException if the user types non-numeric text, your programs assume valid numeric input, which is fine for this exercise but is exactly the kind of input validation real programs must add.

Extension Challenge: Enhance the guessing game with a limited number of attempts so the player can lose, using a counted for loop bounded by a maximum number of guesses, with a break when the guess is correct, combining the counted-for and break constructs from lesson 04. For the calculator, add a 'net run rate' operation that subtracts one run rate from another, and add basic input validation that re-prompts (rather than crashing) when the user enters a non-positive number of balls or overs.

  • Two complete console programs combine Module 1's constructs: a menu-driven calculator and a feedback-driven number-guessing game.
  • A do-while menu loop displays options at least once and repeats until the user quits, with a switch dispatching to each operation.
  • Arithmetic correctness depends on casting to double before integer division and guarding every division against a zero denominator.
  • Each calculator operation is a focused method taking inputs and returning a correctly-typed result, separating flow from computation.
  • The guessing game uses a condition-driven while loop of unknown length with relational comparisons giving higher/lower feedback until correct.
  • Scanner reads console input; verify programs against hand-checked values and edge cases like zero denominators and not-out innings.
Lesson 5 of 35
0% complete