Back

Activity 1.17: Repeating With while

divider

Activity 1.17

Repeating With while

Key Concepts

Repeating a Block

Start, Condition, Change

Loops That Never Stop

Twenty Runs, By Hand

Activity 1.16 asked you to run a program twenty times to decide whether a die that never rolled a 6 was broken. Your honest answer was that you still could not prove it.

You were right, and the reason was that twenty is a small number. Ten thousand runs would have settled it, and clicking ten thousand times is not an option.

Today is the first thing in this course that can do something more than once.

Five Lines to Count to Five

Console.WriteLine(5);
Console.WriteLine(4);
Console.WriteLine(3);
Console.WriteLine(2);
Console.WriteLine(1);

This works. Now count down from a thousand.

A Loop Says It Once

int count = 5;
while (count > 0)
{
Console.WriteLine(count);
count = count - 1;
}
Console.WriteLine("Liftoff!");

Predict what prints, and how many lines.

A Loop Says It Once

Terminal window
5
4
3
2
1
Liftoff!

while checks the condition, runs the whole block if it is true, and then goes back and checks again. When the check fails, it stops and the program carries on below.

Changing 5 to 1000 changes one character. That is the whole point.

Every Loop Needs Three Things

  • A start. count exists and holds 5 before the loop begins.
  • A condition. count > 0 — checked before every pass, including the first.
  • A change. Something inside the block moves count toward failing that condition.

Leave out the change and the condition can never become false.

Forget the Change and It Never Stops

int count = 5;
while (count > 0)
{
Console.WriteLine(count);
}

count is 5 and nothing ever changes it. Predict how long this runs.

Forget the Change and It Never Stops

Terminal window
5
5
5
5
5
... and it never stops

It compiles. It runs. It never ends. This is an infinite loop, and you will write one today — everybody does.

Press Ctrl + C in the terminal to stop it. Nothing is broken and nothing is lost. Learn that now rather than at 11pm.

Counting Is Not the Only Job

int total = 0;
int n = 1;
while (n <= 4)
{
total = total + n;
n = n + 1;
}
Console.WriteLine($"Total: {total}");

Two variables now. n drives the loop; total collects. Predict the total.

Counting Is Not the Only Job

Terminal window
Total: 10

1 + 2 + 3 + 4. The variable that keeps a running answer has to start outside the loop — declare it inside and it would be thrown away and rebuilt on every pass.

The Check Happens Before, Not During

int fuel = 0;
while (fuel < 500)
{
fuel = fuel + 120;
}
Console.WriteLine(fuel);

The condition says under 500. Predict what this prints.

The Check Happens Before, Not During

Terminal window
600

600, not 480. At 480 the condition was still true, so the whole block ran once more. A loop never stops partway through its block — it finishes, then checks.

So the final value can overshoot the number in the condition, and Task 2 is built on exactly that.

Today's Objectives

  • Repeating a block with while
  • Giving every loop a start, a condition, and a change
  • Recognizing and stopping an infinite loop
  • Collecting a running total across passes
  • Asking again until the answer is acceptable

Key Terms

Loop
A block that can run more than once.
Iteration
One pass through a loop's block.
Infinite loop
A loop whose condition never becomes false, so it never ends.
Accumulator
A variable outside the loop that collects a result across every pass.

'F' → Fullscreen

divider

Build

Everything today goes in a new program named 1-17-lunar-lander.

How to read the code blocks. Each task's code block shows your whole program, from line 1, as it should look when that task is finished.

The green lines marked with a + are the ones you add or change for that task — everything else is already in your file. Do not type the + sign.

Where a block shows only comments, you write that code yourself. The comments stay in your file.

If a program will not stop, press Ctrl + C in the terminal. You will need this today. It is not an error and nothing is lost.


Task 1: Free Fall

  • Your lander starts 100 meters up with its engine off. Every turn, gravity adds 4 to its speed, and it drops by that speed.
  • Before you run it, predict how many turns it lasts and how fast it hits. Write both numbers down, then run it and compare.
  • Look at the last turn printed. Its altitude is still above 0 — so why did the loop stop anyway? Be ready to say it.
