patternpythonMinor
Account registration system for a quiz game
Viewed 0 times
registrationsystemquizaccountgamefor
Problem
As part of a school project for ICT lessons, our class has been required to write a quiz program following certain criteria that has been set. The first part of this is a program that handles the registration process by asking the user for details such as player name, age, email and gender.
```
import getpass
import os
import pickle
import time
nope = "I didn't quite get that. Mind trying again?"
yn = {'y': True, 'n': False}
if os.path.exists('players'):
with open('players', 'rb') as f:
if os.stat('players').st_size == 0:
accounts = {}
else:
accounts = pickle.loads(f.read())
else:
f = open('players', 'wb')
f.close()
accounts = {}
class Player(object):
def __init__(self):
self.name = ""
self.email = ""
self.password = ""
self.age = ""
self.gender = ""
def write(self):
accounts[p.name] = [p.email, p.password, p.age, p.gender]
with open('players', 'wb') as f:
pickle.dump(accounts, f)
p = Player()
def askChoices(question, options, errorMessage):
while True:
answer = str(input(question)).lower()
if answer in options:
return options[answer]
else:
print(errorMessage)
def register():
print("\nWelcome, new player!")
while True:
p.name = input("What is your name? ")
if p.name in accounts:
print("Name already taken. Please try again.")
else:
break
isEmailValid = False
while not isEmailValid:
p.email = str(input("What is your email address? "))
if '@' in p.email and '.' in p.email:
isEmailValid == True
break
else:
print(nope, "(Input must contain '@' and '.')")
p.password = getpass.getpass('Please enter a password. ')
while True:
try:
p.age = int(input("How old are you? "))
break
except ValueError:
prin
```
import getpass
import os
import pickle
import time
nope = "I didn't quite get that. Mind trying again?"
yn = {'y': True, 'n': False}
if os.path.exists('players'):
with open('players', 'rb') as f:
if os.stat('players').st_size == 0:
accounts = {}
else:
accounts = pickle.loads(f.read())
else:
f = open('players', 'wb')
f.close()
accounts = {}
class Player(object):
def __init__(self):
self.name = ""
self.email = ""
self.password = ""
self.age = ""
self.gender = ""
def write(self):
accounts[p.name] = [p.email, p.password, p.age, p.gender]
with open('players', 'wb') as f:
pickle.dump(accounts, f)
p = Player()
def askChoices(question, options, errorMessage):
while True:
answer = str(input(question)).lower()
if answer in options:
return options[answer]
else:
print(errorMessage)
def register():
print("\nWelcome, new player!")
while True:
p.name = input("What is your name? ")
if p.name in accounts:
print("Name already taken. Please try again.")
else:
break
isEmailValid = False
while not isEmailValid:
p.email = str(input("What is your email address? "))
if '@' in p.email and '.' in p.email:
isEmailValid == True
break
else:
print(nope, "(Input must contain '@' and '.')")
p.password = getpass.getpass('Please enter a password. ')
while True:
try:
p.age = int(input("How old are you? "))
break
except ValueError:
prin
Solution
Avoid global variables
They are so hard to reason about.
Move
And inside the
A player should know how to print himself
The following is an implementation detail:
It is more clear to write:
To allow this you should implement a
Use a function to handle input validation
In-lining all that code for input validation makes the code noisy, and it becomes hard to follow the high level flow of your code, a
Anything calls anything?
I suggest that only
For example look how simple
Tiny helper functions
Do not feel bad for writing tiny functions that make your code even just a little more readable, they are good! For example:
Takes some time to understand, reading is not fluent, but if I define:
Reading
The same goes for:
Opening a file and closing it again is weird... a small aptly named function will make your intent much clearer.
They are so hard to reason about.
Move
p = Player() out of global scope and to the start of register()And inside the
Player class use self:def write(self):
accounts[self.name] = [self.email, self.password, self.age, self.gender]
with open('players', 'wb') as f:
pickle.dump(accounts, f)A player should know how to print himself
The following is an implementation detail:
print("\nName:", p.name,
"\nEmail:", p.email,
"\nPassword:", ('*' * len(p.password)),
"\nAge:", p.age,
"\nGender:", p.gender)It is more clear to write:
print(p)To allow this you should implement a
__str__ method in the Player class. Use a function to handle input validation
In-lining all that code for input validation makes the code noisy, and it becomes hard to follow the high level flow of your code, a
general_input function may be nice to write:p.name = general_input(
"What is your name? ",
validation = lambda name: name not in accounts,
error_message = "Name already taken. Please try again."
)
p.email = general_input(
"What is your e-mail? ",
validation = lambda email: '@' in email or '.' in email,
error_message = "(Input must contain '@' and '.')"
)
p.password = getpass.getpass('Please enter a password. ')
p.age = general_input(
"How old are you? ",
validation = lambda age: all(i in '1234567890' for i in age)
error_message = 'Age should be a positive integer'
)Anything calls anything?
register may call log-in, login may call register, it does not feel clean. User interaction menu functions calling each other freely is just glorified go-to.I suggest that only
main may call login and register and they may not call each other, but just main back. It would simplify the code and maybe even make the program more predictable to use when/if it grows (When you are unsure about how to do an action, just go back to the main menu and you will be shown how)For example look how simple
login becomes when you make it jump back unconditionally to main:def login():
while True:
name = input("What is your player name? ")
if name not in accounts:
print("Account not found.")
main()
pw = getpass.getpass("Please enter your password. ")
if pw == accounts[name][1]:
print(accounts[name]) # debug placeholder until quiz functionality is addedTiny helper functions
Do not feel bad for writing tiny functions that make your code even just a little more readable, they are good! For example:
os.stat('players').st_size == 0Takes some time to understand, reading is not fluent, but if I define:
def is_file_empty(filename):
return os.stat('players').st_size == 0Reading
is_file_empty('players') is instantaneous.The same goes for:
f = open('players', 'wb')
f.close()Opening a file and closing it again is weird... a small aptly named function will make your intent much clearer.
Code Snippets
def write(self):
accounts[self.name] = [self.email, self.password, self.age, self.gender]
with open('players', 'wb') as f:
pickle.dump(accounts, f)print("\nName:", p.name,
"\nEmail:", p.email,
"\nPassword:", ('*' * len(p.password)),
"\nAge:", p.age,
"\nGender:", p.gender)p.name = general_input(
"What is your name? ",
validation = lambda name: name not in accounts,
error_message = "Name already taken. Please try again."
)
p.email = general_input(
"What is your e-mail? ",
validation = lambda email: '@' in email or '.' in email,
error_message = "(Input must contain '@' and '.')"
)
p.password = getpass.getpass('Please enter a password. ')
p.age = general_input(
"How old are you? ",
validation = lambda age: all(i in '1234567890' for i in age)
error_message = 'Age should be a positive integer'
)def login():
while True:
name = input("What is your player name? ")
if name not in accounts:
print("Account not found.")
main()
pw = getpass.getpass("Please enter your password. ")
if pw == accounts[name][1]:
print(accounts[name]) # debug placeholder until quiz functionality is addedos.stat('players').st_size == 0Context
StackExchange Code Review Q#112494, answer score: 3
Revisions (0)
No revisions yet.