8
\$\begingroup\$

This is my Hangman game that I created using PyQt5 and Python 3.5 on my Windows 7 machine. What do you think? Is there anything you thing I could change/improve in terms of code or visually (font, font size, font color, image size, button size)?

(Images)

from sys import (exit, argv)
from PyQt5.QtCore import (Qt, QRegExp)
from PyQt5.QtWidgets import (QToolTip, QPushButton, QApplication, QWidget, QLabel, QLineEdit)
from PyQt5.QtGui import (QIcon, QPixmap, QFont, QRegExpValidator)
from random import choice
from time import sleep
WORDS = ['Captivity', 'America', 'Europe', 'Federal', 'Gluten', 'Ridiculous', 'Automatic', 'Television', 'Difficult', 'Severe', 'Interesting', 'Indonesia', 'Industrial',
 'Automotive', 'President', 'Terrestrial', 'Academic', 'Comedic', 'Comical', 'Genuine', 'Suitcase', 'Vietnam', 'Achievement', 'Careless', 'Monarchy', 'Monetary', 
 'Quarantine', 'Supernatural', 'Illuminate', 'Optimal', 'Application', 'Scientist', 'Software', 'Hardware', 'Program', 'Colonial', 'Algorithm', 'Intelligent', 
 'Electricity', 'Verification', 'Broadband', 'Quality', 'Validation', 'Online', 'Telephone', 'Dictionary', 'Keyboard', 'China', 'London', 'Jamaica', 'Biology', 
 'Chemistry', 'History', 'Historian', 'Africa', 'Mathematics', 'Computer', 'Literature', 'Gravity', 'Guitar', 'Violin', 'Illuminate', 'England', 'China', 'Japan',
 'Canada', 'Suitcase', 'Wireless', 'Internet']
