I have a program that gives the player a random U.S. state, asks for its capital, and keeps score. This keeps going until the player decides to stop playing. At the end, it prints out both the amount of correct answers and amount of incorrect answers.
I took some of the advice into account that I got on my other posts and put the dictionary within the main function (I had it in its own function before), but was wondering if there was a more efficient way to do the while loop that is the basis of the game, as well as if me converting the dict to a list is an okay way to solve this problem.
MIN = 0
MAX = 49
import random
def main():
stateDict = {'Alabama': 'Montgomery',
'Alaska': 'Juneau',
'Arizona': 'Phoenix',
'Arkansas': 'Little Rock',
'California': 'Sacramento',
'Colorado': 'Denver',
'Connecticut': 'Hartford',
'Delaware': 'Dover',
'Florida': 'Tallahassee',
'Georgia': 'Atlanta',
'Hawaii': 'Honolulu',
'Idaho': 'Boise',
'Illinois': 'Springfield',
'Indiana': 'Indianapolis',
'Iowa': 'Des Moines',
'Kansas': 'Topeka',
'Kentucky': 'Frankfort',
'Louisiana': 'Baton Rouge',
'Maine': 'Augusta',
'Maryland': 'Annapolis',
'Massachusetts': 'Boston',
'Michigan': 'Lansing',
'Minnesota': 'Saint Paul',
'Mississippi': 'Jackson',
'Missouri': 'Jefferson City',
'Montana': 'Helena',
'Nebraska': 'Lincoln',
'Nevada': 'Carson City',
'New Hampshire': 'Concord',
'New Jersey': 'Trenton',
'New Mexico': 'Santa Fe',
'New York': 'Albany',
'North Carolina': 'Raleigh',
'North Dakota': 'Bismarck',
'Ohio': 'Columbus',
'Oklahoma': 'Oklahoma City',
'Oregon': 'Salem',
'Pennsylvania': 'Harrisburg',
'Rhode Island': 'Providence',
'South Carolina': 'Columbia',
'South Dakota': 'Pierre',
'Tennessee': 'Nashville',
'Texas': 'Austin',
'Utah': 'Salt Lake City',
'Vermont': 'Montpelier',
'Virginia': 'Richmond',
'Washington': 'Olympia',
'West Virginia': 'Charleston',
'Wisconsin': 'Madison',
'Wyoming': 'Cheyenne'}
statesList = list(stateDict)
correct = 0
incorrect = 0
again = 'y'
while (again == 'y'):
num = random.randint(MIN,MAX)
state = statesList[num]
print('\n' + state)
ans = input("\nEnter the capital of this state: ")
if (ans == stateDict[state]):
correct += 1
print("Correct")
again = input("Type y to play again, anything else to stop: ")
else:
incorrect += 1
print("Incorrect")
again = input("Type y to play again, anything else to stop: ")
print("\nYou have",correct,"correct answers")
print("\nYou have",incorrect,"incorrect answers")
main()
1 Answer 1
You are on the right track in several respects -- for example, putting all behavior/actions inside of functions. That said, constants are fine at the top level, and one advantage of putting them there is allowing the reader to focus on the algorithm without the visual heaviness of a big data structure.
Don't force your user to worry about capitalization: lowercase the data and then use Python's built-in string methods to capitalize geographic names for presentation to the user.
Opinions vary on this, but I recommend using natural language as the primary
(not sole) guide when picking variables: in most contexts, for example,
capitals
is a better name than stateDict
; states
better than
statesList
. Sometimes a data-type suffix can disambiguate names, but
don't make that your first impulse.
The random library includes a choice()
function, so you do not
need MIN
, MAX
.
I recommend less chatty messages to users in interactive programs. Once the user understands the basics (computer prints state, user types capital), they do not require verbose instructions. Ruthless text cutting is a virtue in these situations.
Nest the main()
call under the conditional shown below. This mechanism will
make your scripts amenable to importing, easier debugging, and
automated testing should you ever need it.
Whenever you find yourself creating multiple closely related variables
(correct
and incorrect
), consider whether you can unify them under a data
structure. Sometimes taking that approach will suggest further refactoring to
simplify code (for example, by reducing if-else branching). In the illustration
below, I started just by focusing on unifying the correct/incorrect tallies,
but that inspired other simplifications in the reporting of overall results.
import random
# Your dict, but lowercase.
capitals = {
'alabama': 'montgomery',
'alaska': 'juneau',
...
}
def main():
# Setup.
states = tuple(capitals)
tally = {True: 0, False: 0}
results = {True: 'Correct', False: 'Incorrect'}
result = ''
# Quiz loop.
print('State capitals quiz:')
while True:
# Get user reply.
state = random.choice(states)
ans = input(f'{result}{state.title()}? ').lower()
if ans in ('', 'q', 'quit'):
break
# Tally result.
res = ans == capitals[state]
tally[res] += 1
result = results[res] + '. '
# Print overall results.
fmt = 'Results:\n- {}: {}\n- {}: {}'
args = (results[True], tally[True], results[False], tally[False])
print(fmt.format(*args))
if __name__ == '__main__':
main()
Finally, people who take quizzes generally want to see the right answers. You could print the correct result immediately in response to a wrong reply. Or you could keep track of all states with bad replies and print correct answers at the end.
-
3\$\begingroup\$ Good answer, +1. Two small suggestions: 1. Move trailing spaces from the values in
results
to the f-string argument toinput
when assigningans
. 2. Assignans
toinput(...).lower()
to make differently capitalized quit commands work. \$\endgroup\$riskypenguin– riskypenguin2021年04月18日 10:18:16 +00:00Commented Apr 18, 2021 at 10:18 -
1\$\begingroup\$ Mostly good, though your
fmt
should not be hard coding the correct and incorrect strings - you have those in results. \$\endgroup\$Reinderien– Reinderien2021年04月19日 04:20:30 +00:00Commented Apr 19, 2021 at 4:20 -
\$\begingroup\$ I would perhaps consider implementing the dict as a CaseInsensitiveDict. I think it ships with the requests module but can be implemented in 20 lines of code. \$\endgroup\$Kate– Kate2021年04月19日 19:30:03 +00:00Commented Apr 19, 2021 at 19:30
-
\$\begingroup\$ @Anonymous A dependency or implementing a custom container just to avoid calling str.title() and str.lower()? I'll let the OP consider that tradeoff. \$\endgroup\$FMc– FMc2021年04月19日 23:34:16 +00:00Commented Apr 19, 2021 at 23:34