7
\$\begingroup\$

I'm a 16 year old who has picked up coding recently using the codecademy course on Python. I completed the last of the lessons yesterday and decided to start on a simple Hangman game. As this is my first free-form project, it took me around 7h to finish it (a number i'm not proud of, i admit).

Here is the main body:

import string
import Hidden_word

try_again = 'y'

while try_again == 'y':
    word = Hidden_word.HiddenWord()
    hidden_word = word.hide_word()
    shown_word = word.show_word()
    chances_left = int(len(shown_word) / 2 + 1)
    misses = 0
    used_letters = []

    print("Here is the hidden word:", ' '.join(hidden_word))
    print("You have %d tries" % chances_left)

    while chances_left > 0:
        letter = input("Choose a letter: ").lower()
        while True:
            if not letter in string.ascii_lowercase or letter == '':
                letter = input("Please provide a valid answer: ").lower()
            elif letter in used_letters:
                letter = input("You've already used this letter, try another one: ").lower()
            else:
                used_letters.append(letter)
                break

        if letter in shown_word:
            print("Bingo!")
            for x in range(len(shown_word)):
                if shown_word[x] == letter:
                    hidden_word[x] = letter
            print(' '.join(hidden_word))
        else:
            chances_left -= 1
            if chances_left > 0:
                print ("Whoops, there is no '%s' in this word, try again! (%d chance(s) left)" % (letter, chances_left))
                print(' '.join(hidden_word))
                misses += 1

        if ''.join(hidden_word) == shown_word:
            if misses == 0:
                print("Congratulations! You did it without missing a single time!")
            else:
                print("Congratulations! You did it! But you've missed %d time(s)" % misses)
            break
        elif chances_left == 0:
            print("There's no '%s' in this word. You've got no tries left" % letter)
            print("The word was:", shown_word)

    try_again = input("Would you like to try again ? (y/n)").lower()

    while not try_again.lower() in ('y', 'n'):
        try_again = input("Please provide a valid answer: ")
print("Good bye!")

and here is the hidden_word class:

import linecache
import random

def number_lines ():
    with open("Words.txt", 'r') as file:
        for i, l in enumerate(file):
            pass
        return i + 1

class HiddenWord(object):
    hidden_word = []

    def __init__(self):
        self.shown_word = linecache.getline("Words.txt", random.randint(1, number_lines()))[:-1]

    def show_word (self):
        return self.shown_word

    def hide_word(self):
        self.hidden_word = []
        for x in self.shown_word:
            if x == ' ':
                self.hidden_word.append(' ')
            else:
                self.hidden_word.append('*')
        return self.hidden_word

I made sure to check all the possible cases, and it works perfectly without a hitch.

\$\endgroup\$
  • \$\begingroup\$ Welcome to Code Review, and nice work! For completeness, please post your linecache as well. \$\endgroup\$ – 200_success Jul 14 '17 at 1:13
1
\$\begingroup\$

First, I'll mark a couple of things:

Parsing variables to strings.

You should just choose a form to parse variables into strings and stick with it.

print("Here is the hidden word:", ' '.join(hidden_word))
print("You have %d tries" % chances_left)

You're using .join and %d, %s to print variables. I suggest you to just use format (like I've done in the sample code), because you don't have to worry about parsing data. It allows you to be cleaner and has powerful options. Plus, % formatting is deprecated as far as I know.

The .join function is useful when you're using it to create a new string from a couple of different strings. Else, use format.

Classes and objects.

In your code, you're using a class with "only" a constructor.

The method show_word is kind of useless in Python, because you can access it directly, no need for a method to receive the element. The method hide_word is used only one time. It should be called from the constructor and use it to create hidden_word.

The main.py code is just functional programming. You should use methods to make it cleaner and easier to read. Plus, you're just using your class to pass the elements from it to the while loop in the main, instead of using it as a class.

My final suggestion is that you look for Object Oriented Programming tutorials and examples, since you're using it very poorly and badly. Don't worry, you'll improve over time :) Take a look to PEP8 style guide for Python too, it will help you to write cleaner and more readable.

I leave you this code as a suggestion, try to look for everything you don't understand.

import linecache
import random


class HiddenWord():

    def __init__(self, word):
        """Gets a word and turns it into a list. Then hides it as another list in hidden_word"""
        self.word = list(word.upper())
        self.hidden_word = []
        for letter in self.word:
            if letter == " ":
                self.hidden_word.append(" ")
            else:
                self.hidden_word.append('*')

    def check_letter(self, letter):
        """Checks if the letter received is in the word. If it is,
           it will make it visible in the hidden word, and will return true.
           If it isn't, it will just return false."""
        letter = letter.capitalize()
        if letter in self.word:
            for index in range(len(self.hidden_word)):
                if(self.word[index] == letter):
                    self.hidden_word[index] = letter

            return True

        return False


class Game():
    def number_lines(self):
        """Gets the number of lines that the txt has"""
        num_lines = sum(1 for line in open('Words.txt'))
        return num_lines

    def printInfo(self):
        """Shows by console tries left, the hidden word and the used letters"""
        print("Tries left: {}".format(self.chances_left))
        print("Hidden word: {}".format(self.hw.hidden_word))
        print("Used letters: {}".format(self.used_letters))

    def __init__(self):
        """Gets a word from the .txt and initialises the hidenword class"""
        word = linecache.getline("Words.txt", random.randint(1, self.number_lines()))[:-1]
        self.hw = HiddenWord(word)
        self.chances_left = int(len(self.hw.word) / 2 + 1)
        self.used_letters = []
        self.misses = 0

    def gameFinish(self):
        """Check if the player has won"""
        if (self.hw.hidden_word == self.hw.word):
            return True

        return False

    def play(self):
        """Main game"""
        while(self.chances_left > 0 and not self.gameFinish()):
            self.printInfo()
            letter = ""
            while(not letter or letter in self.used_letters):
                letter = input("Choose a letter: ")

            self.used_letters.append(letter)

            if(self.hw.check_letter(letter)):
                print("Bingo! That letter is in the word.")
            else:
                print("That letter is not in the word.")
                self.misses += 1
                self.chances_left -= 1

            if(self.gameFinish()):
                if(self.misses == 0):
                    print("Congratulations! You did it without missing a single time!")
                else:
                    print("Congratulations! You did it! But you've missed {} time(s)".format(self.misses))
                break

        print("You lost. The word was {}.".format(self.hw.word))


if __name__ == '__main__':
    """Main loop"""
    try_again = 'y'
    while try_again == 'y':
        game = Game()
        game.play()

        try_again = input("Would you like to try again ? (y/n)").lower()

        while not try_again.lower() in ('y', 'n'):
            try_again = input("Please provide a valid answer: ")

    print("See you!")
\$\endgroup\$

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.