HANGMAN_PARMS = 100, 200, Qt.KeepAspectRatio, Qt.FastTransformation
class hangman(QWidget):
 def __init__(self):
 super().__init__()
 self.initUI()
 def initUI(self):
 self.background = QLabel(self)
 self.background.setPixmap(QPixmap('background.jpg').scaled(201, 352, Qt.IgnoreAspectRatio, Qt.FastTransformation))
 self.background.move(-1, -1)
 self.number = 1
 self.image = QLabel(self)
 self.image.setPixmap(QPixmap('hangman_{}.png'.format(self.number)).scaled(*HANGMAN_PARMS))
 self.image.move(60, 0.5)
 self.word = choice(WORDS)
 blank_word = '_ ' * len(self.word)
 blank_word.rstrip() 
 self.blank_word_label = QLabel(blank_word, self)
 font1 = self.blank_word_label.font()
 font1.setPointSize(14)
 self.blank_word_label.setFont(font1)
 self.blank_word_label.setFixedWidth(200)
 self.blank_word_label.setToolTip('Attempt to fill in the blanks')
 self.blank_word_label.move(0,200)
 self.blank_word_label.setAlignment(Qt.AlignCenter)
 self.guessed_letters = ''
 self.btn = QPushButton('Check', self)
 self.btn.setFont(QFont('SansSerif', 20))
 self.btn.setToolTip('Click to check if the entered letter is in the word')
 self.btn.clicked.connect(self.check_letter)
 self.btn.resize(102, 43)
 self.btn.move(99, 228)
 self.entered_letter = QLineEdit(self)
 regex = QRegExp("[a-z-A-Z_]+")
 validator = QRegExpValidator(regex)
 self.entered_letter.setValidator(validator)
 font2 = self.entered_letter.font()
 font2.setPointSize(24)
 self.entered_letter.setFont(font2)
 self.entered_letter.setMaxLength(1)
 self.entered_letter.setToolTip('Enter a letter and check if it is in the word')
 self.entered_letter.setFocus(True)
 self.entered_letter.returnPressed.connect(self.check_letter)
 self.entered_letter.resize(100, 43)
 self.entered_letter.move(0.5, 228)
 self.correct_or_incorrect = QLabel(self)
 self.correct_or_incorrect.move(1, 232)
 self.correct_or_incorrect.setVisible(False)
 self.you_lose = QLabel(self)
 self.you_lose.setPixmap(QPixmap('game_over.jpg').scaled(200, 160, Qt.IgnoreAspectRatio, Qt.FastTransformation))
 self.you_lose.move(0.5, 0.5)
 self.you_lose.setVisible(False)
 self.you_win = QLabel(self)
 self.you_win.setPixmap(QPixmap('congratulations.jpg').scaled(200, 160, Qt.IgnoreAspectRatio, Qt.FastTransformation))
 self.you_win.move(0.5, 0.5)
 self.you_win.setVisible(False)
 self.correct_word = QLabel('The word was:', self)
 font1 = self.correct_word.font()
 font1.setPointSize(14)
 self.correct_word.setFont(font1)
 self.correct_word.setFixedWidth(200)
 self.correct_word.move(0,170)
 self.correct_word.setAlignment(Qt.AlignCenter)
 self.correct_word.setVisible(False)
 self.replay_btn = QPushButton('Play Again', self)
 self.replay_btn.setFont(QFont('SansSerif', 15))
 self.replay_btn.setToolTip('Click to play another game of Hangman')
 self.replay_btn.clicked.connect(self.replay)
 self.replay_btn.resize(202, 33)
 self.replay_btn.move(-1, 239.8)
 self.replay_btn.setVisible(False)
 QToolTip.setFont(QFont('SansSerif', 10))
 self.setGeometry(1390, 30, 200, 270)
 self.setFixedSize(self.size())
 self.setWindowTitle('Hangman')
 self.setWindowIcon(QIcon('icon.png')) 
 self.show()
 def check_letter(self):
 if self.entered_letter.text().lower() in self.word.lower():
 self.guessed_letters += self.entered_letter.text().lower()
 self.correct_or_incorrect.setPixmap(QPixmap('correct.png').scaled(40, 40, Qt.IgnoreAspectRatio, Qt.FastTransformation))
 self.correct_or_incorrect.setVisible(True)
 QApplication.processEvents()
 sleep(0.1)
 self.correct_or_incorrect.setVisible(False)
 QApplication.processEvents()
 else:
 self.number += 1
 self.image.setPixmap(QPixmap('hangman_{}.png'.format(self.number)).scaled(*HANGMAN_PARMS))
 self.correct_or_incorrect.setPixmap(QPixmap('incorrect.png').scaled(40, 40, Qt.IgnoreAspectRatio, Qt.FastTransformation))
 self.correct_or_incorrect.setVisible(True)
 QApplication.processEvents()
 sleep(0.1)
 self.correct_or_incorrect.setVisible(False)
 QApplication.processEvents()
 blank_word = ''
 for i in self.word:
 if i.lower() in self.guessed_letters:
 blank_word += i 
 else:
 blank_word += '_ '
 blank_word.rstrip()
 self.blank_word_label.setText(blank_word)
 self.entered_letter.setText('')
 self.entered_letter.setFocus(True)
 if self.number == 7:
 self.blank_word_label.setText(self.word)
 self.image.setVisible(False)
 self.entered_letter.setVisible(False)
 self.btn.setVisible(False)
 self.you_lose.setVisible(True)
 self.correct_word.setVisible(True)
 self.replay_btn.setVisible(True)
 if blank_word == self.word:
 self.image.setVisible(False)
 self.entered_letter.setVisible(False)
 self.btn.setVisible(False)
 self.you_win.setVisible(True)
 self.correct_word.setVisible(True)
 self.replay_btn.setVisible(True)
 def replay(self):
 self.number = 1
 self.image.setPixmap(QPixmap('hangman_{}.png'.format(self.number)).scaled(*HANGMAN_PARMS))
 self.word = choice(WORDS)
 blank_word = '_ ' * len(self.word)
 blank_word.rstrip()
 self.blank_word_label.setText(blank_word)
 self.guessed_letters = ''
 self.you_lose.setVisible(False)
 self.you_win.setVisible(False)
 self.correct_word.setVisible(False)
 self.replay_btn.setVisible(False)
 self.image.setVisible(True)
 self.entered_letter.setVisible(True)
 self.btn.setVisible(True)
 self.entered_letter.setFocus(True) 
if __name__ == '__main__':
 app = QApplication(argv)
 ex = hangman()
 ex.show()
 exit(app.exec_())
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 12, 2017 at 13:09
\$\endgroup\$
1
  • \$\begingroup\$ blank_word.rstrip() does nothing, as .rstrip() does not modify the original string. You could do blank_word = blank_word.rstrip(), or simply put the .rstrip() on the line above. \$\endgroup\$ Commented Aug 12, 2017 at 20:06

