5
\$\begingroup\$

I am trying to get this code on Python 3.6.3 to be:

  1. More efficient

  2. More readable

  3. More simple

This code is supposed to be like hangman, just without the stickman. I also have added code which will count the amount of times you have won, lost and how many times you have played the game.

(I might put a bit of SQLite into this code so it stores how many points the player has, etc.)

However, the code below is extremely long, and I think that it could be greatly shortened.

Here is my code:

from random import randint as r
game_times = 0
if game_times == 0:
    lives = 10
    game = True
    game_wins = 0
    game_losses = 0
    points = 0
space_1 = '__'
space_2 = '__'
space_3 = '__'
space_4 = '__'
space_5 = '__'
word_chooser_easy = (r(0, 5))
while game:
    #this chooses a random word.
    if word_chooser_easy == 0:
        hangman_word = 'later'
        letter_one = 'l'
        letter_two = 'a'
        letter_three = 't'
        letter_four = 'e'
        letter_five = 'r'
    elif word_chooser_easy == 1:
        hangman_word = 'point'
        letter_one = 'p'
        letter_two = 'o'
        letter_three = 'i'
        letter_four = 'n'
        letter_five = 't'
    elif word_chooser_easy == 2:
        hangman_word = 'water'
        letter_one = 'w'
        letter_two = 'a'
        letter_three = 't'
        letter_four = 'e'
        letter_five = 'r'
    elif word_chooser_easy == 3:
        hangman_word = 'joker'
        letter_one = 'j'
        letter_two = 'o'
        letter_three = 'k'
        letter_four = 'e'
        letter_five = 'r'
    elif word_chooser_easy == 4:
        hangman_word = 'maths'
        letter_one = 'm'
        letter_two = 'a'
        letter_three = 't'
        letter_four = 'h'
        letter_five = 's'
    elif word_chooser_easy == 5:
        hangman_word = 'crazy'
        letter_one = 'c'
        letter_two = 'r'
        letter_three = 'a'
        letter_four = 'z'
        letter_five = 'y'
    #now we need to check if the person has won the game.
    if space_1 != "__" and space_2 != "__" and space_3 != "__" and space_4 != "__" and space_5 != "__":
        #print your congratulations for winning
        print("Well done! You have won the game!")
        game_times += 1
        game_wins += 1
        game = False
        continue
    #print the hangman.
    print("This is your hangman:")
    print(space_1 , " " , space_2 , " " , space_3 , " " , space_4 , " " , space_5)
    which_letter = input("Which letter do you want to choose?")
    if letter_one == which_letter:
        #this means the player has guessed space 1 correctly.
        print("Well done! You have guessed it correctly!")
        space_1 = letter_one
    elif letter_two == which_letter:
        #this means the player has guessed space 2 correctly.
        print("Well done! You have guessed it correctly!")
        space_2 = letter_two
    elif letter_three == which_letter:
        #this means the player has guessed space 3 correctly.
        print("Well done! You have guessed it correctly!")
        space_3 = letter_three
    elif letter_four == which_letter:
        #this means the player has guessed space 4 correctly.
        print("Well done! You have guessed it correctly!")
        space_4 = letter_four
    elif letter_five == which_letter:
        #this means the player has guessed space 5 correctly.
        print("Well done! You have guessed it correctly!")
        space_5 = letter_five
    else:
        #this means the player got it wrong.
        print("You were wrong...")
        lives -= 1
        if lives == 0:
            print("Game over...")
            game_losses += 1
            game_times += 1
            game = False
            continue
        else:
            print("You now have" , lives , "lives left...")