1-17-lunar-lander
Console.WriteLine("=== LUNAR LANDER ===");
Console.WriteLine("Touch down at a speed of 5 or less.");
Console.WriteLine();
int altitude = 100;
int speed = 0;
int turn = 0;
while (altitude > 0)
{
turn = turn + 1;
Console.WriteLine($"Turn {turn}: altitude {altitude}, speed {speed}");
speed = speed + 4;
altitude = altitude - speed;
}
Console.WriteLine();
Console.WriteLine($"Touchdown at speed {speed}.");
if (speed <= 5)
{
Console.WriteLine("The Eagle has landed.");
}
else
{
Console.WriteLine("CRASH. The lander is in pieces.");
}

Task 2: Take the Controls

  • Add fuel and an engine. Each turn you choose a burn, and every point of burn takes 1 off your speed and 1 out of your fuel.
  • The if stops you burning fuel you do not have. With an empty tank, you are back in free fall.
  • Land it. Play until you touch down at speed 5 or less, and write down the burns that worked. Burn too early and you run out of fuel. Burn too late and you cannot stop in time.
  • Notice the loop does not know how many turns there will be — your flying decides that. That is exactly the job a while loop is for.
1-17-lunar-lander
Console.WriteLine("=== LUNAR LANDER ===");
Console.WriteLine("Touch down at a speed of 5 or less.");
Console.WriteLine();
int altitude = 100;
int speed = 0;
int fuel = 40;
int turn = 0;
while (altitude > 0)
{
turn = turn + 1;
Console.WriteLine($"Turn {turn}: altitude {altitude}, speed {speed}, fuel {fuel}");
Console.Write("Burn? ");
int burn = int.Parse(Console.ReadLine());
if (burn > fuel)
{
burn = fuel;
}
fuel = fuel - burn;
speed = speed + 4 - burn;
altitude = altitude - speed;
}
Console.WriteLine();
Console.WriteLine($"Touchdown at speed {speed}.");
if (speed <= 5)
{
Console.WriteLine("The Eagle has landed.");
}
else
{
Console.WriteLine("CRASH. The lander is in pieces.");
}

Task 3: Choose a Difficulty

  • The comments describe a loop that refuses to start the game until the player picks 1, 2, or 3. Write the code under them, leaving the comments where they are.
  • The question has to be asked twice in your code — once before the loop, and once inside it. Work out why, because it is the part everybody gets wrong first.
  • Test 9, then 0, then 2. The first two should both be refused, and the game should only start after the 2.
  • Then try to land on Hard. It is possible, and it is not easy.
1-17-lunar-lander
Console.WriteLine("=== LUNAR LANDER ===");
Console.WriteLine("Touch down at a speed of 5 or less.");
Console.WriteLine();
int altitude = 100;
int speed = 0;
int fuel = 40;
int turn = 0;
// Ask for a difficulty from 1 to 3 and convert it
// While it is below 1 or above 3, say it is invalid and ask again
// Easy (1) gets 60 fuel, Normal (2) keeps 40, Hard (3) gets 30
while (altitude > 0)
{
turn = turn + 1;
Console.WriteLine($"Turn {turn}: altitude {altitude}, speed {speed}, fuel {fuel}");
Console.Write("Burn? ");
int burn = int.Parse(Console.ReadLine());
if (burn > fuel)
{
burn = fuel;
}
fuel = fuel - burn;
speed = speed + 4 - burn;
altitude = altitude - speed;
}
Console.WriteLine();
Console.WriteLine($"Touchdown at speed {speed}.");
if (speed <= 5)
{
Console.WriteLine("The Eagle has landed.");
}
else
{
Console.WriteLine("CRASH. The lander is in pieces.");
}

Task 4: Break It on Purpose

Two changes, one at a time. Write down exactly what happens, and put each back before the next.

  1. In the game loop, delete the line that changes altitude. Run it and keep entering burns for a few turns, then press Ctrl + C.
  2. Put it back. Now run the program and, at the difficulty prompt, type abc instead of a number.

For number 1, record what the turns showed and how you stopped it. For number 2, record the exception and the line it names.

