ThePythonGameBook

learn Python. Create Games

User Tools

Site Tools


en:resources:people:jens_horst:part1step002

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

en:resources:people:jens_horst:part1step002 [2014/01/09 11:07] (current)
Line 1: Line 1:
 +====== step 002 - adventure game ======
 +The //code examples// below work best if you write them with an [[en:​resources:​glossary:​e:​editor|program editor]] like [[en:​resources:​websites:​start#​idle]]. Slowly, the examples will grow into a playable game.
  
 +Some examples, so called //​snippets//​ are only parts of a bigger code example and may not run stand-alone.
 +
 +By default, all code examples are designed for [[en:​resources:​glossary:​p:​python3.x]]. If an separate version for [[en:​resources:​glossary:​p:​python2.x]] exist, it is displayed below the python3.x example. ​
 +
 +<note tip>
 +For a deeper introduction into python, read those sources:
 +  * [[http://​docs.python.org/​3.1/​tutorial/​index.html|Official Python3.x Tutorial]]
 +  * [[en:​resources:​books:​start#​a_byte_of_python|Swaroop'​s A byte of Python]]
 +</​note>​
 +
 +[[en:​resources:​glossary:​l:​Line numbers]] in code examples are only displayed to make referring more simple. Line numbers are **never** part of python code and should **not** be copied into an python editor. If a code example has line numbers, copy and paste the code example without selecting the line numbers, or click on the download link if available. On smaller code samples / snippets, you can hide (fold/​unfold) the line numbers with an mouseclick (see picture). Larger code samples/​snippets will have both an version with line numbers and below an version without line numbers.
 +
 +
 +=====  input / output =====
 +
 +
 +==== print ====
 +
 +The most basic Python command is the ''​print''​ function, ideal to print something on the screen like a situation description:​
 +
 +download {{:​en:​part1:​snippet001.py|}}
 +<code python>
 +print("​You are Sir Robin, the young knight. Your way is blocked by an angry dragon."​)
 +</​code>​
 +
 +=== multi-line output ===
 +
 +to include a multi-lined string, encapsulate the string in triple quotation marks (single or double):
 +
 +download {{:​en:​part1:​snippet002.py|}}
 +<code python>
 +print ("""​What do you do now ?
 +1...wait
 +2...fight
 +3...run away"""​)
 +</​code>​
 +
 +alternatively,​ you could also write several strings in one print command and python will glue them together:
 +
 +download: {{:​en:​part1:​snippet003.py|}}
 +<code python>
 +print("​my first line " ​
 +"is made up from "
 +"​several parts"​)
 +</​code>​
 +python will give this output:
 +<​file>​my first line is made up from several parts</​file>​
 +
 +
 +==== input ====
 +
 +but how to get the players response ? For that, we need the input command or raw_input and a concept called variable.
 +
 +download: {{:​en:​part1:​snippet004.py|}}
 +<code python>
 +myanswer = input("​press the corresponding number and ENTER:"​)
 +</​code>​
 +
 +===== Variable =====
 +
 +//​myanswer//​ is a so-called variable. Think of it as an placeholder or conatiner that stores the players choice for later use. Variables can be named like you want, as long as the name follow some rules:
 +  * case-sensitive but shall begin with an lower case letter.
 +  * no reserved python keyword
 +  * do not begin with a number
 +  * do not contain special characters like the comma, the semicolon, dash, space etc. Underscore is allowed, but has sometimes a special meaning.
 +In this snippet, ​ I give variables whose name I forgot made up the prefix "​my"​.
 +
 +//input// accept any keyboard input as **string**. To make the program remember the player'​s input, I **assign** the variable //​myanswer//​ to the string typed in by the player.
 +
 +
 +=== variable output ===
 +
 +Let's confirm the player of his choice:
 +
 +download: {{:​en:​part1:​snippet005.py|}}
 +<code python>
 +print("​Your choosed the answer number {0}"​.format(myanswer))
 +</​code>​
 +What does that mean? The 0 inside the curled brackets is the first placeholder for something to put inside the string. In Python, counting generally begins with 0, not with 1. The <​file>​.format(myanswer)</​file>​ after the string means that python will replace the first placeholder with the first argument of the format command (myanswer).
 +Alternatively,​ if you //really// want you could also write this like in [[wp>​visual_basic]]
 +
 +download: {{:​en:​part1:​snippet006.py|}}
 +<code python>
 +print("​You choose the answer number",​ mymyanswer)
 +</​code>​
 +
 +
 +
 +===== conditional structures =====
 +
 +==== if elif else ====
 +
 +Now let the player know what happens, depending on the choice he made. For that, we need an **if** / **elif** / **else** construct:
 +
 +download: {{:​en:​part1:​snippet007.py|}}
 +<code python>
 +if myanswer == "​1":​
 +    print ("​nothing happens, the dragon also wait")
 +elif myanswer == "​2":​
 +    print ("you fight the dragon. The dragon run away !")
 +    # next situation...
 +elif myanswer == "​3":​
 +    print ("You run away, but the dragon is faster than you. The dragon eat you. Game Over")
 +else:
 +    print ("​wrong key pressed"​)
 +</​code>​
 +
 +----
 +
 +=== line by line discussion ===
 +<code python>​if myanswer == "​1":</​code>​
 +an //equal testing// is coded by two equal signs( == ). One single equal sign is used for assignment. Remember the [[#​variable|myanswer variable]] above.
 +the value of the variable //​myanswer//​ is a string (in quotes), even if it contain only numbers.
 +<code python> ​   print ("​nothing happens, the dragon also wait"​)</​code>​
 +the //​identation//​ (the spaces at the beginning) is required in python after each line ending with an colon.
 +<code python>​elif myanswer == "​2":</​code>​
 +there can be no, one or many **elif:** statements after an **if:** statement
 +<code python> ​   print ("you fight the dragon. The dragon run away !"​)</​code>​|
 +the code block below an **elif:** or **else:** statement can have several lines. ​
 +<code python> ​   # next situation...</​code>​
 +all text following an //hash mark ( # )// is considered a //​comment//​. Comments are meant to be understood by humans, not by the computer. ​
 +<code python>​else:</​code>​
 +there can be no or one **else:** statement after an **if:** (or after the last **elif:**) statemnet
 +<note tip>//​find out more about this topic://
 +  * http://​docs.python.org/​tutorial/​controlflow.html#​if-statements
 +  * http://​www.swaroopch.com/​notes/​Python_en:​Control_Flow
 +</​note>​
 +putting the code snippets 001 until 005 together leads to an very early version of the dragon game:
 +
 +=== dragon001.py ===
 +download code example 008: {{:​en:​part1:​dragon001.py}} ​
 +<code python>
 +# filename: dragon001.py
 +print("​You are Sir Robin, the young knight. Your way is blocked by an angry dragon."​)
 +print ("""​What do you do now ?
 +1...wait
 +2...fight
 +3...run away"""​)
 +myanswer = input("​press the corresponding number and ENTER:"​)
 +print("​Your choosed the answer number {0}"​.format(myanswer))
 +if myanswer == "​1":​
 +    print ("​nothing happens, the dragon also wait")
 +elif myanswer == "​2":​
 +    print ("you fight with the dragon."​)
 +    print ("you are now faced with the next situation...."​)
 +    # continue the code here later
 +elif myanswer == "​3":​
 +    print ("You run away, but the dragon is faster than you. The dragon eat you. Game Over")
 +else:
 +    print ("​wrong key pressed"​)
 +</​code>​
 +
 +----
 +
 +**line by line discussion or why {{:​en:​part1:​dragon001.py}} sucks**
 +<code python># filename: python001.py</​code>​
 +A comment. Not really needed for the computer, but good for us humans.
 +<code python>​print("​You are Sir Robin..."​)</​code>​
 +The situation description. Graphic would be better ​
 +<code python>​print ("""​What do you do now ?
 +1...wait
 +2...fight
 +3...run away"""​)
 +</​code>​
 +One single print command spanning several (physical) lines makes the code hard to read 
 +<code python>​myanswer = input("​press the .. number..."​)</​code>​
 +The player is asked //once// for an decision and the corresponding number (a string !) is stored in the variable //​myanswer//​.
 +It would be nice to have an "​emergency exit" key like <​key>​q</​key>​ to quit the game at will. Later.
 +<code python>​print("​Your choosed the answer...."</​code>​
 +The player is told what option he selected. This is good for forgetful players or games played with latency (like over the internet). Maybe not so necessary in this game.
 +<code python>​if myanswer == "​1":</​code>​
 +The first **if** block processes the answer only once. Note that the variable //​myanswer//​ is a string and must thus be contained in quotes.
 +<code python> ​   print ("​nothing happens..."​)</​code>​
 +Because the previous line ends with a colon <​key>:</​key>​ this line must be //​idented//​. ​
 +Bad: The game always end, even if the player choose answer 1 
 +<code python> ​   # continue the code here later</​code>​|
 +This is a comment to remind us humans to implement more code here later. If you write only comments after an **if:**, **elif:** or **else:** branch, you must at least write an single **pass** command. **pass** does nothing, but allows python to work correctly.
 +<code python>​else:​
 +    print ("​wrong key pressed"​)</​code>​
 +Missing (yet): It would be nice if after the "wrong key pressed"​ message the player is asked again to press a key.
 +
 +==== loops ====
 +
 +It would be nice to have the program ask the player for a choice **until** he type in a correct number. As the game will have many situation descriptions and choices later, it would be good to include an //emergency exit// option if the player need to end the game quickly or is bored.
 +
 +This can be done with a loop. Python knows the **while-loop** and the **for-loop**. The for-loop is used to repeat commands a defined number of time. Because i don't know how stupid or persistent the player is with typing in wrong numbers, i need the while-loop. ​
 +
 +download: {{:​en:​part1:​snippet009.py|}}
 +<code python>
 +# --- repeat until the playe type in a correct number (or q) ----
 +while myanswer not in ["​q",​ "​1",​ "​2",​ "​3"​]:​
 +    myanswer = input("​press q and ENTER to quit or the corresponding number and ENTER:"​)
 +# --- end of while loop ----
 +</​code>​
 +The identation is necessary after each line ending with an colon. The idented line(s) will be repeated until the value of //​myanswer//​ is equal to an element in the **list**. The list is defined by square brackets.
 +<note tip>
 +//find out more about this topic://
 +  * http://​docs.python.org/​tutorial/​controlflow.html#​for-statements
 +  * http://​www.swaroopch.com/​notes/​Python_en:​Control_Flow#​The_while_Statement
 +</​note>​
 +
 +The while loop runs as long as the condition (the test) equals **True** or until the loop is leaved by an **break** command. Because the program can not test an variable that does not exit, the variable is defined and filled with an "​stupid"​ value beforehand. ​
 +
 +Note that by catching all bad answers with the while-loop, the else construct becomes unnecessary.
 +
 +=== dragon002.py ===
 +
 +download code example 010: {{dragon002.py}}
 +<code python>
 +# filename: dragon002.py
 +print("​You are Sir Robin, the young knight. Your way is blocked by an angry dragon."​)
 +print("""​What do you do now ?
 +1...wait
 +2...fight
 +3...run away"""​)
 +myanswer="​something stupid"​ # assing a value to the variable to make testing it possible
 +
 +while myanswer not in ["​q",​ "​1",​ "​2",​ "​3"​]: ​
 +    myanswer = input("​press q and ENTER to quit or the corresponding number and ENTER:"​)
 +
 +if myanswer == "​1":​
 +    print("​nothing happens, the dragon also wait")
 +    #continue the code here later
 +elif myanswer == "​2":​
 +    print("​you fight the dragon. The dragon run away !")
 +    print("​you are now faced with the next situation...."​)
 +    # continue the code here later
 +elif myanswer == "​3":​
 +    print("​You run away, but the dragon is faster than you.\n"​
 +          "The dragon eat you. Game Over")
 +</​code> ​
 +
 +test it out, you can now type in "​stupid"​ answers as long as you like, the game will ask you for a correct answer until you give one or press "​q"​.
 +
 +----
 +
 +**line by line discussion or why {{dragon002.py}} still suck**
 +
 +<code python># filename: python002.py</​code>​
 +A comment. Still not needed for the computer, but good for us humans.
 +
 +<code python>​print("​You are Sir Robin, ..."​)</​code>​|
 +The situation description. Still lacking graphic !
 +<code python>​myanswer="​something stupid"​ # assing...</​code>​
 +The variable myanswer is assigned a "​stupid"​ value. This is necessary because the myanswer will be tested soon. Note that the rest of the code line after the <​key>#</​key>​ sign is a comment!
 +<code python> </​code>​
 +An empty (!) line. Empty lines sometimes make the code more pretty to look at.
 +<code python>​while myanswer not in ["​q",​ "​1",​ "​2",​ "​3"​]:</​code>​
 +The while loop. The //​condition//​ of this while loop is at the beginning not met, "​stupid"​ is no element of the list ["​q",​ "​1",​ "​2",​ "​3"​] and thus the condition equals True and python continues with the next line.
 +<code python> ​   myanswer = input("​press q or ..."​)</​code>​
 +Because the previous line ends with an colon, this line is //​idented//​.
 +The player has now an "​emergency exit" option by pressing <​key>​q</​key>​
 +This line will be repeated until the //​condition//​ in the previous ​ line becomes False, meaning the player is making a reasonable choice by pressing one of the keys listed in the previous line line.
 +|<code python> ​   print("​You run away.......\n"​
 +          "The dragon eat you. Game Over"​)</​code>​
 +
 +
 +The <​nowiki>​\n</​nowiki>​ inside the **print** command is called an [[en:​resources:​glossary:​e:​escape sequence]]. This special escape sequence will force python to print a new line.
 +Note that print command spans several (physical) lines. If a **print** command has several strings, all of them will be glued together by python automatically. This multi-line syntax was coded to make the code more pretty to the human eye.
 +The <​key>​q</​key>​ key has no **elif** branch, not even an **else** branch. The **while** loop make sure that only keys from the accepted list were typed in by the player. If the player pressed <​key>​q</​key>,​ no **if elif** branch is processed and python continues at the next line. Because there is no next line, python exit and the game ends.
 +
 +The game still does not make much sense to play: 
 +
 +  * if you choose answer 1 (wait) the game ends instead of repeating the the situation
 +  * if you press <​key>​q</​key>​ to end the game there is no message like ''​you quit the game''​
 +  * if you choose answer 2 there is the game ends instead of leading to a new situation or a more detailed fight.
 +
 +Let's say that to win the game, the player fight the dragon **until** the dragon is wounded at the belly **and** at the tail **and** at the head. 
 +Translated into computer programming language, that means that **while** the dragon is not wounded in all three spots, the player has to keep fighting.
 +To control if this condition is met, let us assign three variables (belly, tail, head) to the value **False** and repeat the while loop until all 3 variables become **True**. If the player want to leave the fight (because he is bored or can not figure out how to win), let him **break** out of the while loop.  ​
 +
 +==== loops: break , else ====
 +
 +While loops can have an optional else part after the while statement. The code in this else statement will be executed if the while loop is leaved "​correctly"​ (the condition of the while loop becomes **False**).
 +A **break** command ends the current loop immediately,​ even if the condition of the while loop remain **True**. If an else part exist after the while loop, it will not be executed if the while loop is leaved by an break command.
 +
 +<note tip>
 +find out more about this topic:
 +  * http://​docs.python.org/​3.1/​reference/​simple_stmts.html#​the-break-statement
 +  * http://​www.swaroopch.com/​notes/​Python_en:​Control_Flow#​The_break_Statement
 +</​note>​
 +
 +=== dragon003.py ===
 +
 +This code example let you fight a dragon:
 +download code example 011: {{:​en:​part1:​dragon003.py|}} ​
 +<code python>
 +# filename: dragon003.py
 +# assign 3 variables to the value False
 +belly = False # mybelly or belly_wound or dragonbelly etc.
 +head = False
 +tail = False
 +print("​You fight the dragon!"​)
 +situation2="""​Where do you want to attack the dragon?
 +1...attack the dragon'​s head
 +2...attack the dragon'​s belly
 +3...attack the dragon'​s tail
 +q...quit the game"""​
 +# repeat until all those 3 variables are True
 +while not (belly and head and tail):
 +    print(situation2)
 +    myanswer = input("​what do you want to do?")
 +    if myanswer == "​1":​
 +       ​print("​You hit the dragon on the head with your sword!"​)
 +       head = True
 +    elif myanswer == "​2":​
 +       ​print("​You inflict an ugly wound on the dragon'​s belly"​)
 +       belly = True
 +    elif myanswer =="​3":​
 +       ​print("​You hack a deep wound in the dragon'​s tail")
 +       tail = True
 +    elif myanswer =="​q":​
 +       break # leave the game
 +else:
 +    print("​The dragon bleeds from head, tail and belly and runs away.\n You are victorious! Congratulation,​ you have won the game")
 +print("​bye-bye"​)
 +</​code> ​
 +
 +----
 +
 +**line by line discussion or why dragon003.py is not so bad at all:**
 +
 +<code python># filename: dragon003.py</​code>​
 +A comment. You know, only for us humans.
 +<code python>​belly = False # mybelly....
 +head = False
 +tail = False</​code>​
 +Alternatively,​ this three code lines could be condensed into one single code line. While saving space, it makes the code harder to read:​{{:​en:​part1:​snippet013.py|}}<​code python>​head,​ belly, tail = False, False, False</​code>​
 +<code python>​situation2="""​Where do you..."""​)</​code>​
 +//​situation2//​ is a variable holding the text for the print statement later. This makes the code better readable and offers the possibility for text-manipulation later.
 +<code python>​while not (belly and head and tail):</​code> ​
 +The condition for the while loop is written very condensed. If a **boolean variable**((any variable that is either True or False)) is tested, python allows to test the variable directly. Alternatively,​ instead of:​{{:​en:​part1:​snippet014.py|}}<​code python>​if belly == True:</​code>​you can write:​{{:​en:​part1:​snippet015.py|}}<​code python>​if belly:</​code>​The long form of the while condition in this line would be:​{{:​en:​part1:​snippet016.py|}}<​code python>​while not (belly==True and tail == True and head == True):</​code>​
 +//​situatoin2//​ is a text variable, but not a string. Thus, situation2 does not need to be contained in quotes. The //value// of //​situation2//​ is a string, and was assigned with the help of quotes in a previous line.
 +<code python> ​   if myanswer == "​1":</​code>​
 +Nothing new: the players response is assigned to the text variable //​myanswer//​.
 +Each possible value of myanswer is processed now. Note that the value of myanswer is a string and thus need to be contained in  quotes.
 +The //testing// for equal is coded in python with two equal signs. On of the most popular programming errors with python is to code an equal testing with only one equal sign.
 +<code python> ​      ​print("​You hit the dragon ..."​)</​code>​
 +Only some gory text description at the moment. Later we will add graphics here, i promise.
 +<code python> ​      head = True</​code>​
 +That's new: we //assign// the value **True** to the boolean variable //head//. Meaning, the dragon is now sufficient hit at the head. Note that only one equal sign is used now. Also Note that **True** and **False** both begin with an upper case letter.
 +<code python> ​   elif myanswer =="​q":</​code>​
 +[[#​dragon002.py]] had a far superiour input-handling than this example. Only input that made sense was accepted in dragon002.py,​ whereas this example accepts every input from the player, no matter how stupid.
 +<code python> ​      break # leave the game</​code>​
 +A **break** command ! This will break out of the current (while) loop and force python to continue at the non-indented line below.
 +<code python>​else:</​code>​
 +This **else** block will only be computed by python if the while loop is leaved correctly (condition becoming False), but not when the while loop is leaved by an **break** command.
 +<code python> ​   print("​The dragon bleeds...\n You..."​)</​code>​
 +Note the [[en:​resources:​glossary:​e:​escape sequence]] <​nowiki>​\n</​nowiki>​ to force python to make a new line.
 +<code python>​print("​bye-bye"​)</​code>​
 +This last line will always be displayed, no matter how the while loop was leaved.
 +
 +If you compare [[#​dragon002.py]] with [[#​dragon003.py]],​ you should see that both programs have //​something//​ in common. Something more than the name //dragon// alone. Detecting things that two different programs (should) have in common is an important skill for any good python programmer. (See → [[wp>​Pattern_recognition]]).
 +
 +===== functions =====
 +==== def and return ====
 +
 +Basically, dragon003.py could not only be viewed as an -up to now missing- ​ part of python002.py;​ both programs also share the task of accepting the players input with the **input** command. Instead of writing the nearly identical piece of code twice, it makes sense to out-source this code-snippet into a **function** and call this function (with variable parameters if needed) from different parts of the python program.
 +A function will always **return** a value. If the **return** statement is missing the function will return the constant **None**.
 +
 +<note tip>find out more about this topic:
 +  * http://​docs.python.org/​3.1/​tutorial/​controlflow.html#​defining-functions
 +  * http://​www.swaroopch.com/​notes/​Python_en:​Functions
 +</​note>​
 +
 +=== sinppet015.py ===
 +
 +Snippet015.py is just a demonstration step for the coming dragon004.py
 +
 +download snippet017: {{:​en:​part1:​snippet017.py|}}
 +<code python>
 +#filename: snippet017.py
 +def getanswer(acceptable=[]):​
 +    """​asking the user for an answer. adds "​q"​ to the list of acceptable answers.
 +    returns the accepted answer or ask again."""​
 +    acceptable.append("​q"​)
 +    localanswer = "​something stupid" ​ # assign a unacceptable value to localanswer
 +    while localanswer not in acceptable: ​
 +        localanswer = input("​press q and ENTER to quit or the corresponding number and ENTER:"​)
 +    return localanswer
 +
 +# --- the program start here ---
 +print("​You are Sir Robin, the young knight. Your way is blocked by an angry dragon."​)
 +print("""​What do you do now ?
 +1...wait
 +2...fight
 +3...run away"""​)
 +myanswer = getanswer(["​1",​ "​2",​ "​3"​]) # call the function getanswer, store the return value in myanswer
 +</​code>​ |
 +
 +----
 +
 +**line by line code sinppet discussion**
 +<code python>#​filename:​ snippet017.py</​code>​
 +A comment. Note that snippets are not meant to run stand-alone and will later be merged into an meaningful code example.
 +<code python>​def getanswer(acceptable=[]):</​code>​
 +Each **function** ​ must start with the command **def**, followed by the function name and a pair of round brackets <​key>​(</​key><​key>​)</​key>​
 +Inside the round brackets can be one or more optional parameters. In this example, //​acceptable//​ is a parameter.
 +If the function call forget to submit an parameter, the function default the parameter to the value right of the equal sign. In this case, the default value for //​acceptable//​ is an empty list. Remember, lists have the square brackets.
 +<code python> ​   """​asking the user..."""</​code>​
 +A function can have an //​docstring//​. If the docstring is more than one line long, he need to be contained in triple quotes. The docstring is very helpful for automatic generated helpfiles and help functions of the program editor. Basically, the docstring tells the human reader what the function is supposed to do.
 +<code python> ​   acceptable.append("​q"​)</​code>​
 +Heavy stuff ! Instead of forcing the function call to always insert a <​key>​q</​key>​ in the argument list of acceptable answers, i instead simply **append** ​ an <​key>​q</​key>​ to the acceptable list. This is not necessary, but it is always a good idea to make the function as clever and comfortable as possible instead of reuqiring lots of intellectual effort at each function call.
 +<code python> ​   localanswer = "​something stupid"</​code>​
 +All variables have an scope where they are valid. Variables first assigned inside a **function** "​live"​ only inside this function and are not known outside the function. If you want to make a variable to be known outside the function as well, you need the **global** command.
 +Because //​localanswer//​ will soon be used in a test it is necessary to assign an (not acceptable) value to the variable.
 +<code python> ​   while localanswer not in acceptable:</​code>​
 +A while loop (inside the function) with a condition that is True at first: "​someting stupid"​ is most likely not an acceptable answer (an element of the list //​acceptable//​),​ meaning the while condition remains **True**, and python continues with the next //​indented//​ line.
 +<code python> ​       localanswer = input("​press..."​)</​code>​
 +Where the player is asked to give input:
 +<code python> ​   return localanswer</​code>​
 +Until his answer is acceptable. This answer will be **returned** to the function call.
 +<code python># --- the...</​code>​
 +Comment to make it clear that we are not inside a function now. we are in the main program now.
 +<code python>​myanswer = getanswer(["​1",​ "​2",​ "​3"​]) # call..</​code>​
 +A lot happens in this single line. Note the comment after the <​key>#</​key>​ sign:
 +The variable //​myanswer//​ is assigned a value.
 +The value is generated from the **function** //​getanswer//​. As soon as //​getanswer//​ has received an answer from the player, this answer is **return**ed and instantly assigned to the variable myanswer. This is called a //function call//. Note that the variable //​localanswer//​ is not visible outside the function //scope//.
 +The function //​getanswer//​ is called with an //​parameter//,​ a list of acceptable answers. Note that q is not in this list, because //​getanswer//​ adds q to the list independently.
 +This is only a snippet and lots of code is missing here.
 +
 +=== putting it all togehter ===
 +
 +To merge dragon003.py and dragon002.py into an complete playable dragon004.py it is only necessary to combine the commands learned.
 +
 +Let's try it out:
 +
 +=== dragon004.py ===
 +
 +A not very elegant but playable version of the dragon adventure game with two nested while loops:
 +download code example 018: {{:​en:​part1:​dragon004.py|}} ​
 +<code python>
 +# filename: dragon004.py
 +def getanswer(acceptable=["​1","​2","​3"​]):​
 +    """​asking the user for an answer. adds "​q"​ to the list of acceptable answers.
 +    returns the accepted answer or ask again."""​
 +    acceptable.append("​q"​)
 +    localanswer = "​something stupid" ​ # assign a unacceptable value to localanswer
 +    while localanswer not in acceptable: ​
 +        localanswer = input("​press q and ENTER to quit or the corresponding number and ENTER:"​)
 +    return localanswer
 +# --- the program start here ---
 +# -- assign values to variables
 +situation1=("​You are Sir Robin, the brave knight. Your way is blocked by an angry dragon."​)
 +options1=("""​What do you do now ?
 +1...wait
 +2...fight
 +3...run away"""​)
 +situation2=("​You fight the dragon!"​)
 +options2="""​Where do you want to attack the dragon?
 +1...attack the dragon'​s head
 +2...attack the dragon'​s belly
 +3...attack the dragon'​s tail
 +4...retreat away from the dragon
 +q...quit the game"""​
 +belly = False # the dragon is very healthy yet
 +head = False
 +tail = False
 +gameOver = False 
 +# --- the main loop ---
 +print(situation1)
 +while not gameOver:
 +    print(options1)
 +    myanswer = getanswer()
 +    if myanswer == "​q":​
 +        gameOver = True 
 +    elif myanswer == "​1":​
 +        print("​nothing happens, the dragon also wait")
 +        # continue #
 +    elif myanswer == "​2":​
 +        print("​You bravely decide to fight the dragon."​)
 +        # ----- dragon fight loop ----
 +        print(situation2)
 +        while not (belly and head and tail):
 +            print(options2)
 +            myanswer = getanswer(["​1","​2","​3","​4"​])
 +            if myanswer == "​1":​
 +               ​print("​You hit the dragon on the head with your sword!"​)
 +               head = True
 +            elif myanswer == "​2":​
 +               ​print("​You inflict an ugly wound on the dragon'​s belly"​)
 +               belly = True
 +            elif myanswer =="​3":​
 +               ​print("​You hack a deep wound in the dragon'​s tail")
 +               tail = True
 +            elif myanswer =="​4":​
 +               ​print("​You carefully retreat some steps away from the dragon"​)
 +               ​print(situation1) #return to the main loop
 +               break # leave the dragon loop 
 +            elif myanswer =="​q":​
 +               ​gameOver = True                  ​
 +               break # leave the dragon loop and leave main loop
 +        else:
 +            # dragon loop was leaved correctly
 +            print("​The dragon bleeds from head, tail and belly and runs away.\n"​
 +                  "You are victorious! Congratulation,​ you have won the game")
 +            gameOver = True #leave the dragon loop correctly ​
 +    elif myanswer == "​3":​
 +        print("​You run away, but the dragon is faster than you.\n"​
 +              "The dragon eat you. Game Over")
 +        gameOver = True
 +print("​Bye-Bye,​ thanks for playing"​)
 +</​code> ​
 +
 +----
 +
 +**line by line discussion or why {{:​en:​part1:​dragon004.py|}} is ugly**
 +
 +<code python># filename: dragon004.py</​code>​
 +A comment, as always more meaningful for us humans than for the computer.
 +<code python>​def getanswer(acceptable=["​1","​2","​3"​]):</​code>​
 +The function //​getanswer//​ is **def**ined here.
 +The default value of the parameter //​acceptable//​ is set to the most common value, a list containing the numbers (as strings!) from 1 to 3.
 +<code python># --- the program start here --</​code>​
 +The program start here after all funcions (we had only one) are defined
 +<code python>​options1=("""​What do you ..."""</​code>​
 +Multi-lined text variables don't become prettier when defined later in indented code so i define them right here. Note the split between situation description and options for the player.
 +<code python>​gameOver = False </​code>​
 +The //boolean// variable //​gameOver//​ controls the main loop of the game. The game runs until gameOver becomes True.
 +<code python>​print(situation1)</​code>​
 +Note that the situation is described //before// the main loop repeat itself. This helps to make the output less confusing if a player decide to wait several turns.
 +<code python>​while not gameOver:</​code>​
 +Alternatively,​ this line could be written: {{:​en:​part1:​snippet019.py|}}<​code python>​while not gameOver == True:</​code>​
 +<code python> ​   myanswer = getanswer()</​code>​
 +Thanks to clever defaulting (in the **def**ination of the function //​getanswer//​ it is not necessary to pass any parameter to the function at all.
 +<code python> ​   if myanswer == "​q":​
 +        gameOver = True </​code>​
 +The "​emergency exit" from the game will leave the main loop and thus the game.
 +<code python> ​   elif myanswer == "​1":​
 +        print("​nothing happens..."​)
 +        # continue</​code>​
 +A single **continue** statement would return to the beginning of the current loop immediately. This is not necessary here (thus the **continue** line is out-commented) but it would work.
 +<code python> ​       while not (belly and head and tail):</​code>​
 +While still in the main game loop, python now start a second //nested// loop, the dragon fighting loop:
 +<code python> ​           myanswer = getanswer(["​1","​2","​3","​4"​])</​code>​
 +The default parameter of //​getanswer//​ is ["​1","​2","​3"​]. Because a 4th option (retreat) is possible during the fight, the whole acceptable list must be handed as parameter at the function call.
 +<code python> ​              ​print(situation1)</​code>​
 +Because the player leave the dragon fight loop and return to the main loop, the description1 is printed again.
 +<code python> ​              ​gameOver = True</​code>​
 +By setting //​gameOver//​ to **True** before breaking out of the dragon loop, the main loop will also be leaved.
 +<code python> ​       else:
 +            # dragon loop was leaved correctly
 +            print("​The dragon bleeds..."​)</​code>​
 +This **else** part will only be computed if the dragon fight loop was leaved correctly (by beating the dragon)
 +<code python> ​   elif myanswer == "​3":​
 +        print("​You run away..."​)</​code>​
 +What is that ? it is part of the main loop. For coding beauty, it would make sense to code this branch before the dragon fight branch.
 +<code python>​print("​Bye-Bye,​ thanks for playing"​)</​code>​
 +This last line is not part of any loop and will always be printed, no matter how the player leave the game (winning, loosing or quitting)
 +
 +Congratulation,​ you now have a playable game. While it is possible to expand the game (coding more decicions, options and nested while loops), the code of the game will soon become very confusing to read (for us humans, not for the computer), with lots of very indented lines and several (nested) while loops.
 +This approach is called [[wp>​procedural programming]] and can be good described by (a painted) [[wp>​flow chart]].
 +
 +The program (game) logic is like a flow or river computed directly into the code.
 +
 +However, there exist another program paradigma, the data -driven programming (leading to object orientation). By rebuilding the code of the example above in the [[:​en:​part1:​step003|next page]], i will show you how to put much of the game logic into the game data (such as the text variables //​situation1//,​ //​options2//​ etc.) itself and only maintaining a very small main-loop. ​
 +
 +------
 +
 +
 +
 +^ [[en:​part1:​step001| ← previous]] [[en:start| ↑ Overview]] ^ [[:​en:​part1:​step003| → next ]] ^
/var/www/horst/thepythongamebook.com/data/pages/en/resources/people/jens_horst/part1step002.txt · Last modified: 2014/01/09 11:07 (external edit)