.. Copyright Gareth McCaughan and Jeffrey Elkner. All rights reserved. CONDITIONS: A "Transparent" form of a document means a machine-readable form, represented in a format whose specification is available to the general public, whose contents can be viewed and edited directly and straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup has been designed to thwart or discourage subsequent modification by readers is not Transparent. A form that is not Transparent is called "Opaque". Examples of Transparent formats include LaTeX source and plain text. Examples of Opaque formats include PDF and Postscript. Paper copies of a document are considered to be Opaque. Redistribution and use of this document in Transparent and Opaque forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of this document in Transparent form must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions of this document in Opaque form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution, and reproduce the above copyright notice in the Opaque document itself. - Neither the name of Scripture Union, nor LiveWires nor the names of its contributors may be used to endorse or promote products derived from this document without specific prior written permission. DISCLAIMER: THIS DOCUMENT IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, CONTRIBUTORS OR SCRIPTURE UNION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .. _turning_the_tables: Turning the Tables ================== Introduction ------------ One thing computers are very, very good at is arithmetic. This sheet will show you how to make the computer test how good you are at it. The computer is probably about 10,000,000,000 times faster than you, but for now let's only test how accurate you are. What you need to know --------------------- To do this sheet, you need to know: * The basic bits of Python, from `Sheet 1 <1-intro.html>`__ (*Introducing Python*) * Some simple arithmetic! Planning it out --------------- When you start to think about writing a program, it's helpful to begin by thinking exactly what will usually happen when the program runs. It'll probably go something like this: | What's 6 times 7? *49* | No, I'm afraid the answer is 42. | What's 3 times 2? *6* | That's right -- well done. | ... *And so on, with several more questions...* | What's 5 times 9? *45* | That's right -- well done. | | I asked you 10 questions. You got 7 of them right. | Well done! So, here are some things you need to be able to make the computer do: * Choose numbers (at random, preferably) * Display a question * Calculate the right answer * Get an answer from the person using the program * See whether it's right or not * Display a that's right or that's wrong message * Keep count of how many questions were answered right * Ask a total of (say) 10 questions, and then stop * Display a final message saying how you've done That's quite a lot of things to do, but most of them are quite easy. Let's do them one at a time. Random numbers -------------- Let's start with the first item on that list: choosing the numbers. Try asking Python this and see what it says: .. sourcecode:: python >>> from random import randint # Use this for getting random numbers >>> randint(10, 15) That first line is an import statement. It lets you generate random numbers with ``randint``. As well as putting this line in programs you write, you should also type it in when you start a Python session. Otherwise Python won't understand some of the things you ask it to do. **note:** See `Sheet M `__ (*Modules*) if you want the gruesome details of what's going on here. What do you think ``randint`` does? Try repeating that last line several times until you're sure you understand how it behaves... Hopefully you discovered that the second line calls ``randint`` to ask for a random number between ``10`` and ``15``. We can give a name to each random number, to save them for later use: .. sourcecode:: python >>> num1 = randint(1, 10) >>> num2 = randint(1, 10) >>> num1 7 >>> num2 3 .. describe:: Challenge 1 Make Python print a question like this:: What is 7 times 2? where the two numbers are generated randomly, between 1 and 10, inclusive. Remember to use ``str()`` to convert numbers to strings before you concatenate them together. ``str(randint(1, 10))`` will give you a random number between 1 and 10 converted to a string. *Helpful hint*: Strings can be concatenated and the result can be named using a variable: .. sourcecode:: python >>> num1 = 7 >>> num2 = 2 >>> question = "What is " + str(num1) + " times " + str(num2) + "? " >>> print(question) What is 7 times 42 Now all you have to do is make the two numbers random. Questions and answers --------------------- OK, so now you know how to make Python display the question, but this isn't much use if you can't get an answer from the person using the program. Fortunately, you can. Try this and see what happens: .. sourcecode:: python >>> print(int(input("Enter a number: "))) What about this? .. sourcecode:: python >>> print(3 * int(input("Enter a number: "))) How about this? .. sourcecode:: python >>> print(int(input("What is 5 time 9? "))) Or this? .. sourcecode:: python >>> question = "What is " + str(7) + " times " + str(5) + "? " >>> print(int(input(question))) .. describe:: Challenge 2 Make Python ask for *two* numbers, add them up, and print the result. **Hint**: you can do it with a single command. You can save the number the user enters for ``int(input("Enter a number: "))`` by giving it a name. Try this: .. sourcecode:: python >>> question = 'What is your favorite number? ' >>> answer = int(input(question)) What is your favorite number? 7 >>> answer 7 .. describe:: Challenge 3 Now: Write a short program --- call it ``mathquiz.py`` --- that displays a multiplication question using two random numbers, as above, and then gets the user to type in an answer. This should just be a matter of combining two things you've already done. Don't worry about making the program check whether the user's number is right, or anything. Save this program so that you don't lose it: you'll be needing it again. Remembering the numbers ----------------------- Well, now is the time to worry about making the program check whether the user's number is right. This is trickier than anything else you've done so far, because you will need to use those random numbers *twice*: once when you're saying what question you want answered, and once when you're working out the right answer. *Important Principle*: If you're writing a program and you need to use something twice, *give it a name*. We discussed names in `Sheet 1 <1-intro.html>`__ (*Introducing Python*), and we've already seen them again in this sheet, but here's a brief reminder. You give things names by using the ``=`` sign, and after that you can use the name in place of the thing you named: .. sourcecode:: python >>> thing = 1234 >>> 5 * thing 6170 .. describe:: Challenge 4 Write a program that makes a random number and prints it out 5 times. (This is *not* the same thing as printing out 5 different random numbers!) You'll need to give the random number a name. .. describe:: Challenge 5 Find the program you wrote that prints a question and asks for the answer. Change it so that it gives names to the numbers in the question. Check that you've done it right by making it print the question twice -- run the program and make sure that it does ask the *same* question twice, not two different questions. Make your ``mathquiz.py`` program do the following: #. Choose two random numbers from 1 to 10. #. Display a multiplication question involving them. #. Ask what the answer is. #. Say what the answer should have been. You've already done the first three of these; so the only new thing is the last one. Save the program again! Right or Wrong? --------------- The program you've just written could be used for testing someone's times tables, but it seems rather silly to make the human check all the answers; that's just the kind of boring job computers do well. So, the next stage is to get the machine to check whether the answer you gave was right, instead of just saying what it should have been and leaving you to decide. To do this, you need to learn a new -- and very important -- idea. If... ----- Write a program that looks like this, and run it. The spaces at the start of some of the lines are important! .. sourcecode:: python if 1 < 2: print('Something is wrong!') else: print('Something is right!') The reason why the spaces at the start of a line matter is that Python uses them to decide how much of your program is controlled by the ``if``. Suppose you say .. sourcecode:: python if 1 > 1000: print('Ouch!') print('Boink!') Then the computer *will* print ``Boink!``, because that line isn't part of the ``if``. But if the ``print 'Boink!'`` line had spaces at the start like the ``print 'Ouch!'`` line, then it *would* be part of the ``if``, and therefore wouldn't get printed. Try putting 4 spaces (the recommended indentation in Python) in front of ``print 'Boink!'`` and see what happens. Add a few more print statements both indented and not indented. What happens if you add a print statement with 3 spaces instead of 4? Most computer languages don't take any notice of space at the start of a line. This means that they have to solve the problem in a different way; usually they need something like ``end if`` at the end of the ``if``, or else they insist that you surround everything controlled by the ``if`` in some kind of brackets. Python's way is easier to read. Now change the less than (``<``) to greater than (``>``), and run the program again. Can you guess what's going on? In case you haven't already met the symbols in school: ``<`` means is less than , and ``>`` means is greater than. .. describe:: Challenge 6 Write a program that asks you for a number and then prints different things depending on whether the number is bigger than 100 or not. For your tables-testing program, of course, what you want to know isn't whether the number you typed in is *bigger than* the correct answer; you want to know whether it's *equal to* it. You might expect to do that by writing ``if something = somethingelse:`` and so on, but in fact it turns out that to avoid confusion between (1) using ``=`` to mean is equal to and (2) using ``=`` to mean is the name of, Python uses different symbols for those two things. You've already seen that ``=`` is how you say is the name of, so is equal to must be something different. In fact, in Python is equal to is written with *two* equals signs, like this: ``==``. If you want to know more about ``if`` and related things, see `Sheet C `__ (*Conditionals*). .. describe:: Challenge 7 Change the little program you just wrote that tests whether a number is bigger than 100, so that instead it tests whether the number is *equal to* 100. .. describe:: Challenge 8 Make your ``mathquiz.py`` print a yes! or no! message (like the ones in the sample dialog in the *Planning it out* section earlier in the sheet) depending on whether you typed in the right answer to the question or not. So now you have a program that tests you on *one* multiplication question, and then stops. You're making progress... Over and over and over again ---------------------------- You may remember the ``for`` loop, from `Sheet 1 <1-intro.html>`__ (*Introducing Python*). Whether you do or not, here's an example of how to use it. Write a little program: .. sourcecode:: python for x in 10, 20, 30, 40, 50, 60: n = int(input("Please give me a number: ")) if n == x: print("You got it! Your number and mine are both " + str(x) + ".") else: print("Your number, " + str(n) + " is not " + str(x) + ".") Remember -- *spaces at the starts of lines matter*! Every statement inside the ``for`` loop is indented 4 spaces. The statements inside the ``if`` and ``else`` expressions are indented 4 more spaces. Indentation is very important to Python programs. .. describe:: Challenge 9 Put this program inside a ``for`` loop, so that it repeats three times: .. sourcecode:: python from random import randint win1 = randint(1, 10) win2 = randint(11, 20) win3 = randint(21, 30) winners = str(win1) + " " + str(win2) + " " + str(win3) print("And the three lucky winners are: " + winners + ".") Move everything except the import statement inside the ``for`` loop. If you managed that, do something similar to ``mathquiz.py`` so that it does everything 10 times. If you want to know more about how to do things over and over again in Python, see `Sheet L `__ (*Loops*). Who's counting? --------------- A little while ago we were complaining that your program forced the person using it to check their own answers. You've fixed that now, but the user still has to count how many answers they've got right. The computer ought to be able to do that, too. Here's a little program to try. It doesn't have much to do with the times table tester, but you'll probably find what you have to do next easier if you try this first. .. sourcecode:: python odd = 1 for x in 1, 2, 3, 4, 5, 6: print('An odd number:', odd) odd = odd + 2 That last line may look rather strange: how can ``odd`` be equal to ``odd + 2``? Well, remember that we said a little while ago that in Python ``==`` means is equal to , and ``=`` means is a name for . What the line tells Python to do is: work out ``odd + 2``, and then call *that* ``odd``. In `Sheet 1 <1-intro.html>`__ (*Introducing Python*) we mentioned that what we're calling **names** are often called **variables**. You've now discovered why: the things they name can change, or *vary*. In the program above, ``odd`` starts off meaning 1; then it means 3, then 5, and so on. OK. Back to the math quiz. .. describe:: Challenge 10 Add each of the following lines to your ``mathquiz.py`` program. You'll have to work out *where* in the program. Some of the lines may need some spaces added at the start. .. sourcecode:: python right = 0 right = right + 1 print("I asked you 10 questions. You got " + str(right) + " of them right.") print("Well done!") Improving the program --------------------- If you've done everything correctly so far, you now have a program that does what we described at the start of this sheet. There are lots of things that could be made better; if you aren't fed up of the program yet, you could try some of these: #. *Improve the layout*. It's a pity that the question and the user's answer have to be on different lines, and that there are some unnecessary spaces. Have a look at `Sheet I `__ (*Input and Output*) which tells you a bit more about **input and output**: that is, making the program ask things or say things. You may find that you also need to know some things described in `Sheet S `__ (*Strings*). #. *Timing*. It's probably not hard to get 100% if you don't mind taking, say, an hour over each question. But if you get 100% and take less than a second per question, you're doing very well. So, make the program time you and report at the end how long you took. You'll need to look at `Sheet T `__ (*Time*) for this. #. *Adjustable difficulty*. Some people are very good with numbers. They might find being tested on numbers from 1 to 10 rather boring. Some people are very bad with numbers, and might prefer easier questions. Obviously, it's not too hard to change the program to use larger or smaller numbers --- look at the program and make sure you can see how to do that. It might be more interesting if the program became a little harder every time you get a question right, and a little easier every time you get one wrong. For this to work well, you'd probably need to ask more than 10 questions. #. *Adjustable length*. You might want a quick test, with only four questions. Or a long one, with 100 questions, to see how long you can stay awake. Make the program begin by asking how many questions you want, and then ask that many.To do this, you'll need to know about things called **ranges**. They're described in `Sheet L `__ (*Loops*). What next? ---------- The next sheet in the series is `Sheet 3 <3-pretty.html>`__ (*Pretty Pictures*). It's all about graphics: drawing pictures with Python.