else:
    stats = input("Do you want to see your stats so far? y/n")
    if stats == "y":
        print("You have lost" , game_losses , "times, you have won" , game_wins , "times and you have played hangman" , game_times , "times.")
    else:
        pass
    print("Your second game will be one that has more double lettered words in it...")
    lives = 8
    word_chooser_easy = (r(0, 5))
    space_1 = '__'
    space_2 = '__'
    space_3 = '__'
    space_4 = '__'
    space_5 = '__'
    while game:
        #this chooses a random word.
        if word_chooser_easy == 0:
            hangman_word = 'later'
            letter_one = 'l'
            letter_two = 'a'
            letter_three = 't'
            letter_four = 'e'
            letter_five = 'r'
        elif word_chooser_easy == 1:
            hangman_word = 'point'
            letter_one = 'p'
            letter_two = 'o'
            letter_three = 'i'
            letter_four = 'n'
            letter_five = 't'
        elif word_chooser_easy == 2:
            hangman_word = 'water'
            letter_one = 'w'
            letter_two = 'a'
            letter_three = 't'
            letter_four = 'e'
            letter_five = 'r'
        elif word_chooser_easy == 3:
            hangman_word = 'joker'
            letter_one = 'j'
            letter_two = 'o'
            letter_three = 'k'
            letter_four = 'e'
            letter_five = 'r'
        elif word_chooser_easy == 4:
            hangman_word = 'maths'
            letter_one = 'm'
            letter_two = 'a'
            letter_three = 't'
            letter_four = 'h'
            letter_five = 's'
        elif word_chooser_easy == 5:
            hangman_word = 'crazy'
            letter_one = 'c'
            letter_two = 'r'
            letter_three = 'a'
            letter_four = 'z'
            letter_five = 'y'
        #now we need to check if the person has won the game.
        if space_1 != "__" and space_2 != "__" and space_3 != "__" and space_4 != "__" and space_5 != "__":
            #print your congratulations for winning
            print("Well done! You have won the game!")
            game_times += 1
            game_wins += 1
            game = False
            continue
        #print the hangman.
        print("This is your hangman:")
        print(space_1 , " " , space_2 , " " , space_3 , " " , space_4 , " " , space_5)
        which_letter = input("Which letter do you want to choose?")
        if letter_one == which_letter:
            #this means the player has guessed space 1 correctly.
            print("Well done! You have guessed it correctly!")
            space_1 = letter_one
        elif letter_two == which_letter:
            #this means the player has guessed space 2 correctly.
            print("Well done! You have guessed it correctly!")
            space_2 = letter_two
        elif letter_three == which_letter:
            #this means the player has guessed space 3 correctly.
            print("Well done! You have guessed it correctly!")
            space_3 = letter_three
        elif letter_four == which_letter:
            #this means the player has guessed space 4 correctly.
            print("Well done! You have guessed it correctly!")
            space_4 = letter_four
        elif letter_five == which_letter:
            #this means the player has guessed space 5 correctly.
            print("Well done! You have guessed it correctly!")
            space_5 = letter_five
        else:
            #this means the player got it wrong.
            print("You were wrong...")
            lives -= 1
            if lives == 0:
                print("Game over...")
                game_losses += 1
                game_times += 1
                game = False
                continue
            else:
                print("You now have" , lives , "lives left...")
\$\endgroup\$
  • \$\begingroup\$ You should also add some explanation what this code achieves in the description. \$\endgroup\$ – Graipher Jan 9 '18 at 12:42
6
\$\begingroup\$

Well done

There are some obvious beginner mistakes, but you have created a working game.

Avoid working in the global namespace

game_times = 0
if game_times == 0:
    lives = 10
game = True
game_wins = 0
game_losses = 0
points = 0
  • These should not be global, but be part of a setup function
  • There are 0! functions in your code. The code could improve a lot, simply by splitting your code into functions
  • Since these are currently globals, they should be written with ALL_CAPS

DRY:

Don't repeat yourself

You do this quite alot, for instance:

space_1 = '__'
    ...
  • Those spaces are all the same, a single space_char = '__' would suffice
word_chooser_easy = (r(0, 5))
if word_chooser_easy == 0:
   word = "later"
   ...
  • choice is more python then randInt
  • Don't import like import random as r, but import what you need from random import choice

With random.choice you can quite literally choose a random item from a list

>>> from random import choice
>>> words = ["word_1", "word_2"]
>>> random_choice = choice(words)
letter_one = 'c'
letter_two = 'r'
letter_three = 'a'
letter_four = 'z'
letter_five = 'y'
...
if letter_one == which_letter:
    #this means the player has guessed space 1 correctly.
    print("Well done! You have guessed it correctly!")
    space_1 = letter_one
  • in Python almost anything is iterable.

This could be solved in different ways.

>>> string = "word"
# String are iterable
>>> print(string[0])
w
# However not assignable
>>> string[0] = "k"
TypeError: 'str' object does not support item assignment
# Lastly you can check if a char is in a string with the in keyword
>>> print("w" in string)
True

You could save the currently_guessed word in a list to make it more mutable

  1. You can first fill the current_guess list with SPACE chars, that will work as non guessed.
  2. If the user input letter is in the word to guess. You can loop over the string with enumerate() and fill the place in the list where letter matches.
  3. As a return you can check if they are all filled(not SPACE chars) nicely with the all() keyword

Miscellaneous

  • Use a guard for all your scripts
  • Use format() or f"" over print concat
  • If you ever start writing functions, don't forget writing docstrings ;)

Simplified code

from random import choice

