I have a program, and one function is to sell an item that the user owns. It prompts the user to input the name (id) and amount, and it sells. But there are a lot of items the user can own, so there are lots of if else elif statements. How do I shorten this? (P.S. I am using Replit, and Replit currently has Python 3.8) Here is the sell function, for reference.
def sell_command():
global cash
cash = 0
#I created a dictionary, inventory, which has how much the user has of a particular item.
#itemSell variable contains what the user wants to sell
#itemSellCount variable contains how much the user wants to sell
#itemSoldCash variable calculates how much one item is worth, and multiplies for how much the user is selling
#cash variable is hlobal since another function prints cash
itemSell = input('What would you like to sell? ')
itemSell = itemSell.lower()
if itemSell == "cobblestone" or "cobble stone":
itemSellCount = int(input("How many would you like to sell? "))
if itemSellCount <= inventory["cobblestone"]:
itemSoldCash = itemSellCount*10
print("You sold " str(itemSellCount) " cobblestone/s for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["cobblestone"] -= itemSellCount
elif itemSellCount > inventory["cobblestone"]:
print("You tried to sell more than what you have!")
elif itemSell == "coal":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["coal"]:
itemSoldCash = itemSellCount*5
print("You sold " str(itemSellCount) " coal for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["coal"] -= itemSellCount
elif itemSellCount > inventory["coal"]:
print("You tried to sell more than what you have!")
elif itemSell == "iron ore" or "ironore":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["ironOre"]:
itemSoldCash = itemSellCount*20
print("You sold " str(itemSellCount) " iron ore/s for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["cobblestone"] -= itemSellCount
elif itemSellCount > inventory["ironOre"]:
print("You tried to sell more than what you have!")
elif itemSell == "iron ingot" or "ironingot":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["ironIngot"]:
itemSoldCash = itemSellCount*25
print("You sold " str(itemSellCount) " iron ingot/s for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["ironIngot"] -= itemSellCount
elif itemSellCount > inventory["ironIngot"]:
print("You tried to sell more than what you have!")
elif itemSell == "emerald" or "emeralds":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["emerald"]:
itemSoldCash = itemSellCount*100
print("You sold " str(itemSellCount) "emerald/s for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["emerald"] -= itemSellCount
elif itemSellCount > inventory["emerald"]:
print("You tried to sell more than what you have!")
elif itemSell == "diamond" or "diamonds":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["diamond"]:
itemSoldCash = itemSellCount*300
print("You sold " str(itemSellCount) " diamond/s for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["diamond"] -= itemSellCount
elif itemSellCount > inventory["diamond"]:
print("You tried to sell more than what you have!")
elif itemSell == "oak":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["oak"]:
itemSoldCash = itemSellCount*15
print("You sold " str(itemSellCount) " oak/s for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["oak"] -= itemSellCount
elif itemSellCount > inventory["oak"]:
print("You tried to sell more than what you have!")
elif itemSell == "birch":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["birch"]:
itemSoldCash = itemSellCount*15
print("You sold " str(itemSellCount) " birch for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["birch"] -= itemSellCount
elif itemSellCount > inventory["birch"]:
print("You tried to sell more than what you have!")
elif itemSell == "redwood" or "red wood":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["redwood"]:
itemSoldCash = itemSellCount*15
print("You sold " str(itemSellCount) "redwood for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["redwood"] -= itemSellCount
elif itemSellCount > inventory["redwood"]:
print("You tried to sell more than what you have!")
elif itemSell == "spruce":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["spruce"]:
itemSoldCash = itemSellCount*15
print("You sold " str(itemSellCount) " spruce for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["spruce"] -= itemSellCount
elif itemSellCount > inventory["spruce"]:
print("You tried to sell more than what you have!")
elif itemSell == "acacia":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["acacia"]:
itemSoldCash = itemSellCount*15
print("You sold " str(itemSellCount) " acacia for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["acacia"] -= itemSellCount
elif itemSellCount > inventory["acacia"]:
print("You tried to sell more than what you have!")
elif itemSell == "jungle":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["jungle"]:
itemSoldCash = itemSellCount*15
print("You sold " str(itemSellCount) " jungle for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["jungle"] -= itemSellCount
elif itemSellCount > inventory["jungle"]:
print("You tried to sell more than what you have!")
elif itemSell == "maple":
itemSellCount = int(input("How many would you like to sell?"))
if itemSellCount <= inventory["maple"]:
itemSoldCash = itemSellCount*15
print("You sold " str(itemSellCount) " maple for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory["maple"] -= itemSellCount
elif itemSellCount > inventory["maple"]:
print("You tried to sell more than what you have!")
CodePudding user response:
That's a lot of duplicate code for what is, essentially, the same thing (I've cleaned up your syntax a bit):
itemSellCount = int(input("How many would you like to sell? "))
if itemSellCount <= inventory[itemSell]:
itemSoldCash = itemSellCount*10
print(f"You sold {itemSellCount} {itemSell}/s for ${itemSoldCash}")
cash = itemSoldCash
inventory[itemSell] -= itemSellCount
else:
print("You tried to sell more than what you have!")
There are, however, three things to consider:
1. How much does each item sell for?
This can be addressed in a number of ways, depending on the programming style, and what you need to track about each item. An OOP approach would be to make an item class, with each item having some attribute defining its value. A straightforward, procedural approach, would be to have a dictionary that defines this:
itemValue = {
"cobblestone": 10,
"coal": 5,
...
}
Now, use a dictionary lookup to determine itemSoldCash
:
itemSoldCash = itemSellCount*itemValue[itemSell]
2. Alternative Item Names
You accept alternative item names, e.g. "cobble stone" is treated as "cobblestone." This can also be approached with a dictionary, e.g. something like:
itemAltNames = {
"cobble stone": "cobblestone",
"iron ingot": "iron ingot",
...
}
Then, you can do something like:
if itemSell in itemAltNames:
itemSell = itemAltNames[itemSell];
Alternatively, if your alternatives only involve stripping spaces, then just do so:
itemSell = itemSell.replace(" ","")
3. Checking that the Item Exists
As it stands, your control flow won't execute if the user enters an invalid item. This is good, but overcomplicated! Also, do you give an error message (or allow repeated input) if the user enters an invalid item? Check against your inventory dictionary to ensure that the user has the item:
if itemSell in inventory:
Putting it All Together
Here's what everything might look like now:
def sell_command():
global cash
cash = 0
itemSell = input("What would you like to sell? ")
while (itemSell := itemSell.lower().strip().replace(" ","")) not in inventory:
itemSell = input(f"You do not have {itemSell} in your inventory. What would you like to sell? ")
itemSellCount = int(input("How many would you like to sell? "))
if itemSellCount <= inventory[itemSell]:
itemSoldCash = itemSellCount * itemValue[itemSell]
print(f"You sold {itemSellCount} {itemSell}/s for ${itemSoldCash}")
cash = itemSoldCash
inventory[itemSell] -= itemSellCount
else:
print("You tried to sell more than what you have!")
CodePudding user response:
You can reduce the branching a lot using dictionaries and objects for what you are doing. And it is the power of OOPs. Here is an example how you will remodel your code.
cash = 0
class CommodityShelf:
"""
A shelf to hold commodities
"""
def __init__(self, item_name, available_quantity, price):
self.item_name = item_name
self.available_qty = available_quantity
self.price = price or 10
def key(self):
# "make it easy to search for this shelf"
return self.item_name.lower().replace(" ", "")
def sell(self):
# handle the selling logic at one place, for any item
global cash
sell_units = int(input(f"How many {self.item_name} would you like to sell? "))
if sell_units > self.available_qty:
print(f"You tried to sell more {self.item_name} than what you have!")
else:
cash = (sell_units * self.price)
self.available_qty -= sell_units
print(f"You sold {self.item_name} for ${sell_units * self.price}")
def start_selling(pos_registry):
"""
Start selling commodities
:param pos_registry:
:return:
"""
item_to_sell = input('What would you like to sell? ').lower().replace(" ", "")
if item_to_sell in pos_registry:
pos_registry[item_to_sell].sell()
else:
print(f"You tried to sell {item_to_sell} but it's not in your inventory!")
if __name__ == '__main__':
# create a shelf for each commodity
inventory = [
CommodityShelf("Cobble Stone", 10, 0),
CommodityShelf("Coal", 10, 0),
CommodityShelf("Iron Ore", 10, 0),
CommodityShelf("Iron Ingot", 10, 0),
CommodityShelf("Emarald", 10, 0),
CommodityShelf("Diamond", 10, 0),
]
# create a registry of all the shelves
pos_registry = {pos.key(): pos for pos in inventory}
# start selling
start_selling(pos_registry)
# loop it if the user wants to
I hope the logical explanation is in the comments.
CodePudding user response:
It appears a lot of your if-else is redundant. The only thing that is unique in each if-condition is itemSoldCash
. You can use a helper function to map them to the relevant itemSell
s and use a single if-else condition otherwise:
def sell_command():
global cash
cash = 0
def get_Cash(itemSell, itemSellCount):
if itemSell == "cobblestone":
return itemSellCount*10
elif itemSell == "coal":
return itemSellCount*5
elif itemSell == "ironore":
return itemSellCount*20
elif itemSell == "ironingot":
return itemSellCount*25
elif itemSell == "emerald":
return itemSellCount*100
elif itemSell == "diamond":
return itemSellCount*300
elif itemSell in ["oak","birch","redwood","spruce","acacia","jungle","maple"]:
return itemSellCount*15
itemSell = ''.join(input('What would you like to sell? ').lower())
itemSellCount = int(input("How many would you like to sell? "))
if itemSellCount <= inventory[itemSell]:
itemSoldCash = get_Cash(itemSell, itemSellCount)
print("You sold {} {} for ${}".format(itemSellCount, itemSell, itemSoldCash))
cash = itemSoldCash
inventory[itemSell] -= itemSellCount
else:
print("You tried to sell more than what you have!")
CodePudding user response:
This code is probably the easiest fix. You might have to change the inventory dictionary though, so that every key is lowercase.
Also, itemSell == "cobblestone" or "cobble stone"
always returns true.
def sell_command():
global cash
cash = 0
cashMultiplierDict = {"cobblestone": 10, "coal": 5} #etc
#The following line just removes all white spaces (e.g. cobble stone becomes cobblestone)
itemSell = input('What would you like to sell? ').lower().replace(" ", "")
itemSellCount = int(input("How many would you like to sell? "))
if itemSellCount <= inventory[itemSell]:
itemSoldCash = itemSellCount * cashMultiplierDict[itemSell] #Uses the dict created before
print("You sold " str(itemSellCount) " " itemSell "/s for $" str(itemSoldCash))
cash = cash itemSoldCash
inventory[itemSell] -= itemSellCount
elif itemSellCount > inventory[itemSell]:
print("You tried to sell more than what you have!")
CodePudding user response:
You can organize the code a little bit better:
the
itemSellCount = int(input("How many would you like to sell?")
is done for each items, this can be done one time, and after that the
itemSoldCash = itemSellCount*15
is the quantity for costs. Costs can be organized into a catalog in a better data structure, maybe something like this:
# you can add if needed other attributes for all material, like color, weight, damage, duration, and so on
catalogue = {
"cobblestone": {"cost": 15, 'color':'red'},
"maple": {"cost": 15},
"jungle": {"cost": 15},
"acacia": {"cost": 15},
"diamond": {"cost": 300},
...
}
# aliases
catalogue["cobble stone"] = catalogue["cobblestone"]
def sell(item, qty, inventory):
if qty <= inventory[item]:
sold = qty * catalogue[item]["cost"]
print("You sold {} maple for ${}".format(qty, sold))
cash = sold
inventory[item] -= qty
else:
print("You tried to sell more {} than what you have!".format(item))
and finally you call this function with all needed information:
itemSell = input('What would you like to sell? ')
itemSell = itemSell.lower()
itemSellCount = int(input("How many would you like to sell? "))
sell(itemSell,itemSellCount, inventory)
inventory is not defined in the example.
PS if many objects costs the same, and they are considered default costs, you can simplify the catalogue definition putting in it only special cost, default can be applied as missing value:
sold = qty * (catalogue[item]["cost"] if item in catalogue else 15)