Phase 0 · Foundations
A program can only choose and repeat
By the end you'll have a game that thinks — and you'll watch your computer find any number from 1 to 100 in seven questions.
Every program you've written so far is a shopping list. Java starts at the top, does each line once, hits the bottom, and quits. Useful, but a bit sad. A shopping list can't notice that the shop's shut.
To fix that, Java hands you exactly two new powers. Only two. One lets a program choose between paths. The other lets it repeat work.
That's the lot. Every game, every website, every app on your phone is those two moves stacked up thousands of times. Nothing else gets added later.
What you'll be able to do
- Ask Java a true-or-false question, and act on the answer.
- Repeat work until something changes — and stop a program stuck repeating forever.
- Read what a person types, so your program becomes a conversation.
- Write a guessing game, then flip it so the computer guesses.
Section 1It all starts with a yes-or-no question
A bouncer on a door has one job: are you on the list? Yes or no. There's no "sort of". The whole door runs off one two-way answer.
Java's got a type for exactly that. You've already met it in 0.2: boolean, a box holding only true or false. No maybe.
You rarely type those by hand. Instead you let Java work one out by comparing two values. Java hands you the same six you met in maths class:
a == b a != b a < b a > b a <= b a >= bAn operator is a symbol that does a job — + is one too. Here's the bit maths class never mentioned: every one of these six hands back a boolean, not a number.
Two are spelled oddly. != means "not equal", because ! means "not" in Java. And <= is one operator spelled with two characters, so never put a space in the middle.
int age = 15;
System.out.println(age > 12);
System.out.println(age > 90);
System.out.println(age == 15);
System.out.println(age != 15);
System.out.println(age <= 15);
boolean canRide = age >= 12;
System.out.println("canRide = " + canRide);Line 1 puts 15 in an int box — old news from 0.2. The five println lines each print one comparison. The last pair is the move worth learning: boolean canRide = age >= 12; stores the answer instead of printing it.
$ javac Compare.java
$ java Compare
true
false
true
false
true
canRide = trueFive booleans in code order, then the stored one. Only the fourth is false: 15 is not different from 15.
The one that gets everyone: = versus ==
It's the most common mistake in beginner Java. Not one of them. The most.
=is an assignment. It puts a value in a box. A command: "make score be 10."==is a comparison. It asks whether two things match: "is score 10?"
Remember the boxes from chapter 0.2, each with a label on the front. = is writing on that label with a marker pen. == is reading the label to check it's yours. One changes the world. The other only looks at it.
Java catches this half the time. src/OneEquals.java has the bug on purpose:
int score = 3;
if (score = 10) {
System.out.println("Perfect score!");
}$ javac OneEquals.java
OneEquals.java:6: error: incompatible types: int cannot be converted to boolean
if (score = 10) {
^
1 errorThat error is the exact truth. score = 10 is a command, and its result is the number 10 — an int. But if demands a boolean. Java can't turn 10 into true or false, so it refuses. The ^ points at the guilty character.
That's the good case. Now the bad one.
gameOver starts as false, and the if uses one equals sign by mistake. Does it compile? Does the message print? What does the last line show? This one catches people who've been writing code for years.
boolean gameOver = false;
if (gameOver = true) {
System.out.println("Game over, man.");
}
System.out.println("gameOver is now " + gameOver);$ java OneEqualsBool
Game over, man.
gameOver is now trueIt compiles, runs, prints the message, and quietly rewrites your variable. If you guessed "nothing happens", you read it as a question — which is what you meant. That's the trap.
gameOver = true shoves true into the box, and the result of that shove is true. So the if runs — every single time, whatever the game's real state. No error, no warning. A game that's always over.
Memorise it as a sentence: an if asks, so it needs two equals signs.
A piece of text has its own kind of box in Java, spelled String with a capital S. You've seen the word already, in the String[] args line at the top of every program. Text goes in double quotes, so "yes" is a String and 'y' is the char from 0.2.
Text needs its own rule, and here it is, with no exceptions: compare text with .equals(…), never with ==. Write reply.equals("yes"), because == can answer false for two pieces of text that read the same. Chapter 0.5 shows you what is going on, and Phase 1 gives the full rule.
Section 2Choosing: if, else if, else
A boolean nobody acted on is an unused answer. Here's how you act on one: if.
if (/* a true-or-false question */) {
// runs only when the answer is true
}Three parts. The word if. Round brackets holding a question that must give a boolean. Curly brackets holding the work. True means run the block. False means skip it. A block is the name for a group of lines inside curly brackets — main is one.
You can chain forks together. src/Grade.java:
int mark = 74;
if (mark >= 90) {
System.out.println("A");
} else if (mark >= 75) {
System.out.println("B");
} else if (mark >= 50) {
System.out.println("C");
} else {
System.out.println("Not yet");
}Line 1 stores 74. Java then works down the chain, and here's the bit people miss: it stops at the first true one. At least 90? No. At least 75? No — 74 is one short. At least 50? Yes. Print "C", then jump past all the rest, else included.
else has no brackets because it's the catch-all. It runs when everything above came out false, and you don't have to include one.
$ java Grade
CSo order decides everything, and a chain in the wrong order is a real bug. Put mark >= 50 first and every passing mark becomes a C, including 95. It compiles, runs, and lies to you.
Always write the curly brackets
Java lets you leave them off when the body is one line. Lots of tutorials do. Don't.
It's 15 degrees, so definitely not hot. Both indented lines look like they belong to the if. What prints? Careful — the indentation's bait.
int temperature = 15;
if (temperature > 30)
System.out.println("It is hot.");
System.out.println("Drink water.");
System.out.println("Done.");$ java NoBraces
Drink water.
Done."Drink water." on a chilly day. If you guessed only "Done.", you read it the way a human reads it — and that's precisely the problem.
Without curly brackets, an if owns exactly one statement: the next one. That's "It is hot." and nothing else. The "Drink water." line was never inside the if at all.
Java doesn't care about indentation. Not one bit. Leading spaces are for your eyes. You read those two lines as a pair. The compiler saw one statement, then unrelated code. Only one of those readings runs.
So write the brackets, even for one line. Two characters, one whole species of bug gone.
Because you'll read your code far more often than you write it. Indentation shows at a glance what sits inside what. It's a reading aid, like paragraph breaks in a book — no rule forces those either.
Section 3Asking two things at once
Real questions rarely come one at a time. "Are you over 12 and with an adult?" Java's got three tools for stitching them together.
&&— and. True only when both sides are true.||— or. True when at least one side is true.!— not. Flips a boolean to its opposite.
|| is two vertical bars, usually sharing a key with the backslash. Note the doubles — single & and | exist and behave differently.
The word that trips people is "or". In English, "tea or coffee?" means pick one. Java's || is happy if both are true. It asks "at least one?", not "exactly one?".
Don't memorise this. Drive it. Below are two switches, a and b. Flip both and watch which rows change, and which stubbornly don't. Your mission: find the one setting where a && b comes out true. There is exactly one.
a && bfalseone side is false, and && needs botha || btrueat least one side is true!afalse! flips whatever a is!(a && b)truethe && answer, flippedFound it? Both switches on. That's "and" being fussy — one true out of four. Now try the same hunt for a || b being false: also one setting, both off. "Or" is the easy-going one. src/TruthTable.java prints all four rows if you'd rather hear it from Java.
int age = 15;
boolean withAdult = true;
if (age >= 18 || (age >= 12 && withAdult)) {
System.out.println("You may watch the film.");
} else {
System.out.println("Sorry, not tonight.");
}Read that condition from the inside out. The inner brackets ask "at least 12 and with an adult?" — true && true, so true. The outer question is "18 or older, or that inner thing?" Left half false. Right half true. And "or" needs only one. Film happens. Those inner brackets group the "and" so it's answered first, exactly like brackets in maths.
$ java AndOrNot
AND: false
OR: true
NOT: false
You may watch the film.The first three lines come from earlier in that file, where hasTicket is true and hasSnack is false. Ticket and snack? Only one, so false. Ticket or snack? One is enough, so true. Not ticket? The ticket's real, so flipping it gives false.
Java is lazy, and that turns out to be a gift
Given A && B, Java checks A first. A false A makes the whole thing false — look at the table. So Java doesn't read B at all. Same with A || B: a true A settles it, and B never runs.
That's short-circuit evaluation — stopping once the answer is known. It's more than a speed trick. It lets the first half of a condition guard the second half.
7 sweets, 0 people. Dividing a whole number by zero crashes a Java program. The condition below contains sweets / people. Does this crash, or print something?
int sweets = 7;
int people = 0;
if (people != 0 && sweets / people > 2) {
System.out.println("Everyone gets at least three.");
} else {
System.out.println("Cannot share those out.");
}$ java ShortCircuit
Cannot share those out.
Reached this without crashing.
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ShortCircuit.main(ShortCircuit.java:21)No crash from the if. If you expected one, you assumed Java reads the whole condition — reasonable, and wrong.
people != 0 is false, because people is 0. With a false left side, && is finished. Java never touches the division, so there's nothing to crash. The first test shielded the second.
Line 2 is the same idea with ||. Here people == 0 is true, so the division on the right is skipped again.
Line 3's crash is deliberate. The file's last line divides by zero with no shield, so you see what you were protected from. Read the message: / by zero, plus the file and line. Java tells you where to look.
Now the sting. Swap the halves to sweets / people > 2 && people != 0 and it crashes. Same test, same data, different order. With &&, put the cheap safety check on the left.
Section 4Repeating: while, and the loop that never ends
Power number two. A loop is a block Java runs over and over instead of once.
Brushing your teeth. You don't plan 60 separate strokes. You've got one instruction — "keep brushing while there's time left" — and you glance at the clock. Small instruction, big result.
while (/* a true-or-false question */) {
// runs again and again, while the answer stays true
}That's one word different from an if, and completely different behaviour. An if checks once. A while checks, runs the block, then comes back and checks again. It stops only when the check comes out false.
int n = 5;
while (n > 0) {
System.out.println(n);
n = n - 1;
}
System.out.println("Lift off. n is " + n);Line 1 sets n to 5. Line 3 asks "is n bigger than 0?" Line 4 prints n. Line 5 makes n one smaller — that line's the whole ballgame, as you'll see. The closing bracket sends Java back to line 3 to ask again. The last line runs once the loop finishes.
Step through it before you look at the output.
Before the loop. Java has run int n = 5;. The box holds 5. Nothing has printed.
Variables
Check 1. Is 5 > 0? Yes. Print 5, then knock n down by one.
Variables
Printed so far
Check 2. Is 4 > 0? Yes. Print 4, drop n to 3.
Variables
Printed so far
Check 3. Is 3 > 0? Yes. Print 3, drop n to 2.
Variables
Printed so far
Check 4. Is 2 > 0? Yes. Print 2, drop n to 1.
Variables
Printed so far
Check 5. Is 1 > 0? Yes — barely. Print 1, drop n to 0.
Variables
Printed so far
Check 6. Is 0 > 0? No. Zero isn't bigger than zero. The loop ends, and the block doesn't run a sixth time.
Variables
Printed so far
After the loop. Java moves to the next line. Notice n survived, holding 0 — the value that failed the check. That's normal, and worth remembering.
$ java Countdown
5
4
3
2
1
Lift off. n is 0Six checks, five printed lines. That gap's where a lot of loop bugs live.
Now let's break it on purpose
Take Countdown.java and delete one line — the n = n - 1;. That's src/Forever.java:
int n = 5;
while (n > 0) {
System.out.println(n);
}
System.out.println("You will never see this line.");Nothing changes n now. So n > 0 is true, stays true, and it'll still be true after the heat death of the universe. That's an infinite loop: a loop with no way out.
Before you run it, learn the escape hatch. Hold Ctrl and press C. In the terminal that means "stop what you're running". Not Command-C, even on a Mac. Keep that finger ready.
I let mine run and counted the lines. It printed a million lines of 5 before I stopped it, and it wasn't anywhere near done. The message at the end of the file never printed and never will.
Every infinite loop has the same cause. The condition is true, and nothing inside the loop ever makes it false. When a program hangs, look there first. Find the variable in the condition, then check whether anything in the block touches it.
Section 5for loops, and the fence-post problem
Most loops follow the same tired pattern. Set a counter, check it, change it. Forget the third job and you've got the infinite loop from a moment ago. So Java has shorthand — src/Counting.java writes one loop twice:
int i = 0;
while (i < 5) {
System.out.println("i is " + i);
i = i + 1;
}
for (int j = 0; j < 5; j++) {
System.out.println("j is " + j);
}Those two do exactly the same thing. The for gathers the three counter jobs onto one line, split by semicolons:
int j = 0— the setup. Runs once, before anything else.j < 5— the check. Runs before every turn, exactly like awhilecondition.j++— the change. Runs after every turn, then Java goes back to the check.
j++ is new: shorthand for j = j + 1. There's j-- for subtracting one.
So the order runs setup, check, body, change, check, body, change… and out. The change happens at the end of a turn. So the counter you see inside the body is always the value that passed the check.
$ java Counting
-- while --
i is 0
i is 1
i is 2
i is 3
i is 4
-- for --
j is 0
j is 1
j is 2
j is 3
j is 4Identical, as promised. Use while when you don't know how many turns you need — "until the player guesses right". Use for when you do — "five times".
Why 0, and why < instead of <=
That loop printed 0, 1, 2, 3, 4. Five numbers, and 5 isn't one of them. New programmers find this maddening, so let's make it plain.
A fence 5 metres long, a post every metre. How many posts? Six — at 0, 1, 2, 3, 4 and 5. Count the gaps and you get 5. Count the posts and you get 6. Neither is wrong. They're different questions. Nearly every off-by-one bug is someone counting posts when they wanted gaps.
Starting at 0 and stopping before the limit is a gift. i < 5 runs exactly 5 times, and you read the count straight off the code. With i = 1; i <= 5 you get 5 turns too, but now you're doing arithmetic in your head. And in chapter 0.5, lists of data turn out to be numbered from 0 as well.
An off-by-one error is a loop running one turn too many or too few. It's usually one character. src/OffByOne.java lines up three cases:
$ java OffByOne
less than 5: 0 1 2 3 4
less or equal 5: 0 1 2 3 4 5
counting down: 5 4 3 2 1One extra = gives you six numbers instead of five. The third line is a for going backwards: setup at 5, check i > 0, change i--. The three parts needn't count upward — they only have to agree.
Leaving early: break and continue
break— leave the loop now. Skip the rest of the block and all remaining turns.continue— skip the rest of this turn only. Go straight to the next check.
for (int i = 0; i < 10; i++) {
if (i == 4) {
break;
}
System.out.print(i + " ");
}
for (int i = 0; i < 10; i++) {
if (i % 2 == 1) {
continue;
}
System.out.print(i + " ");
}The first loop is set up for ten turns. But when i hits 4 the break fires and abandons the lot. The second uses % from 0.2 — the remainder after dividing. So i % 2 == 1 means "i is odd". For each odd number, continue jumps past the print.
$ java BreakContinue
break at 4: 0 1 2 3
skip odds: 0 2 4 6 8The first prints 0 to 3 — it stopped before printing 4, because the check comes first. Use both sparingly: a loop with breaks scattered through it gets hard to follow.
One more chooser: switch
Checking one variable against a list of exact values makes a long else if chain repetitive. And that's what switch is built for.
int choice = 2;
switch (choice) {
case 1:
System.out.println("New game");
break;
case 2:
System.out.println("Load game");
break;
case 3:
System.out.println("Quit");
break;
default:
System.out.println("No such option");
}Java looks at choice, finds the matching case label, and jumps there. choice is 2, so it lands on case 2: and prints "Load game". break then leaves the switch. default is the catch-all, like else.
Those break statements look like clutter. Watch what happens without them.
The second half of Menu.java is that same switch with every break deleted. choice is still 2. How many lines print, and which?
$ java Menu
Load game
--- now with the breaks removed ---
Load game
Quit
No such optionThree lines, not one. If you said one, you read case as a box with walls. It isn't.
A case label is a door in, not a room. Java jumps to case 2: and then keeps running downward through everything after it — case 3, default, the lot. It stops only at a break or the closing bracket. There were none, so it ran to the end. This is fall-through.
It's occasionally useful, much more often a bug. The habit: write the break the moment you write the case.
Java 17 also has an arrow form, in src/MenuArrow.java: case 2 -> System.out.println("Load game");. It can't fall through, so no break is needed. It prints Load game and stops. Learn the classic form first — that's what older code uses.
Section 6Letting a person type
Everything so far was decided before the program started. To read what somebody types you need a Scanner. It's a piece of Java that watches the keyboard and hands you what arrives.
import java.util.Scanner;
public class AskAge {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("How old are you? ");
int age = in.nextInt();
if (age >= 18) {
System.out.println("You can vote.");
} else {
System.out.println("Not yet. " + (18 - age) + " years to go.");
}
}
}Four new things, one at a time.
import java.util.Scanner; sits at the very top, above the class. Java ships with thousands of ready-made tools and doesn't load them all. import says "I'll be using the one called Scanner, go and find it". Forget it and the compiler says it cannot find the symbol Scanner.
Scanner in = new Scanner(System.in); builds one and names it in. System.in is the keyboard, the way System.out is the screen. new means "build me a fresh one" — more on that in Phase 1.
System.out.print, not println. The ln means "line" and jumps to a new one after printing. Here we're keeping the cursor right after the question mark, so the typing lands on the same line.
in.nextInt() reads one whole number and hands it back. It also waits — the program stops dead there until somebody types a number and presses Enter.
$ java AskAge
How old are you? 15
Not yet. 3 years to go.15 isn't 18 or more, so the else ran and 18 - age worked out the 3. There's also in.nextLine() for a whole line of text, and in.next() for a single word.
That's the whole of Scanner. Now, before you write a single line with it, one trap. Mix nextInt() and nextLine() in the wrong order and your program skips a question. Learn it here, not at midnight.
printf '15\nSam\n' | java ScannerTrap feeds the answers in from the left instead of the keyboard. So these reveals show identical output every time. The trade-off: the answers aren't shown, because they never went through the keyboard. Java printed both questions. 15 and Sam arrived invisibly. Run it yourself and your typing appears.
The trap that has wasted more beginner evenings than any other
This asks for a number, then a name. I ran it and gave it 15, Enter, Sam, Enter. The square brackets in the last line let you see exactly what landed in name. What prints?
System.out.print("Your age? ");
int age = in.nextInt();
System.out.print("Your name? ");
String name = in.nextLine();
System.out.println("Hello [" + name + "], age " + age + ".");$ printf '15\nSam\n' | java ScannerTrap
Your age? Your name? Hello [], age 15.The name's empty, and the program never paused to let you type it.
When you press Enter, an invisible newline character joins your input — the "move to the next line" marker. You gave it 15 and Enter, so the Scanner received 15 followed by a newline.
nextInt() is picky. It grabs the 15 and leaves the newline sitting there. So when nextLine() arrives, it asks for everything up to the next newline. It finds one immediately, with nothing in front of it. It hands back empty text and never waits.
The fix is one line: a bare in.nextLine(); straight after nextInt(), to eat the leftover newline. That's src/ScannerFixed.java:
int age = in.nextInt();
in.nextLine(); // throw away the rest of that line
$ printf '15\nSam\n' | java ScannerFixed
Your age? Your name? Hello [Sam], age 15.Same input, and now Sam arrives. The rule: after nextInt(), if the next read is a nextLine(), put a spare nextLine() in between.
Section 7The project: a game, then the twist
You've now got all three ingredients: a loop to keep going, an if to judge, a Scanner to listen. That's a game.
int secret = 42;
int guess = 0;
int tries = 0;
while (guess != secret) {
System.out.print("Your guess: ");
guess = in.nextInt();
tries = tries + 1;
if (guess < secret) {
System.out.println("Too low.");
} else if (guess > secret) {
System.out.println("Too high.");
} else {
System.out.println("Got it in " + tries + " guesses!");
}
}Three boxes. secret is the answer, fixed at 42 so the game behaves the same every test. guess starts at 0 because it must hold something before the first check, and 0 safely isn't the secret. tries counts attempts.
The condition guess != secret means "keep going while the guess is wrong". It's a while and not a for because nobody knows how many turns it'll take.
Inside: print the prompt, read a number, add one to the count, then the if chain gives the hint. When the guess matches, the celebration prints. Java loops back, finds guess != secret is now false, and stops on its own. No break needed.
$ printf '50\n25\n37\n43\n41\n42\n' | java GuessGameEcho
I picked a number from 1 to 100.
Your guess: 50
Too high.
Your guess: 25
Too low.
Your guess: 37
Too low.
Your guess: 43
Too high.
Your guess: 41
Too low.
Your guess: 42
Got it in 6 guesses!Six guesses out of a hundred numbers, and that's not luck. Look what they did: 50 split the range in half, 25 split what was left, then 37. Each answer threw away a chunk.
Now flip it
What if the computer guesses and you answer? It's got no idea what you picked. It only gets "too high" or "too low". Sounds hopeless.
The whole trick is to always guess the middle. Every answer then wipes out half the numbers still possible — and one yes-or-no answer can't do better than half. Watch it hunt for 73.
Start. Two boxes hold the edges of what's still possible: low is 1, high is 100.
Variables
Still possible
Guess 1: 50. The middle of 1 and 100. You say "too low", so 50 and everything under it is gone. low jumps to 51.
Variables
Still possible
Guess 2: 75. The middle of 51 and 100. "Too high", so everything from 75 up is gone. high drops to 74.
Variables
Still possible
Guess 3: 62. "Too low." low becomes 63. A hundred candidates, three questions, twelve left.
Variables
Still possible
Guess 4: 68. "Too low." low becomes 69. Six left.
Variables
Still possible
Guess 5: 71. "Too low." low becomes 72. Three left: 72, 73, 74.
Variables
Still possible
Guess 6: 73. Correct. Here's the whole hunt as src/HalvingTrace.java printed it:
$ java HalvingTrace
try 1: range 1-100 (100 left), guess 50
try 2: range 51-100 (50 left), guess 75
try 3: range 51-74 (24 left), guess 62
try 4: range 63-74 (12 left), guess 68
try 5: range 69-74 (6 left), guess 71
try 6: range 72-74 (3 left), guess 73
correct after 6 guessesFollow the "left" column: 100, 50, 24, 12, 6, 3. Halving, every single time.
int low = 1;
int high = 100;
int tries = 0;
while (low <= high) {
int guess = (low + high) / 2;
tries = tries + 1;
System.out.print("Guess " + tries + ": is it " + guess + "? (h/l/y) ");
String reply = in.next();
if (reply.equals("y")) {
System.out.println("Found it in " + tries + " guesses.");
break;
} else if (reply.equals("h")) {
high = guess - 1;
} else if (reply.equals("l")) {
low = guess + 1;
}
}low and high are the edges of the range still in play. The condition low <= high means "there's at least one number left". If low ever passes high, the range is empty and you must have lied.
(low + high) / 2 is the midpoint. Whole-number division from 0.2 chops the fraction off, and that's fine. in.next() reads one word. Then three .equals() tests, because this is text and == would betray us — Section 1's warning, earning its keep.
The two update lines are the heart of it. Too high? The answer's below the guess, so high = guess - 1. That - 1 matters: the guess itself is ruled out. Too low? low = guess + 1. Get either wrong and the range stops shrinking — hello, infinite loop. break leaves at once on a correct guess.
Last one, and it's the best. src/HalvingProof.java plays this game against every secret from 1 to 100 — all hundred, no human. It reports the worst it ever did. What's the highest number of guesses it needs? Write a number down before you look. Most people guess far too high.
$ java HalvingProof
Numbers tested: 100
Worst case: 7 guesses (secret was 2)Seven. Not on average — seven at the very worst, across all hundred. No number between 1 and 100 holds out for eight.
Here's the reason — the halving chain: 100, 50, 25, 12, 6, 3, 1. Seven steps from a hundred candidates down to one. Halving a hundred gets you to one alarmingly fast.
Here's that worst case actually played, hunting for 2:
$ printf 'h\nh\nh\nh\nh\nl\ny\n' | java ComputerGuessesEcho
Think of a number from 1 to 100. Do not tell me.
Guess 1: is it 50? (h/l/y) h
Guess 2: is it 25? (h/l/y) h
Guess 3: is it 12? (h/l/y) h
Guess 4: is it 6? (h/l/y) h
Guess 5: is it 3? (h/l/y) h
Guess 6: is it 1? (h/l/y) l
Guess 7: is it 2? (h/l/y) y
Found it in 7 guesses.Now the part that should genuinely startle you. src/Ranges.java runs that same all-secrets test on bigger ranges. For 1–1000 the worst case is 10 guesses. For 1–1,000,000 it's 20. Ten thousand times as many numbers, thirteen extra questions. Doubling the range costs exactly one.
$ java Ranges
1 to 100 -> worst case 7 guesses
1 to 1000 -> worst case 10 guesses
1 to 1000000 -> worst case 20 guessesYou built that from a while, an if chain and two lines of arithmetic. It's got a proper name, and it powers dictionaries, databases and search engines. You don't need the name to see why it works — you watched it happen.
Section 8Your turn
Work in src/. Compile with javac Whatever.java, run with java Whatever.
Section 9Check yourself
A friend's program is stuck. It printed a few lines, then froze, and the prompt never came back. Where do you look first?
What does for (int i = 1; i <= 10; i++) run — how many turns, with which values?
Judgement call. You must check a list isn't empty before reading from it, and reading an empty one crashes. Which condition is safe?
Section 10What broke, what surprised you
Six things here were built to catch you out. Note which ones did — writing it down turns a surprise into a memory.
if (gameOver = true)compiled, ran, and silently rewrote your variable.- "Drink water." printed on a 15-degree day, because indentation is decoration.
- A division by zero sat inside a condition and never happened.
- Deleting one line turned a five-line countdown into a million lines of
5. - A
switchwith nobreakran three cases instead of one. nextLine()afternextInt()came back empty and never waited for you.
If any of those still feels wrong, chase it. Change the file, run it, watch. Being surprised and then checking — that's the whole method. Faster than reading, and it sticks.
One last thing. Every program here crammed its logic into main. That works at ten lines. It's unreadable at a hundred. Next you'll learn how to take a chunk of work, give it a name, and use it anywhere.
Nice. Chapter marked complete.