{"id":"loop-conditions-writing-conditions","slug":"writing-conditions","title":"Writing conditions","text":"A loop condition can be anything you could write after `if`: a comparison, or several of them joined with `and`, `or` and `not`. With `and`, the loop goes on only while both parts are true, so it ends as soon as either part is false.\n\nIn this little game, a hiker walks 4 km per round and uses 3 points of energy for it. The hike ends when the hiker has walked 12 km or runs out of energy, whichever comes first:\n\n```python\nenergy = int(input(\"Energy: \"))\ndistance = 0\nwhile distance < 12 and energy > 0:\n    distance += 4\n    energy -= 3\n    print(f\"{distance} km walked, energy {energy}\")\nprint(\"The hike is over\")\n```\n\n```input\n10\n```\n\n```output\nEnergy: 10\n4 km walked, energy 7\n8 km walked, energy 4\n12 km walked, energy 1\nThe hike is over\n```\n\nWith 10 points of energy, the hiker gets to 12 km, and `distance < 12` is what ends the loop. With 5 points, the energy runs out first: after two rounds it's -1, and the hike ends at 8 km.\n\n### Make sure the loop ends\n\nBefore you trust a loop, check that its condition really becomes false, whatever the input. In this game, every hit takes 3 points from a dragon's health, and the dragon falls when its health is gone:\n\n```python\nhealth = int(input(\"Dragon's health: \"))\nhits = 0\nwhile health != 0:\n    health -= 3\n    hits += 1\nprint(f\"The dragon falls after {hits} hits\")\n```\n\n```input\n9\n```\n\n```output\nDragon's health: 9\nThe dragon falls after 3 hits\n```\n\nWith 9 health points, the health goes 6, 3, 0, and then `health != 0` is false. But with 10 it goes 7, 4, 1, -2, -5 and on: it steps over 0 and is never equal to it. The loop never ends, and the program seems to freeze without printing anything. The condition says \"until the health is exactly 0\", but what you mean is \"while there is health left\": `while health > 0:`. That one becomes false whether the health lands on 0 or drops below it, and with 10 health points the dragon falls after 4 hits. In the same way, when you count up, `<` or `<=` stops a loop that jumps past its limit, where `!=` might not.\n\n### Debugging a loop\n\nWhen a loop misbehaves, look at its condition first. A `<` that should have been `<=` loses the last round, and a `!=` that the variable can step over, like the dragon's, never lets the loop go. Two habits help you see what's going on:\n\n- **Fix the input while you test.** Typing an answer to `input` on every test run gets tedious fast. Turn the `input` line into a comment for now, and give the variable a value of your own on the line below it; to have the program ask again, swap the two over. If a check fails with some input, make that input your fixed value: then every run shows the failing case, and you can watch it go wrong.\n- **Print the values in every round.** A debugging `print` in the body shows what the variables are in each round. Remove it once the program works, since the extra lines would fail the checks.\n\nThis program counts how many squares (1 * 1, 2 * 2, 3 * 3 and so on) it takes to add up to a goal. Both habits are in use:\n\n```python\n# goal = int(input(\"Goal: \"))\ngoal = 30\ntotal = 0\ncount = 0\nwhile total < goal:\n    count += 1\n    total += count * count\n    print(\"debug:\", count, total)\nprint(f\"{count} squares add up to at least {goal}\")\n```\n\n```output\ndebug: 1 1\ndebug: 2 5\ndebug: 3 14\ndebug: 4 30\n4 squares add up to at least 30\n```\n\nThe debugging lines show every round, and that the loop stops as soon as `total` reaches 30.\n","task":"In this game you get the same number of points on every try. The loop should go on while you've had fewer than 5 tries **and** your score is still below 10. Fill in the condition.\n\n```\nPoints per try: 3\nTry 1: score 3\nTry 2: score 6\nTry 3: score 9\nTry 4: score 12\n```\n","kind":"fill","seed":"points = int(input(\"Points per try: \"))\ntries = 0\nscore = 0\nwhile [[tries < 5 and score < 10‖score < 10 and tries < 5]]:\n    tries += 1\n    score += points\n    print(f\"Try {tries}: score {score}\")\n","solution":"points = int(input(\"Points per try: \"))\ntries = 0\nscore = 0\nwhile tries < 5 and score < 10:\n    tries += 1\n    score += points\n    print(f\"Try {tries}: score {score}\")\n","hints":["The condition has two parts, one about `tries` and one about `score`. The loop goes on only while both are true.","Fewer than 5 tries is `tries < 5`, and a score below 10 is `score < 10`. Join them with `and`."],"tests":[{"name":"Test 1","stdin":"3\n","expect":"Points per try: 3\nTry 1: score 3\nTry 2: score 6\nTry 3: score 9\nTry 4: score 12","hidden":false},{"name":"Test 2","stdin":"1\n","expect":"Points per try: 1\nTry 1: score 1\nTry 2: score 2\nTry 3: score 3\nTry 4: score 4\nTry 5: score 5","hidden":true},{"name":"Test 3","stdin":"2\n","expect":"Points per try: 2\nTry 1: score 2\nTry 2: score 4\nTry 3: score 6\nTry 4: score 8\nTry 5: score 10","hidden":true},{"name":"Test 4","stdin":"10\n","expect":"Points per try: 10\nTry 1: score 10","hidden":true}],"require":[],"forbid":[],"more":[{"task":"This program prints numbers from a start value upward in steps of 4, as long as they are below 30. It works when the start is 2, but with 3 as the start it never stops. Fix the condition so that it works for every start value.\n\n```\nStart: 2\n2\n6\n10\n14\n18\n22\n26\nDone\n```\n","kind":"code","seed":"number = int(input(\"Start: \"))\nwhile number != 30:\n    print(number)\n    number += 4\nprint(\"Done\")\n","solution":"number = int(input(\"Start: \"))\nwhile number < 30:\n    print(number)\n    number += 4\nprint(\"Done\")\n","hints":["Try it with 3 as the start, on paper or with the input written into the code: 3, 7, 11, ..., 27, 31. Is the number ever equal to 30?","The loop should go on while the number is below 30, not while it's different from 30."],"tests":[{"name":"Test 1","stdin":"2\n","expect":"Start: 2\n2\n6\n10\n14\n18\n22\n26\nDone","hidden":false},{"name":"Test 2","stdin":"3\n","expect":"Start: 3\n3\n7\n11\n15\n19\n23\n27\nDone","hidden":true},{"name":"Test 3","stdin":"29\n","expect":"Start: 29\n29\nDone","hidden":true},{"name":"Test 4","stdin":"45\n","expect":"Start: 45\nDone","hidden":true}],"require":[],"forbid":[]},{"task":"Write a program that asks for a savings goal and the amount saved each week, with the prompts `Goal: ` and `Saved per week: `. It then adds the weekly amount week by week and prints the total after each week, until the total reaches the goal. Last, it prints how many weeks that took.\n\n```\nGoal: 100\nSaved per week: 30\nWeek 1: 30\nWeek 2: 60\nWeek 3: 90\nWeek 4: 120\nWeeks needed: 4\n```\n","kind":"code","seed":"goal = int(input(\"Goal: \"))\nweekly = int(input(\"Saved per week: \"))\n","solution":"goal = int(input(\"Goal: \"))\nweekly = int(input(\"Saved per week: \"))\ntotal = 0\nweeks = 0\nwhile total < goal:\n    weeks += 1\n    total += weekly\n    print(f\"Week {weeks}: {total}\")\nprint(f\"Weeks needed: {weeks}\")\n","hints":["You need two helper variables, both starting at 0: the total saved so far and the number of weeks.","The loop goes on while the total is still below the goal. In each round, add 1 to the weeks and the weekly amount to the total, then print the line.","The last line comes after the loop, when the total has reached the goal: `Weeks needed: ...`."],"tests":[{"name":"Test 1","stdin":"100\n30\n","expect":"Goal: 100\nSaved per week: 30\nWeek 1: 30\nWeek 2: 60\nWeek 3: 90\nWeek 4: 120\nWeeks needed: 4","hidden":false},{"name":"Test 2","stdin":"50\n25\n","expect":"Goal: 50\nSaved per week: 25\nWeek 1: 25\nWeek 2: 50\nWeeks needed: 2","hidden":true},{"name":"Test 3","stdin":"7\n2\n","expect":"Goal: 7\nSaved per week: 2\nWeek 1: 2\nWeek 2: 4\nWeek 3: 6\nWeek 4: 8\nWeeks needed: 4","hidden":true},{"name":"Test 4","stdin":"1000\n120\n","expect":"Goal: 1000\nSaved per week: 120\nWeek 1: 120\nWeek 2: 240\nWeek 3: 360\nWeek 4: 480\nWeek 5: 600\nWeek 6: 720\nWeek 7: 840\nWeek 8: 960\nWeek 9: 1080\nWeeks needed: 9","hidden":true}],"require":[],"forbid":[{"pattern":"while\\s+True","message":"Write the loop with a condition, such as `while total < goal:`, instead of `while True`."}]}]}