This project was created for an introductory programming course at Penn State in the fall of 2021.
Learning Outcomes:
- Utilize multiple types of 1D data structures
- Clean and handle data using built-in string and list functions
- Apply nested if-else statements in series to handle increasing complexity
- Incorporate a dictionary to translate between numerals and text numbers
Monopoly property values are an effective tool for practicing logical complexity because of their unique rules:
- (Traditionally) Monopoly has 8 color sets of properties
- Each color set contains 2 or 3 individual properties
- Each color has a different purchase cost
- All properties in the set must be owned by the same person before building
- All properties must be upgraded evenly, ie you cannot build a second house on any property until all properties in the set have their first
- A hotel can only be built by upgrading from four houses (rule #5 still applies)
This creates two problems:
Problem #1: How best to organize the data for retrieval when each property has multiple attributes?
There are several ways this can be done, but for this project I chose to use a simple list structure similar to that of a .csv (comma separated value) file. By keeping the attributes listed in a consistent order, I can utilize list index functions to find related attribute values. In this case, I listed the data as (“color”, #properties, #cost) for the eight standard monopoly colors. The benefit to this structure is that it can be easily modified to change number values or add/remove colors and minimizes code redundancy.
I’m also using a dictionary in order to convert numerals to text numbers for use in the output. Because of the structure of (traditional) monopoly, the highest possible number of total houses & hotels on one set is twelve and the lowest is zero). So am able to restrict my dictionary to this range for efficiency.
#Monopoly Property Table (color, properties, cost)
value_table = ("violet", 2, 50, "pale blue", 3, 50, "maroon", 3, 100, "orange", 3, 100,
"red", 3, 150, "yellow", 3, 150, "green", 3, 200, "dark blue", 2, 200)
#dictionary to convert numbers to words
number_dictionary = {0:"zero", 1:"one", 2:"two", 3:"three", 4:"four", 5:"five", 6:"six",
7:"seven", 8:"eight", 9:"nine", 10:"ten", 11:"eleven", 12:"twelve"}
I then utilized list and string functions to display property options, clean keyboard inputs, loop back for invalid inputs, and report the correct property cost.
#displays color choices, which are every 3rd item in the list
color_list = value_table[::3]
print("The block colors in Monopoly are:")
print(", ".join(color_list))
#Take & clean keyboard input
print("")
color = input("Which color block will you be building on? ")
color = color.strip()
color = color.lower()
#Loop invalid inputs
while color not in value_table:
if color == "blue":
color = input("Would that be pale blue or dark blue? ")
color = color.strip()
color = color.lower()
else:
color = input("There is no block by that color. Choose another? ")
color = color.strip()
color = color.lower()
#Extract relevant data from list for convenience
color_index = value_table.index(color)
properties = value_table[color_index + 1]
cost = value_table[color_index + 2]
print("")
print(f"There are {number_dictionary[properties]} properties and each house costs {cost}")
Next, after taking keyboard input regarding the amount of available money, we must determine how many houses and hotels can be built. Since hotels are built only after building four houses, we can comfortably focus our attention on the houses for now.
money = int(input("How much money do you have to spend? "))
#calculate max possible houses
number_houses = money // cost
#determine how houses will be distributed
#first upgrade all properties equally
minimum = number_houses // properties
#second, determine how many properties get extra house
extra = number_houses % properties
Now that we’ve distributed the houses evenly, we’ve come to our second main problem.
Problem #2: How to ensure that all properties are upgraded evenly and follow the rules for building hotels?
In this case, there are four types of outcomes we must consider as each type will require a differently formatted output:
- Build nothing
- Build all hotels
- Build some hotels
- Build no hotels
The first two cases are easiest to handle since we’ve already calculated the minimum number of houses per property. Remember too that hotels are built after four houses and nothing can be built after a hotel. Therefore, any property with five or more houses becomes a hotel. If the calculated minimum is five or above, all properties get hotels.
if number_houses == 0:
print("You can't afford even one house :(")
elif minimum >= 5:
print(f"{number_dictionary[properties].capitalize()} will have a hotel.")
Next, we should consider the cases where only some properties get hotels. Because of the even development rule, we know that if even one property has a hotel, all properties must have built at least four houses (and at least one property received an extra).
Therefore, minimum = 4 and extra > 0
elif minimum == 4 and extra > 0:
print(f"{number_dictionary[extra].capitalize()} will have a hotel, and {number_dictionary[properties - extra]} will have {number_dictionary[minimum]} houses")
else:
Finally, we consider the most complex case: some houses and no hotels. There are three possibilities here:
- Some properties build none, some build one (minimum = 0, extra > 0)
- All properties build equally (minimum >0, extra = 0)
- All properties build, some build extra (minimum > 0, extra >0)
This is where properly ordering our logical arguments is paying off. We know logically that properties building more than 4 houses will become hotels, but we don’t have to code in value limits because we’ve already separated all those cases out in the earlier chunks of code!
print("You can build", number_dictionary[number_houses], "house" if number_houses == 1 else "houses as follows:")
if minimum == 0: #minimum = 0
print(f"{number_dictionary[extra].capitalize()} will have {number_dictionary[minimum + 1]}")
elif extra == 0: #extra = 0
print(f"{number_dictionary[properties].capitalize()} will have {number_dictionary[minimum]}")
else: #minimum and extra >0
print(f"{number_dictionary[extra].capitalize()} will have {number_dictionary[minimum + 1]}, and {number_dictionary[properties - extra]} will have {number_dictionary[minimum]}")
And we’re done!
Here’s how the final program looks when run: