Game

Simple fighting game.

Players

First we need player in order for our game to work. Each player is just a set of stats, we group and represent them using dictionaries with the attribute names being strings and their values being their respective type ( integers here).

{'health': 50, 'damage': 5}

We create dicts by wrapping key: value pairs in {}.

Variables

In order to store data somewhere so we can reference and use later we use variables. In this case, we will name our two players in recognisable ways.

Usage

player1 = {'health': 50, 'damage': 5}
player2 = {'health': 50, 'damage': 5}

Our players are identical to begin with.

Damage

Now we need to make the first operation of our game, dealing damage.

Modules

To introduce some level of “randomness”, we use the built-in random module.

Modules are chunks of code that other people have written for our use.

Importing modules can be done with import. In this case, we need its randint function.

from random import randint

Python offers a variety of other built-in modules, we will take look at more of them as we go.

Usage

But for now, let’s deal some damage.

minimum = 1
maximum = player1['damage']

damage_dealt = randint(minimum, maximum)

We assign our minimum and maximum (from our player with the item access [] notation) damage to variables and then pass those in the randint function, creating a random integer and then storing it in the incoming variable.

To avoid redundancy and be a little bit quicker in our code:

damage_dealt = randint(1, player1['damage'])

Instead of storing our min and max in variables, we pass them directly to the function.

Now, all we have to do is deduce this damage from the other player’s health.

old_health = player2['health']
new_health = old_health - damage_dealt
player2['health'] = new_health

Or, we little bit faster:

player2['health'] = player2['health'] - damage_dealt

EVEN FASTER:

player2['health'] -= damage_dealt

All three ways are equivalent with the only significant difference being less lines of code, making the whole thing more compact. Use whichever you are more comfortable with.

Printing

Now we need to show how much damage was dealt and how much health is left.

new_health = player2['health']
message = f'Player 2 took {damage_dealt} damage: {new_health} health left'
print(message)

Aside from normal strings starting and ending with the same type of quotes (single or double), python offers f-strings for quickly formatting/injecting/interpolating data.

In this example, we simply pass our variables in an f-string, storing them in the message variable, which we then print to the console using the built-in print function.

Repeating

All that’s left now is to repeat the exact same process for player2 attacking player1.

damage_dealt = randint(1, player2['damage'])
player1['health'] -= damage_dealt
print(f'Player 1 took {damage_dealt} damage: {player1["health"]} health left')

We don’t need to re-import the randint function, this is done once at the very beginning of our code.

The only notable difference between what we did before and now is printing. Not only did we pass our string directly in print, without using a message variable, we also messaged player1’s health directly.

In order to differentiate between the start-end string quotes and the health string, different quotes had to be used.

Loops

So far, our code looks exactly like this:

from random import randint

player1 = {'health': 50, 'damage': 5}
player2 = {'health': 50, 'damage': 5}

damage_dealt = randint(1, player1['damage'])
player2['health'] -= damage_dealt
print(f'Player 2 took {damage_dealt} damage: {player2["health"]} health left')

damage_dealt = randint(1, player2['damage'])
player1['health'] -= damage_dealt
print(f'Player 1 took {damage_dealt} damage: {player1["health"]} health left')

player1 attacks player2, and vice versa and our program exits. Obviously, we need this to happen multiple times until either of the players falls to-or-bellow 0 health. Or, in other words, we need our program to loop back to the beginning while both players are above 0 health.

Conveniently, this can be done with a while loop.

while player1['health'] > 0 and player2['health'] > 0:
  damage_dealt = ...

Comparisons

Let’s take a look at what’s going on.

player1['health'] > 0

This statement will, unsurprisingly, return True if player1’s health is above 0 health, and False otherwise.

player1['health'] > 0 and player2['health'] > 0

Here we get True if both players’ health is above 0, and False otherwise.

While

Our while loop needs a statement that returns True or False next to it. That statement is executed on every iteration, stopping the loop the moment it evaluates to False.

while player1['health'] > 0 and player2['health'] > 0:
  damage_dealt = randint(1, player1['damage'])
  player2['health'] -= damage_dealt
  print(f'Player 2 took {damage_dealt} damage: {player2["health"]} health left')

  damage_dealt = randint(1, player2['damage'])
  player1['health'] -= damage_dealt
  print(f'Player 1 took {damage_dealt} damage: {player1["health"]} health left')

Anything that is part of the loop’s execution should be indented inward.

Each player’s health will get decreased on each iteration, until at least one is not above 0. The main caveat of this approach the possibility that both players’ health gets reduced bellow 0, resulting in a trade-kill.

Break

To prevent this from happening, we take a slightly different approach.

while True:

  damage_dealt = randint(1, player1['damage'])
  player2['health'] -= damage_dealt
  print(f'Player 2 took {damage_dealt} damage: {player2["health"]} health left')

  if player2['health'] <= 0:
      print('Player 1 wins')
      break

  damage_dealt = randint(1, player2['damage'])
  player1['health'] -= damage_dealt
  print(f'Player 1 took {damage_dealt} damage: {player1["health"]} health left')

  if player1['health'] <= 0:
    print('Player 2 wins')
    break

We create an infinite loop by giving while something that always evaluates to True. That could be 1 > 0, 'hg' == 'hg', or simply True itself.

This allows us sequentially check whether each player’s health is at-or-bellow 0:

if player2['health'] <= 0:
  print('Player 1 wins')
  break

If player2['health'] <= 0 returns True, everything in our if clause (indented code) gets executed; printing who won and then breaking out of the loop.

Recap

And behold our final result.

from random import randint

player1 = {'health': 50, 'damage': 5}
player2 = {'health': 50, 'damage': 5}

while True:

  damage_dealt = randint(1, player1['damage'])
  player2['health'] -= damage_dealt
  print(f'Player 2 took {damage_dealt} damage: {player2["health"]} health left')

  if player2['health'] <= 0:
      print('Player 1 wins')
      break

  damage_dealt = randint(1, player2['damage'])
  player1['health'] -= damage_dealt
  print(f'Player 1 took {damage_dealt} damage: {player1["health"]} health left')

  if player1['health'] <= 0:
    print('Player 2 wins')
    break

Something to consider is that this game is skewed toward player1 since they always strike first ;)