5
\$\begingroup\$

So this is the code to a calculator I made for a game. Essentially what the calculator does is, it calculates the cost of buying the next stat.

So I wrote the code just for the Human race and the strength stat. From the way I see it, I will have to do for each race the same code 3 times for each stat.

I was hoping there would be a shorter way around this like

instead of human.strength I would like it to be race.strength where race = user_race.

Thanks

class race:
    """The different races in the calculator"""
    def __init__(self, race, strength, agility, health, strength_cost, agility_cost, health_cost):
        self.race = race
        self.strength = strength
        self.agility = agility
        self.health = health
        self.strength_cost = strength_cost
        self.agility_cost = agility_cost
        self.health_cost = health_cost

human = race('Human', 15, 17, 18, 5, 3, 4) 
elf = race('Elf', 11, 21, 14, 4, 3, 5)
giant = race('Giant', 25, 11, 27, 4, 8, 3)

print("Human, Giant, Elf")
user_race = str(input("Enter your race:")).lower()
print("Strength, Agility, Health")
user_stat = str(input("Enter your desired stat:")).lower()
user_present_stat_value = int(input("Enter your present stat value:"))
user_desired_stat_value = int(input("Enter your desired stat value:"))

if user_race == 'human' and user_stat == 'strength':
    human_strength_present_statdif = (user_present_stat_value - human.strength) # difference of present stat with respect of base stat

    human_strength_desired_statdif = (user_desired_stat_value - human.strength) #difference of desired stat with respect of base stat
    
    human_strength_present_stat_cost = (human.strength_cost + (human_strength_present_statdif - 1) * human.strength_cost) #The cost of present stat stat 
    
    human_strength_total_present_cost = ((human_strength_present_statdif / 2) * (human.strength_cost + human_strength_present_stat_cost)) # The total cost from base stat to present stat
    
    human_strength_desired_stat_cost = (human.strength_cost + (human_strength_desired_statdif - 1) * human.strength_cost) #The cost of desired stat
    
    human_strength_total_desired_cost = ((human_strength_desired_statdif / 2) * (human.strength_cost + human_strength_desired_stat_cost)) # The total cost base stat to desired stat
    
    human_strength_net_cost = (human_strength_total_desired_cost - human_strength_total_present_cost) # The Net cost from the difference of Total desired stat and Total present stat
    
    print("Net cost: " + str(human_strength_net_cost))
```
\$\endgroup\$
4
  • \$\begingroup\$ "From the way I see it I will have to do for each race the same code 3 times for each stat." Have you considered passing arguments and standardizing your functions to make the whole thing less tedious? Example \$\endgroup\$
    – Mast
    Commented Nov 14, 2020 at 19:35
  • \$\begingroup\$ Why not make use of functions? \$\endgroup\$ Commented Nov 14, 2020 at 19:38
  • \$\begingroup\$ IMO, a constructor with more than 3 data members indicates that the class is doing too much. \$\endgroup\$ Commented Nov 14, 2020 at 19:40
  • \$\begingroup\$ @theProgrammer Thanks for that bit of info!!! I can get around it now :D \$\endgroup\$ Commented Nov 14, 2020 at 20:54

1 Answer 1

1
\$\begingroup\$

If you are just trying to make an interactive calculator, the classes, etc. are not needed.

First, make a simple table that lets you look up the stats based on race. Keep it easy for a human (like you) to edit it, make changes, add new races or stats, etc.

keys = "base_strength base_agility base_health strength_cost agility_cost health_cost".split()

traits = [
    #        base     base    base  strength agility health 
    #race  strength agility  health   cost     cost   cost
    "human    15       17      18      5        3      4",
    "elf      11       21      14      4        3      5",
    "giant    25       11      27      4        8      3",
]

It's just a list of strings. Now transform it into a format that makes it easy to use in a program. We'll turn it into a dict of dicts so we can look up values using something like: stat["elf"]["base_agility"]. Here's the code:

stats = {}

for row in traits:
    row = row.strip().split()
    stats[row[0]] = dict(zip(keys, map(int, row[1:])))

Now your code that calculates the cost of changing strength for a human, can be turned into a generic function that works for any race or stat:

def calc_change_cost(race, stat_name, present_value, desired_value):
    base_value = stats[race][f"base_{stat_name}"]
    stat_cost = stats[race][f"{stat_name}_cost"]

    present_statdif = present_value - base_value
    present_stat_cost = stat_cost + (present_statdif - 1) * stat_cost
    total_present_cost = (present_statdif / 2) * (stat_cost + present_stat_cost)

    desired_statdif = desired_value - base_value
    desired_stat_cost = stat_cost + (desired_statdif - 1) * stat_cost
    total_desired_cost = (desired_statdif / 2) * (stat_cost + desired_stat_cost)

    net_cost = total_desired_cost - total_present_cost

    return net_cost

You'll notice the repeated code for calculating total_present_cost and total_desired_cost. Those lines could be refactored into another function (an exercise for the reader).

Now, the main program just collects the user's inputs, calls the function above, and prints the results:

user_race = str(input("Enter your race (Human, Giant, Elf):")).lower()
user_stat = str(input("Enter your desired stat (Strength, Agility, Health):")).lower()
present_value = int(input("Enter your present stat value:"))
desired_value = int(input("Enter your desired stat value:"))

net_cost = calc_change_cost(user_race, user_stat, present_value, desired_value)
print(f"Net cost to change {user_race} {user_stat} from {present_value} to {desired_value}: {net_cost}")
\$\endgroup\$
1
  • \$\begingroup\$ Holy... That's amazing what you did. I managed to write a script for this but it isn't anywhere as good as yours. I get results but the code is very basic and long since I don't know much about python. Thanks for this :D \$\endgroup\$ Commented Jan 28, 2021 at 5:45

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.