I tried to create a "guess the word" game. I would appreciate to get some suggestion to improve myself, because I'm new at Python.
from random_word import RandomWords
import random
from translate import Translator
import time
import sys
def hangman():
SENTINEL = 1
lang = input('What language do you choose?\nit, es, en, etc..\n>: ')
while SENTINEL == 1:
hints = 3
answers = {'Yes':1, 'No':0}
source = RandomWords()
word = source.get_random_word()
translator= Translator(to_lang = lang) #translates every word to a choosen language
itWord = translator.translate(word).lower()
print('Hello everybody and Welcome to the hangman game! Try guessing the right word before finishing your possibilities!')
time.sleep(1) #I added time sleep just for slowing some parts
print('Ready?')
time.sleep(1)
print('Go')
time.sleep(1)
lenght = len(itWord) + 1 #get the lenght of the picked word
choice = int(lenght*(3/2)) #possibilities depend by the word lenght
showIt = '_'*(lenght-1)
newIt = show_it(showIt)
showIt = list(newIt.split()) #creates a list that can be modified easier
choices = [] #creates an empty list that has to be filled with the used letters/words
print('The word has lenght', lenght,'.\nYou can call the list of used letters by writing "list", exit from the game by writing "exit", or try to guess the word, by writing first "guess"')
print('Write "help" to get some hints: but you have just 3 of it!')
while choice >= 1:
old = choice #preserves the remained chances
time.sleep(1)
print('You have', choice, 'possibilities and', hints,'hints. Try it up!\n', newIt)
guess = (input('>: ')).lower()
if guess == 'help': #help is needed to get hints
if hints == 0:
print('Sorry, you don\'t have anymore hints')
continue
else:
guess = random.choice(itWord)
while guess in newIt: #this is needed to get a letter that was not choosen
guess = random.choice(itWord)
hints -= 1 #decreases the number of hints
if guess in choices: #checks if the guessed letter was not choosen yet
print('You\'ve already used this letter/word. Please choose another one')
continue
else:
try:
if len(guess) == 1 :
if hints == 3 : choices.append(guess) #it adds just the letter guessed by the user and not randomly picked by the game
elif guess != 'help' and guess != 'exit' and guess != 'guess' and guess != 'list': raise ValueError
except ValueError:
print('Please choose a letter, not a word')
continue
if guess == 'list': #needed to get the list of words/letters used
print(choices)
time.sleep(1)
continue
elif guess == 'exit':
sys.exit(print('Thanks for the game'))
#this closes the game
elif guess == 'guess': #this option is for trying guessing the entire word
guess = input('>: ')
if guess == itWord: #if the word is right it puts choice to 0 to go through the next while loop(But the choice value is preserved in the 'old' variable seen before)
newIt = guess
print('You did it!')
choice = 0
else: #if the word is not right it decreases the possibility
print('No way, retry')
choice -= 1
continue
elif guess in itWord.lower(): #if the guessed letter belongs to the randomly picked word, the program gets the index of the letter in it, the number of it and replaces the guessed letter in the right place of the showIt list
index = itWord.index(guess)
lettCount = itWord.count(guess) - 1
showIt[index] = guess
while lettCount != 0: #if there is more than one guessed letter in the randomly picked word, the program does the same thing as before for all of them
index = itWord.index(guess, index +1)
showIt[index] = guess
lettCount -= 1
newIt = show_it(showIt)
else:
time.sleep(1)
print('Sorry, you wrong. Retry!')
choice -= 1
if '_' not in newIt:
#This removes all the spaces in newIt
newIt = remove_spaces(newIt)
print('All right, you found the word!', newIt.lower())
choice = 0
while choice == 0 :
#the old variable preserves all remained possibilities. The different answers depends by old value
time.sleep(1)
if old == 0: print('Sorry, you used all your possibility')
time.sleep(1)
print('Do you want to restart the game?\n Yes/No')
choose = input('>: ').capitalize()
#from this point on, the user has the opportunity to restart the game with the previous word(if not guessed) or not, or close it
try:
SENTINEL = answers[choose]
if SENTINEL == 1:
print('Do you want to use the previous word?\n Yes/No')
choose = input('>: ').capitalize()
if choose == 'Yes':
choice = int(lenght*(3/2))
choices.clear()
elif choose == 'No': choice, SENTINEL = -1, 1
else: SENTINEL, choice = 0, -1
except KeyError:
print('Please, insert a correct answer')
choice = 0
sys.exit(print('Thanks for the game'))
def show_it(word1):
#The function creates dashes format like _ _ _
newIt = ''
for x in word1: newIt = newIt + x + ' '
newIt = newIt.rstrip(' ')
return newIt
def remove_spaces(word):
string = ''
for x in word:
if x != ' ': string += x
return string
1 Answer 1
Few things that I think will help ya in the long run...
multi_line_string = """
Do you want to use the previous word?
Yes/No
"""
print(multi_line_string)
Multi-line strings maybe assigned via triple quote (either """
or '''
) blocks; having the stray apostrophe becomes no big deal. Furthermore one can utilize dedent
from textwrap
while print
ing such that the flow isn't broken...
from textwrap import dedent
some_string = """
Sorry, you've used all available possibilities!
... taking a nap...
"""
print(dedent(some_string))
Functions/Methods (def
initions) are super useful for repeated snippets of code...
from textwrap import dedent
from translate import Translator
to_lang = 'en'
translator = None
if to_lang != 'en':
translator = Translator(to_lang = to_lang)
def accessibility(msg, **kwargs):
"""
Side note, this is a `__doc__ string` that _documents_
how something is intended to be used. And is accessible
via commands such as;
print(accessibility.__doc__)
help(accessibility)
This is a shortcut for formatting and then translating
passed `msg` string prior to `return`ing.
"""
if kwargs:
msg = msg.format(**kwargs)
if translator:
msg = translator.translate(msg)
return msg
def whats_wanted(msg, **kwargs):
"""
Simple short-cut for getting user input while also
translating `msg` if necessary.
"""
return input(accessibility(msg, **kwargs))
## ... also do __not__ be afraid of blank lines, two between
## classes and functions, and one between blocks and/or
## where it makes since to do so is the _rule of thumb_
## that I use when writing. Also it's a good idea to
## avoid comment blocks of this length, keep things _tight_
## and use `__doc__ strings` to avoid feeling the need for'em ;-)
the_question = "Shall we continue {user}?"
an_answer = whats_wanted(the_question,
user = 'yourName here')
## ... Note, defaulting instead of else-ing on a single line
## often looks _cleaner_ when re-reading code later.
the_answer = an_answer
if translator:
reverse_translator = Translator(to_lang = 'en')
the_answer = reverse_translator.translate(an_answer)
if the_answer.lower() == 'yes':
msg = accessibility("I think I heard a 'yes' from {user}",
user = 'yourName here')
else:
msg = accessibility('What are you talking about?')
print(msg)
The try
blocks may need a little rewriting, following is a starting point...
## ... Other code trimmed...
if old == 0:
_msg = """
Sorry, you used all your possibility
Do you want to restart the game?
Yes/No
"""
print(textwrap.dedent(_msg))
choose = input('>: ').capitalize()
# from this point on, the user has the opportunity
# to restart the game with the previous word(if not
# guessed) or not, or close it
try: ## To do something that may result in an exception
SENTINEL = answers[choose]
except KeyError: ## that some errors will occur
msg = 'Please, insert a correct answer'
choice = 0
print(textwrap.dedent(msg))
else: ## Do things when there was no exceptions
msg = '''
Do you want to use the previous word?
Yes/No
'''
print(textwrap.dedent(msg))
choose = input('>: ').capitalize()
finally: ## Do things when there where no un-caught exceptions
if choose == 'Yes':
choice = int(lenght*(3/2))
choices.clear()
elif choose == 'No':
choice = -1
SENTINEL = 1
else:
choice = -1
SENTINEL = 0
## ... other stuff...
... which'll hopefully expose bugs a bit easier; some will remain hiding though because you've got some formatting issues elsewhere as @Josay already pointed out.
With a little debugging and some tasteful use of abstraction you'll get there, so keep at it and in a few months time your code wont be as much of a danger to sobriety.
Updates
Some other bits that sorta stood out to me...
# ... Things such as
elif guess != 'help' and guess != 'exit' and guess != 'guess' and guess != 'list':
# ... look _neater_ with
elif guess not in ['help', 'exit', 'guess', 'list']:
And things like...
def show_it(word1):
# The function creates dashes format like _ _ _
newIt = ''
for x in word1:
newIt = newIt + x + ' '
newIt = newIt.rstrip(' ')
return newIt
def remove_spaces(word):
string = ''
for x in word:
if x != ' ':
string += x
return string
... should be assigned prior to being used, and they may be written in a more shorthand way via...
remove_spaces = lambda word: word.replace(' ', '')
def show_it(word):
"""
The function creates dashes format like _ _ _
"""
newIt = ' '.join('_' for _ in word)
return newIt.rstrip(' ')
I don't understand what lambda does. Can you explain me ?
I can try to explain lambda
, when programming their a handy way of writing one-line functions. Borrowing a few examples from a past iteration...
edge_cost = lambda base_cost, drivers: base_cost * drivers
edge_cost(base_cost = 0.7, drivers = 2)
## -> 1.4
lambda base_cost, drivers
declares arguments names that maybe used on the other side of the:
(colon)what ever is done on the other side of the colon (
:
) shouldreturn
something as part of the operations, in this casebase_cost * drivers
and the
edge_cost = ...
isdef
ining the name that this operation can be called up with
I'll encourage you to try'em out in an active terminal session...
user@host ~ $ python
>>> remove_spaces = lambda word: word.replace(' ', '')
>>> remove_spaces(word = 'lamb spam and ham')
'lambspamandham'
>>>
Enter
>>> first_class = lambda base_cost: base_cost + 0.5
>>> business_class = lambda base_cost: base_cost + 0.2
>>> first_class(0.4)
0.9
>>> business_class(0.4)
0.6
One thing to keep in mind when using'em is that their intended to be functional in the programming since, so please do not ever do...
bad_idea = lambda d: [d.update({k: v * 2}) for k, v in d.items()]
some_data = {'first': 1, 'second': 2, 'third': 3}
worse_idea = bad_idea(some_data)
... because worse_idea
will then equal [None, None, None]
, nearly useless output, and some_data
will have mutated into something like {'second': 4, 'third': 6, 'first': 2}
. This type of usage of lambda
will only lead to loss of time (if not hair) during the eventual debugging process.
Another not so good example would be...
show_it = lambda i: ' '.join('_' for _ in range(0, i))
... which'll output _ _ _ _ _
via show_it(5)
, but unless you're changing changing i
constantly it's far better to assign a variable that calculates things once...
show_it = ' '.join('_' for _ in range(0, 5))
... Reasons that remove_spaces
should be a function and not show_it
is wonderfully obvious in this case, in the future figuring out how things should be assigned can be a little murky.
Other than that though their supper useful for simple things that get reused elsewhere, as well as for prototyping because it's less key-strokes to some kind of result... Oh and ya may run across lambda being used in Math (if I remember correctly this is where such ideas originated), and in most cases they'll operate very much the same, however, they're not equivalent so that can sometimes cause troubles when translating from one to the other.
Even more updates
So I spent a little more time examining your code and other things popped out...
## ...
if guess == 'help':
if hints == 0:
print('Sorry, you don\'t have anymore hints')
continue
else:
guess = random.choice(itWord)
while guess in newIt:
guess = random.choice(itWord)
## ...
... doesn't need an else
, because when the if
statement trips continue
things move on to the next iteration. Following is a more correct way of expressing your intentions with a computer...
## ...
if guess == 'help':
if hints == 0:
print("Sorry, you don't have anymore hints")
continue
guess = random.choice(itWord)
while guess in newIt:
guess = random.choice(itWord)
## ...
... with a little editing other places that the code is using continue
like this, the amount of tabbing in that's required (AKA cyclomatic complexity) could be significantly reduced.
-
\$\begingroup\$ Thank you. It is really helpful.. But I don't understand what lambda does. Can you explain me ? \$\endgroup\$Roberta Belladonna– Roberta Belladonna2019年06月01日 11:30:30 +00:00Commented Jun 1, 2019 at 11:30
-
1\$\begingroup\$ Most welcome @RobertaBelladonna and
lambda
is another way todef
ine a function (an anonymous one in this case) in Python; and some other languages. See the updates for example usage and a few warnings too. Generally I uselambda
for short-cuts when it doesn't subtract from readability, and/or labeling some kind of transformation or math to be outputed. \$\endgroup\$S0AndS0– S0AndS02019年06月01日 21:59:00 +00:00Commented Jun 1, 2019 at 21:59