ThePythonGameBook

learn Python. Create Games

User Tools

Site Tools


en:python:goblins:step002

This is an old revision of the document!


Step 002 - loop 1000 times

If you tried balancing the values for the goblins Stinky and Grunty in step 001 you will feel the law of Law_of_large_numbers: If Stinky wins 5 times in a row over Grunty, that does not proof that Stinky's values are superior over Grunty. Maybe Stinky has a streak of luck or Grunty's random numbers are specially unlucky. Only if you test a game (several) thousands times you can start to make qualified statements.

Well, pushing thousand times the “run program” button on my text editor is not my idea of fun. (Maybe later if the program becomes better). Good thing that there is a python function to repeat a given task a many times: the for loop.

The for loop iterates over a given list. If you give the for loop a list with thousand items to iterate over, it will do the same task thousand times. But where to get a list with thousand items ? Lucky for you, python provides also a function to generate lists: the range function (and the xrange function).

Flow chart

playing with python's direct mode

This is a good time to play around with python's direct mode. If you start the editor Idle (shipped, as you know, together with python), you are by default in the direct mode. If you -like me- dislike idle (inner values aside, the thing is simply ugly) you can open a terminal and enter

python

. The result in both cases is that you are in python's direct mode, symbolized by the 3 leading “greater than” signs:

>>>

As soon as you enter some commands and press the <key>ENTER</key> python will try to interpret the command and print the result. This is handy to try out functions you do not know by heart, to access python's help system with the help() command or -if you are really bored- create some infinite loops like that one:

while True:
   print "it's never boring with you"

list

Let's use python's direct mode to learn about list's and the range function. A list in python is a comma seperated list of items, starting and ending with square brackets. If you want to put text strings in the list you need quotes:

>>>shoppinglist = ["banana","apple",555, 3.13]

The interesting thing about list's is that each list item gets an number, starting with 0. You can access an list item by it's number:

>>>shoppinglist[0]
'banana'
>>>shoppinglist[2]
555

More about list later or if you are interested here: http://www.swaroopch.com/notes/Python_en:Data_Structures

range

If you just want to have a list with 1000 items in it, all you need to type is:

>>>mylist = range(1000)
>>>mylist

You will get a list starting with “[0,1,2,3,4,” and ending with “997,998,999]

for loop

You can iterate over this list with a for loop (and break out of it using the break command): Write this little program in the direct mode or in your python text editor:

>>> for x in range(1000):
	print x

Note that all indented lines after the for loop will be repeated for each item in the list and also note that the for loop line ends with a colon <key>:</key>.

It is now time to leave python's direct mode (if you work in a terminal, press <key>CTRL</key> and <key>d</key> and go back to your “real” python text editor.

Code discussion

Copy the whole code from this step from the gitub page below and start analyzing it:

functions

So far you know 2 functions: the randint() function of the random module and now the range() functions. You know you are looking at a function if you see a pair of round brackets at the end of the function name.

Like in every other programming language, you can define your own functions. Let us do that: Let's make a function out of the programm 001_goblindice.py ! This is actually very simple: You just write those lines in a text editor (or copy the whole example from Github, see below):

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#...
import random
 
#...
 
def combat():
	"""a function that let 2 goblins fight and return the winners name"""
 
	# define Grunty and Stinky. Note that variables are lowercase
	stinky_hitpoints = 50 # Stinky is weak but smart
	grunty_hitpoints = 60 # Srunty is strong but dumb

below the variable assignments comes the whole rest of 001_goblindice.py , complete with the while loop, but additional indented because it is now part of the combat() function. See below at the github code to get an overview. Note that the first line after def combat(): is a docstring in triple quotes. It's like a comment, but python's help function can make more use of it.

return values

Because the combat() function is called -from it's so called “parent” function- it is important that the combat() function returns the name of the winning gobling. Therefor the end of the combat function is slightly different than in the previous step:

        #----- end of loop ----
        print "=================================="
        #print "The combat ends after {0} rounds".format(combatround)
        print "Stinky has {0} hitpoints left".format(stinky_hitpoints)
        print "Grunty has {0} hitpoints left".format(grunty_hitpoints)
        if grunty_hitpoints > 0:
                print "Grunty is the winner !"
                return "Grunty"
        else:
                print "Stinky is the winner !"
                return "Stinky"

Note that the combat() function returns either the string “Grunty” or the string “Stinky”.

Calling a function many times

To call the combat function 1000 times you could write:

   for x in range(1000):
       combat()

But i will instead write another function to do that:

def many_games(number_of_fights=1000):
	"""calls the combat function 1000 times"""
	stinky_wins = 0
	grunty_wins = 0		
	for fight in range(number_of_fights):
		print "fight number %i" % fight
		winner = combat()
		if winner == "Grunty":
			grunty_wins += 1
		else:
			stinky_wins += 1
	print "==============================="
	print " * * * end results * * * "
	print "==============================="
	print "Grunty wins: %i  vs. Stinky wins: %i" % (grunty_wins, stinky_wins)

Note that this many_games() function has a so called default parameter inside it's parantheses: number_of_fights=1000. That means that if you code

many_games():

the computer notices that there is no value inside the round brackets and default to 1000.

If you rather want to test out one billion games you have to code:

many_games(1000000)

The function call is actual an assignment:

   winner = combat()

The combat() function calculates the name of the winning goblin and assign this string to the variable winner.

calling the calling function

the last line in this program actually calls the many_games() function:

# start !
many_games() # enter another number in the parantheses

ideas

Now you really have a tool to balance out the values of Stinky and Grunty ! Try to give different values for hitpoints, min_damage and maxdamage while still keeping the game fair (nearly exact 50%:50% win chance). Try out your values with large number of games. Obey the law of large numbers !

Source Code on Github

To start this example you need:

file in folder download comment
002_goblindice.py python Download the whole Archive with all files from Github:
https://github.com/horstjens/ThePythonGameBook/archives/master
version for python2.x


python 2.x

View/Edit/Download the file directly in Github: https://github.com/horstjens/ThePythonGameBook/blob/master/python/002_goblindice.py

click reload in your browser if you see no code here:

Comment this Page

~~DISQUS~~

/var/www/horst/thepythongamebook.com/data/attic/en/python/goblins/step002.1324066167.txt.gz · Last modified: 2014/01/09 11:07 (external edit)