Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Learning Python Application Development

You're reading from   Learning Python Application Development Take Python beyond scripting to build robust, reusable, and efficient applications

Arrow left icon
Product type Paperback
Published in Sep 2016
Publisher Packt
ISBN-13 9781785889196
Length 454 pages
Edition 1st Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Ninad Sathaye Ninad Sathaye
Author Profile Icon Ninad Sathaye
Ninad Sathaye
Arrow right icon
View More author details
Toc

Table of Contents (12) Chapters Close

Preface 1. Developing Simple Applications FREE CHAPTER 2. Dealing with Exceptions 3. Modularize, Package, Deploy! 4. Documentation and Best Practices 5. Unit Testing and Refactoring 6. Design Patterns 7. Performance – Identifying Bottlenecks 8. Improving Performance – Part One 9. Improving Performance – Part Two, NumPy and Parallelization 10. Simple GUI Applications Index

Using functions – Attack of the Orcs v0.0.5

In the last section, you wrote a quick set of instructions to create a nice little command-line game. You asked your friends to try it out and they kind of liked it (perhaps they were just trying to be nice!). You received the first feature request for the game.

"I think this game has good potential to grow. How about including combat in the next version of the game? When Sir Foo encounters an enemy, he should not just give up that easily. Fight with the enemy! Let the combat decide the winner. "-your friend

Using functions – Attack of the Orcs v0.0.5

You liked the idea and decided to add this capability to the code in the next version. Additionally, you also want to make it more interactive.

The script you wrote for the first program was small. However, as we go on adding new features, it will soon become a maintenance headache. As a step further, we will wrap the existing code into small functions so that the code is easier to manage. In functional programming, the focus is typically on function arrangement and their composition. For example, you can build complicated logic using a simple set of reusable functions.

Revisiting the previous version

Before adding any new features, let's revisit the script that you wrote in the previous version (version 0.0.1). We will identify the blocks of code that can be wrapped into functions. Such code chunks are marked in the two code snippets that follow:

Revisiting the previous version

We will wrap most of the highlighted code into individual functions, as follows:

1:  show_theme_message 
2:  show_game_mission 
3:  occupy_huts 
4:  process_user_choice 
5:  reveal_occupants
6:  enter_hut
Revisiting the previous version

In addition to these six blocks of code, we can also create a few top-level functions to handle all this logic. In Python, the function is created using the def keyword, followed by the function name and arguments in parentheses. For example, the reveal_occupants function requires the information about the huts list. We also need to optionally pass the dotted_line string if we do not want to recreate it in the function. So, we will pass the hut number idx, the huts list, and the dotted_line string as function arguments. This function can be written as follows:

Revisiting the previous version

After this initial work, the original script can be rewritten as:

Revisiting the previous version

This is much easier to read now. What we just did is also referred to as refactoring; more on various refactoring techniques in a later chapter. It makes it easier to do changes to the individual methods. For example, if you want to customize the mission statement or scenario description, you do not need to open the main function, run_application. Similarly, occupy_huts can be expanded further without any clutter in the main code.

Tip

The initial refactored version of the code is not perfect. There is plenty of room for improvement. Can you reduce the burden of passing the dotted_line parameter or think of some other way to handle the printing of bold text?

Pseudo code with attack feature – Version 0.0.5

In the previous section, we wrapped the game logic into individual functions. This not only improved the code readability, but also made it easier to maintain. Let's move on and include the new attack() function in the game. The following steps show the logic of the game with the attack feature included.

While the user wishes to keep playing the game:

  • Print game mission
  • Create a huts list
  • Randomly place 'enemy', 'friend', or 'unoccupied' in 5 huts
  • Prompt the player to select a hut number
  • if the hut has an enemy, do the following:
    • while the user wishes to continue the attack, use the attack() method on the enemy

      After each attack, update and show the health of Sir Foo, and of the enemy too; if enemy health <= 0: print "You Win".

      But, if Sir Foo health <= 0: print "You Lose".

  • else (hut has a friend or is unoccupied) print "you win"

Initially, Sir Foo and the Orc will have full health. To quantify health, let's assign hit points to each of these characters (or the game units). So, when we say the character has full health, it means it has the maximum possible hit points. Depending on the character, the default number of hit points will vary. The following image shows Sir Foo and the Orc with the default number of hit points, indicated by the Health label:

Pseudo code with attack feature – Version 0.0.5

The bar above the Health label in the image represents a health meter. Essentially, it keeps track of the hit points. In the discussion that follows, we will use the terms hit points and health meter interchangeably. During the combat, either the player or the enemy will get injured. For now, neglect the third possibility where both escape unhurt. An injury will reduce the number of available hit points for the injured unit. In the game, we will assume that in a single attack turn only one of the characters is hit. The following image will help you imagine one such attack turn:

Pseudo code with attack feature – Version 0.0.5

Here, Sir Foo's health meter is shown as the maximum and the Orc has sustained injuries!

Pseudo code with attack feature – Version 0.0.5

Hmm, the Orc thinks he can defeat Sir Foo! This is interesting. Let's develop the game first and then see who has a better chance of winning!

With this understanding of the problem, let's review the code that implements this feature.

Reviewing the code

Download the source file, ch01_ex02.py, from the chapter's code bundle and skim through the code. The key logic will be in the attack() function. We will also need a data structure to keep the health record of Sir Foo and the enemy. Let's start by introducing the following utility functions that take care of some print business:

Reviewing the code

Now, look at the main function, run_application, and the supporting function, reset_health_meter. In addition to introducing the dictionary health_meter, we have also encapsulated the game logic in play_game:

Reviewing the code

At the start of a new game, the values of the health_meter dictionary are set back to the initial ones by calling reset_health_meter:

Reviewing the code

Next, let's review the play_game function. If the hut has the enemy, the player will be asked if the attack should be continued (the start of the while loop). Based on the user input, the code calls the attack function or exits the current game:

Reviewing the code

The enemy is attacked repetitively using the interactive while loop, which accepts user input. Execution of the attack function may result in injury to Sir Foo, or the enemy, or both. It is also possible that no one gets hurt. For simplicity, we will only consider two possibilities: a single attack that will injure either the enemy or Sir Foo. In the previous section, we used the built-in random number generator to randomly determine the occupants of the huts. We can use the same technique to determine who gets hurt:

injured_unit = random.choice(['player', 'enemy'])

But hold on a minute. Sir Foo has something to say:

Reviewing the code

We should take into account the chance of an injury to the player and to the enemy. In the attack function shown next, we will assume that for about 60% of the time, the enemy will get hit and for the remaining 40%, it is Sir Foo who is on the receiving end.

The simplest way is to create a list with 10 elements. This list should have six entries of 'enemy' and four entries of 'player'. Then, let random.choice select an element from this list. You can always introduce a difficulty level in the game and change this distribution:

Reviewing the code

Once the injured_unit is selected randomly, the injury is determined by picking a random number between 10 and 15, inclusive. Here, we use the random.randint function. The final important step is to update the health_meter dictionary for the injured unit by reducing its number of hit points.

Running Attack of the Orcs v0.0.5

We have discussed the most important functions in this game. Review the other supporting functions from the downloaded file. The following screenshot shows the game in action:

Running Attack of the Orcs v0.0.5
You have been reading a chapter from
Learning Python Application Development
Published in: Sep 2016
Publisher: Packt
ISBN-13: 9781785889196
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime