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.
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.
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.
# 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.
// 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.
// 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.
// 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.
# 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.