2020 Sep 28

Creating a Simple Game in Python

Gaming is a great part of a life. Diving into the virtual competition against enemies, puzzles, time is a good way to spend your evening in a cozy environment with a cup of a favorite beverage. Back in 2014 I was keen to learn new stuff, I was younger and more naïve. I could have tried to learn some programming languages ending up with a basic knowledge, zero practice and no real outcome. Python is still pretty good for the sysadmin job, but anyway this post is about the way of having the simple game in your command line.

As mentioned above, this script was written in 2014. It might be awful up to the current guidelines, and I would be really glad for the feedback, I have just tested it working before the publication. In general, we have a simple game of sticks for 2 players (player vs the PC). Each competitor should take 1, 2 or 3 sticks till there are none left. That, who has taken the last stick is the one to lose the game.
 

#!/usr/local/bin/python3
# coding=utf-8
from random import randint
from time import sleep

def sticks_amount():
    '''Let's decide the amount of sticks for a game'''
    amount = ' '
    while type(amount) != int:
        print ("With how many sticks do you want to play?")
        amount = input()
        try:
            amount = int(amount)          
        except ValueError:
            print ("Oops!  That was no valid number.  Try again...")
    if amount > 9 and amount < 43:
        return int(amount)
    else:
        print ("Impossible amount, we will play with the default amount of sticks (20)")
        return 20

def again():
    '''We just ask a person for another game'''
    global amount
    print("Do you want to play again?")
    if input().lower().startswith('y'):
        amount=sticks_amount()
        print ("Left:"+amount*" |", amount)
        game()
    else:
        print ("Thanks for playing")
        print()
        sleep(0.5)
        quit()

def game():
    '''Just what we need to grab sticks'''
    global amount
    move = 0
    while move not in [1,2,3]:
        print ("How many sticks do You want to take? (Only 1, 2 or 3)")
        move = input()
        try:
            move = int(move)
        except ValueError:
            print ("Oops!  That was no valid number.  Try again...")
    amount = amount - move
    if amount <= 0:
        print ("You have lost!")
        #quit()
        again()        
    print ("Left:"+amount*" |", amount)
    pc_move()
    return amount

def pc_move():
    '''Game AI'''
    global amount
    if amount > 1 and amount < 5:
        amount = 1
        print("So, I move")
        print ("Left: |", amount)
    elif amount%4 == 0 and amount > 1:
        amount -= 3
        if amount <= 0:
            print ("I have lost!")
            again()
        print("So, I move")
        print ("Left:"+amount*" |", amount)
    elif (amount-1)%4 == 0:
        amount -= randint(1,3)
        if amount <= 0:
            print ("I have lost!")
            #quit()
            again()
        print("So, I move")
        print ("Left:"+amount*" |", amount)
    else:
        small = amount
        while small > 4:
            small -= 4
        amount -= (small-1)
        if amount <= 0:
            print ("I have lost!")
            #quit()
            again()
        print("So, I move")
        print ("Left:"+amount*" |", amount)
    game()
    return amount
amount=sticks_amount()
print ("Left:"+amount*" |", amount)
game()

Let's review the code together. Lines 1-2 are more optional, especially in the spotlight of Python 2 EOL. I guess all modern interpreters should recognize not only the path to python3, but also will accept the encoding. UTF-8 is the default one, I had a habit to make it compatible withing different locales (not as much as with different OS).

Lines 3-4 are to import the modules. Technically you can import the complete module, but that will use more resources, and we are willing to be productive - so that why we can just import some attributes.

The following def is to determine an amount of sticks you want to play:

def sticks_amount():
    '''Let's decide the amount of sticks for a game'''
    amount = ' '
    while type(amount) != int:
        print ("With how many sticks do you want to play?")
        amount = input()
        try:
            amount = int(amount)          
        except ValueError:
            print ("Oops!  That was no valid number.  Try again...")
    if amount > 9 and amount < 43:
        return int(amount)
    else:
        print ("Impossible amount, we will play with the default amount of sticks (20)")
        return 20 

It doesn't accept attributes, just returns an integer. The try-except code checks if the typed string could be converted to an integer without an error. If it fails the user is asked to enter the amount again. This prevents the game crash. If the value is correct we can proceed with a game. Additional check is for the amount of sticks: there is no logical reason to have them less than 9, 43 I guess is just a relatively big amount of sticks to fit that screen's resolution (and not to get bored).

The following lines are mostly for the players who are never bored to challenge the PC:

def again():
    '''We just ask a person for another game'''
    global amount
    print("Do you want to play again?")
    if input().lower().startswith('y'):
        amount=sticks_amount()
        print ("Left:"+amount*" |", amount)
        game()
    else:
        print ("Thanks for playing")
        print()
        sleep(0.5)
        quit()

If the reply begins with "y" in upper- or lowercase, you will play again, any other string will just lead to exit in half a second.

The next snippet makes it possible to grab the sticks by a player:

def game():
    '''Just what we need to grab sticks'''
    global amount
    move = 0
    while move not in [1,2,3]:
        print ("How many sticks do You want to take? (Only 1, 2 or 3)")
        move = input()
        try:
            move = int(move)
        except ValueError:
            print ("Oops!  That was no valid number.  Try again...")
    amount = amount - move
    if amount <= 0:
        print ("You have lost!")
        #quit()
        again()        
    print ("Left:"+amount*" |", amount)
    pc_move()
    return amount

We should always have a global amount variable to have a proper number of sticks in the game. You can take only 1 to 3 sticks, any other amount is not accepted, and this is fulfilled with while and try-except. Quit is commented out, so it is non-mandatory for this script to work - you can leave this out. The printing of Left and the pipe sign ("|") above shows the number of sticks in a current game.

The last part of the code determines the game "AI" and basically starts the game (don't forget Python is executed from the top to the bottom). It is a basic logic of this game. It counts the amount of the sticks left and makes sure you are about to lose (in most cases the player loses indeed, sort for the spoiler). There is some randomization in it for sure, bust in most cases you should not allow the PC having 5 sticks on the table before it moves (it's a general advice for this game):

def pc_move():
    '''Game AI'''
    global amount
    if amount > 1 and amount < 5:
        amount = 1
        print("So, I move")
        print ("Left: |", amount)
    elif amount%4 == 0 and amount > 1:
        amount -= 3
        if amount <= 0:
            print ("I have lost!")
            again()
        print("So, I move")
        print ("Left:"+amount*" |", amount)
    elif (amount-1)%4 == 0:
        amount -= randint(1,3)
        if amount <= 0:
            print ("I have lost!")
            #quit()
            again()
        print("So, I move")
        print ("Left:"+amount*" |", amount)
    else:
        small = amount
        while small > 4:
            small -= 4
        amount -= (small-1)
        if amount <= 0:
            print ("I have lost!")
            #quit()
            again()
        print("So, I move")
        print ("Left:"+amount*" |", amount)
    game()
    return amount
amount=sticks_amount()
print ("Left:"+amount*" |", amount)
game()