Number 2 is not a loop bug, and your difficulty loop did not catch it. Say why a loop that checks whether the number is between 1 and 3 never gets the chance to look at abc.


Challenge (Optional): Survive the Nonsense

  • Activity 1.9 left this one open on purpose. There is a version of int.Parse that reports failure instead of crashing: int.TryParse(Console.ReadLine(), out difficulty) is true when the text was a number and false when it was not.
  • Rebuild your Task 3 loop around it so that abc is refused exactly like 9 and 0 were, instead of ending the program.
  • You will need int difficulty; on its own line first, with no value.
  • Write a comment saying what your program now does with abc, and why that is better than the exception even though both stop the wrong value getting through.
  • Then find the cheat. There is a burn that gives you fuel instead of costing it. Find it, and add a check that stops it.
divider

Same Idea, Exam Notation

C#
int count = 5;
while (count > 0)
{
Console.WriteLine(count);
count = count - 1;
}
Exam Notation
count ← 5
REPEAT UNTIL(count ≤ 0)
{
DISPLAY(count)
count ← count - 1
}

Read those two conditions again. They are opposites. while keeps going while its condition is true. REPEAT UNTIL keeps going until its condition becomes true — so it runs while that condition is false.

count > 0 and count ≤ 0 describe the same loop from the two ends. Translating one into the other means flipping the comparison, not copying it across.

C#Exam notation
while (count > 0)REPEAT UNTIL(count ≤ 0)
while (fuel < 500)REPEAT UNTIL(fuel ≥ 500)
while (playing)REPEAT UNTIL(NOT playing)

The reference sheet also has a counted loop, REPEAT n TIMES, which runs a block a fixed number of times with no condition at all. C# writes that one with for, and that is Activity 1.19.

divider

Checkpoint

Your finished program should run like this.

Example Output
=== LUNAR LANDER ===
Touch down at a speed of 5 or less.
Difficulty (1-3)? 9 [Enter]
Invalid. Enter 1, 2, or 3.
Difficulty (1-3)? 2 [Enter]
Turn 1: altitude 100, speed 0, fuel 40
Burn? 0 [Enter]
Turn 2: altitude 96, speed 4, fuel 40
Burn? 0 [Enter]
Turn 3: altitude 88, speed 8, fuel 40
Burn? 0 [Enter]
Turn 4: altitude 76, speed 12, fuel 40
Burn? 4 [Enter]
Turn 5: altitude 64, speed 12, fuel 36
Burn? 4 [Enter]
Turn 6: altitude 52, speed 12, fuel 32
Burn? 4 [Enter]
Turn 7: altitude 40, speed 12, fuel 28
Burn? 4 [Enter]
Turn 8: altitude 28, speed 12, fuel 24
Burn? 4 [Enter]
Turn 9: altitude 16, speed 12, fuel 20
Burn? 4 [Enter]
Turn 10: altitude 4, speed 12, fuel 16
Burn? 11 [Enter]
Touchdown at speed 5.
The Eagle has landed.
  • You wrote down your free-fall prediction before running Task 1, and can say why the loop stopped with altitude still above 0 on the last turn printed
  • You landed on Normal at speed 5 or less, and wrote down the burns that did it
  • The difficulty prompt refuses 9 and 0 and accepts 2, asking again each time
  • Both Task 4 results are recorded — how you stopped the infinite loop, and the exception abc produced
divider

Reflection

Answer the following questions before submitting your work.

  1. Every loop needs a start, a condition, and a change. Explain what goes wrong when the change is missing, and how you stopped it.
  2. The fuel loop's condition says under 500 and the loop finishes at 600. Explain why that is correct behavior rather than a bug.
  3. Activity 1.16 had you run a program twenty times by hand and you still could not prove the die was broken. Describe how a loop would let you settle that question, and roughly how many runs you would ask for.
divider

Submit

Submit four things to the dropbox:

  1. Your 1-17-lunar-lander program file.
  2. Your free-fall prediction next to what actually happened, and the burns you used to land on Normal.
  3. Both Task 4 results — how you stopped the infinite loop, and the exception and line number from abc.
  4. Your three reflection answers.

Activity Complete