WORDS = ["real", "checkers", "cheese", "baboon"]
SPACE = '_'

def hangman(correct_word=None, lives=10):
    """Simple hangman game.

    Keyword arguments:
    correct_word -- the word to guess (default: a random word from WORDS)
    lives -- the amount of lives (default: 10)

    Returns:
    True: if the word was guessed
    False: if out of lives"""

    if correct_word is None:
        correct_word = choice(WORDS)

    current_guess = [SPACE for _ in correct_word]

    while True:    
        print("You have {} lives left".format(lives))
        print(' '.join(current_guess))
        letter = input("Pick a letter: ")

        if letter in correct_word:
            for idx, char in enumerate(correct_word):
                if char == letter:
                    current_guess[idx] = letter
        else:
            lives -= 1

        if all(char != SPACE for char in current_guess):
            return True

        if lives < 0:
            return False

if __name__ == '__main__':
    if hangman():
        print("You won")
    else:
        print("Out of lives")
    # or after @Graiphers suggestion you can play the game with a predefined word or lives
    # hangman("randomword", 5)
\$\endgroup\$
  • 1
    \$\begingroup\$ Nice clean up of OP's code. Two comments: I would be explicit and import random and later do random.choice (it is more obvious what is happening IMO). And I would make the word to guess an argument of game and only choose it in the guard clause. This allows playing the game with any word. \$\endgroup\$ – Graipher Jan 9 '18 at 15:22
  • \$\begingroup\$ I've edited your second suggestion, however my preference goes too from x import y especially with small snippets of code, to lessen the import load \$\endgroup\$ – Ludisposed Jan 9 '18 at 15:42
  • \$\begingroup\$ Fair enough. There is always a trade-off involved. For random I usually prefer the explicit call, personally, but YMMV. \$\endgroup\$ – Graipher Jan 9 '18 at 16:36
2
\$\begingroup\$

I am not experienced with python, sorry for that, but you will understand my pseudo-code:

Instead of having 6 if conditional blocks, have an array of 6 words:

var Words[] = ["later", "point", "water", "joker", "maths", "crazy"]

then you make a random number from 0 to 5 and use that to select from the array of words:

var random = (r(0, 5));
hangman_word = Words[random];

Now for the letters: instead of having 6 variables for each letter, don't have it at all. You have the variable hangman_word. :)

But what about spaces? Just create a new string that has same length as the chosen word. Something like that:

var spaces = "";
for(int i=0; i<hangman_word.length; i++){
   spaces += "-";
}

for checking if letter chosen by user is in the word just do:

which_letter = input("Which letter do you want to choose?");

boolean found = false;
for(int i=0; i<hangman_word.length; i++){
      if(hangman_word[i] == which_letter){
       //EG: so from "-----", it will eventually go to "J-KE--", and "JOKER"    

          spaces[i] = which_letter; 
          found = true; // dont forget that we found it :)
      }
}

//if we didn't find it, well we didn't find it.

if(found == false){
         "no such letter in word, sorry";
     }else{ 
          "you have guessed it!" 
          }

These are just some basic ideas. After you will understand and do all this, your code will become more flexible. I'd recommend you to rewrite your game, considering that now you have more experience.

PS: also same logic will easily apply for next level of game etc.

EDIT:

I wrote this on c++. This is best I can do :d

#include <iostream>
#include <stdlib.h>     
#include <time.h>       

using namespace std;

string Words[6] = {"later", "pointeryeah", "water", "joker", "maths", "crazy"};


int main()
{
  int random_index;
  int lives = 6, guesses = 0;

  char guess_letter;
  bool won = false;

  srand (time(NULL));
  random_index = rand() % 5;

  string chosen_word = Words[random_index];

  string spaces = "";
  for(int i=0; i<chosen_word.length(); i++){
    spaces += "-";
  }

    while(lives>0 && !won){

        cout<<"This is your word: "<<spaces<<" Try to guess!"<<endl;
        cin>>guess_letter;

        bool found = false;
        for(int i=0; i<chosen_word.length(); i++){
              if(chosen_word[i] == guess_letter){
                  spaces[i] = guess_letter; 
                  found = true; 
              }
        }
        if(!found){
            cout<<"You didn't guess. ";
                    lives--;
        }
        else{
            cout<<"GJ you guessed! ";
            guesses++;

            if(guesses == chosen_word.length())
                won = true;
        }


    }

    if(won)
        cout<<"you won!";
    else
        cout<<"you lost!";

    return 0;
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Before you downvote, please consider commenting reason too. \$\endgroup\$ – Nick Jan 10 '18 at 5:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.