4 Answers 4

5
\$\begingroup\$

I would like to point out some minor things about your style. Following PEP8 style guide makes code easier to read :)

Class names should normally use the CapWords convention.

Imports should be grouped in the following order:

  1. standard library imports

  2. related third party imports

  3. local application/library specific imports

So your imports would be:

from sys import exit, argv
from random import choice
from time import sleep
from PyQt5.QtCore import Qt, QRegExp
from PyQt5.QtWidgets import QToolTip, QPushButton, QApplication, QWidget, 
QLabel, QLineEdit
from PyQt5.QtGui import QIcon, QPixmap, QFont, QRegExpValidator

You should also add a few docstrings. You can check for other minor mistakes with this tool: http://pep8online.com/

MarianD
1,9561 gold badge11 silver badges20 bronze badges
answered Aug 12, 2017 at 19:29
\$\endgroup\$
1
  • 1
    \$\begingroup\$ I personally also order imports alphabetically most of the time within each of the categories you listed in 1, 2, 3 \$\endgroup\$ Commented Aug 12, 2017 at 19:36
3
\$\begingroup\$

Very nice, there are no many things to improve.

I guess that this part of your code

WORDS = ['Captivity', 'America', 'Europe', 'Federal', 'Gluten', 'Ridiculous', 'Automatic', 'Television', 'Difficult', 'Severe', 'Interesting', 'Indonesia', 'Industrial',
 'Automotive', 'President', 'Terrestrial', 'Academic', 'Comedic', 'Comical', 'Genuine', 'Suitcase', 'Vietnam', 'Achievement', 'Careless', 'Monarchy', 'Monetary', 
 'Quarantine', 'Supernatural', 'Illuminate', 'Optimal', 'Application', 'Scientist', 'Software', 'Hardware', 'Program', 'Colonial', 'Algorithm', 'Intelligent', 
 'Electricity', 'Verification', 'Broadband', 'Quality', 'Validation', 'Online', 'Telephone', 'Dictionary', 'Keyboard', 'China', 'London', 'Jamaica', 'Biology', 
 'Chemistry', 'History', 'Historian', 'Africa', 'Mathematics', 'Computer', 'Literature', 'Gravity', 'Guitar', 'Violin', 'Illuminate', 'England', 'China', 'Japan',
 'Canada', 'Suitcase', 'Wireless', 'Internet']

was much time-consuming for typing many of apostrophes and commas - the faster approach is

WORDS = ("Captivity America Europe Federal Gluten Ridiculous "
 "Automatic Television Difficult Severe Interesting Indonesia "
 "Industrial Automotive President Terrestrial Academic Comedic "
 "Comical Genuine Suitcase Vietnam Achievement Careless "
 "Monarchy Monetary Quarantine Supernatural Illuminate Optimal "
 "Application Scientist Software Hardware Program Colonial "
 "Algorithm Intelligent Electricity Verification Broadband Quality "
 "Validation Online Telephone Dictionary Keyboard China "
 "London Jamaica Biology Chemistry History Historian "
 "Africa Mathematics Computer Literature Gravity Guitar "
 "Violin Illuminate England China Japan Canada "
 "Suitcase Wireless Internet "
 ).split()

Note that it is one very long literal string written part by part (an closed in parentheses for avoiding \ at the ends of the lines).

toto2
5,45017 silver badges21 bronze badges
answered Aug 12, 2017 at 17:26
\$\endgroup\$
2
  • 3
    \$\begingroup\$ Or put them in a separate file entirely. CSV or DB, etc. \$\endgroup\$ Commented Aug 12, 2017 at 19:53
  • \$\begingroup\$ Why not use one triple-quoted string spanning multiple lines? \$\endgroup\$ Commented Aug 13, 2017 at 13:36
2
\$\begingroup\$

It looks good, but I'm not a Qt expert.

I would have used model/view separation: the game code would be in one file and the UI code would be in a logically completely separated file. For example, from the same game code you can write a pure text interface, or a Qt interface.

Also I would put the word list in a text file.

answered Aug 12, 2017 at 18:46
\$\endgroup\$
1
\$\begingroup\$

I don't much like HANGMAN_PARMS as a tuple. Why not separate variables or a dictionary? That way their meanings would be more explicit.

I don't see the point in initUI - why isn't that code in __init__.

answered Aug 13, 2017 at 5:24
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.