5
\$\begingroup\$

I'm super new to python and programming in general. I made this using my computer knowledge to calculate the processing power and power draw of a computer based on the specifications of all the parts.

from termcolor import colored
#COLORS:
#Magenta - welcome/version/credits
#Cyan - questions
#Yellow - scores
#Red - errors
#orange - might use this color later
#green - Copyright
def start():
  global type
  print(colored("=-_"*50,"white",attrs=["blink"]))
  print(colored("* Welcome to Spicy's Processing Power / TDP Calculator! (SPPTDPC) *", "magenta"))
  print(colored("* Version Alpha 2.2 *", "magenta"))
  print(colored("** This program is still in alpha stage and isn't perfect **", "magenta"))
  print(colored("If you are unsure about one of the questions, look up the specs of the part on a website like PCPartPicker or TechPowerUP", "magenta"))
  type = float(input(colored("Is your computer a laptop or desktop? 1 for laptop, 2 for desktop.", "cyan")))
  cpu()
def cpu():
    global r
    global cpus
    global cputdp
    name = input(colored("What is the name of your processor?", "cyan"))
    c = float(input(colored("How many cores does the "+name+" have?", "cyan")))
    t = float(input(colored("How many threads does the "+name+" have?", "cyan")))
    l1 = float(input(colored("How much L1 cache (in total) does the "+name+" have in KB?", "cyan")))
    l2 = float(input(colored("How much L2 cache (in total) does the "+name+" have in MB?", "cyan")))
    l3 = float(input(colored("How much L3 cache (in total) does the "+name+" have in MB?", "cyan")))
    g = float(input(colored("What is the clock speed (in GHz) of the "+name+"?", "cyan")))
    n = float(input(colored("What is the fabrication process of the "+name+" in nm?", "cyan")))
    r = float(input(colored("What type of RAM does the "+name+" use? Enter 3 for DDR3, 4 for DDR4, etc.", "cyan")))
    cputdp = float(input(colored("What is the TDP of the "+name+"? (in W)", "cyan")))
    cpus = ((c+t+g+r+l2+(l1/100)+(.3*l3))/n)*type #CPU Processing Power Formula
    print(colored("** The "+name+" has a score of "+str(cpus)+". **", "yellow"))
    ram()
def ram():
  global rtdp
  global rams
  g = float(input(colored("How much RAM does your system have (in GB?)", "cyan")))
  m = float(input(colored("What is the speed of your slowest installed DIMM? (in MHz)", "cyan")))
  rtdp = float(input(colored("How many DIMMs do you have installed?", "cyan")))
  rtdp = rtdp*4
  rams = ((r+(m/500))*g)/150 #RAM Processing Power Formula
  print(colored("** Your RAM score is "+str(rams)+". **", "yellow"))
  gpu()
def gpu():
  gputest()
  print(colored("** The "+gpuname+" has a score of "+str(gpus)+". **", "yellow"))
  gputdp = float(input(colored("What is the TDP of the "+gpuname+"?", "cyan")))
def gputest():
    global gpuname
    global memtyp
    global gputdp
    gpuname = input(colored("What is the name of your GPU?", "cyan"))
    memtyp = int(input(colored("What type of memory does your GPU use? 0 for GDDR, 1 for HBM", "cyan")))
    gputdp = float(input(colored("What is the TDP of your GPU? (in W)", "cyan")))
    if memtyp == 0:
        gddr()
    if memtyp == 1:
        hbm()
def gddr():
  global gpus
  gc = float(input(colored("How many cores does the "+gpuname+" have?", "cyan")))
  gt = float(input(colored("How many TMUs does the "+gpuname+" have?", "cyan")))
  go = float(input(colored("How many ROPs does the "+gpuname+" have?", "cyan")))
  gm = float(input(colored("How much memory (in MB) does the "+gpuname+" have?", "cyan")))
  gr = float(input(colored("What type of memory does the "+gpuname+" have? Enter 3 for GDDR3, 5 for GDDR5, and 8 for GDDR5X (to account for its additional data rate)", "cyan")))
  gb = float(input(colored("What is the bus width of the "+gpuname+"?", "cyan")))       
  gg = float(input(colored("What is the clock speed of the "+gpuname+" in GHz?", "cyan")))
  gmg = float(input(colored("What is the effective memory speed of the "+gpuname+" in MHz?", "cyan")))
  gn = float(input(colored("What is the fabrication process of the "+gpuname+" in nm?", "cyan")))
  gpus = ((((gc/400)+(gt/25)+(go/10)+(gm/1000)+(gb/30)+(gg*2)+(gmg/1000))*((gr/gn)/25)))*type #GDDR GPU Processing Power Formula
  drive()
def hbm():
  global gpus
  hgc = float(input(colored("How many cores does the "+gpuname+" have?", "cyan")))
  hgt = float(input(colored("How many TMUs does the "+gpuname+" have?", "cyan")))
  hgo = float(input(colored("How many ROPs does the "+gpuname+" have?", "cyan")))
  hgm = float(input(colored("How much memory (in MB) does the "+gpuname+" have?", "cyan")))
  hgr = float(input(colored("What type of HBM does the "+gpuname+" have? Enter 1 for HBM, 2 for HBM2, etc.", "cyan")))
  hgb = float(input(colored("What is the bus width of the "+gpuname+"?", "cyan")))      
  hgg = float(input(colored("What is the clock speed of the "+gpuname+" in GHz?", "cyan")))
  hgmg = float(input(colored("What is the effective memory speed of the "+gpuname+" in MHz?", "cyan")))
  hgn = float(input(colored("What is the fabrication process of the "+gpuname+" in nm?", "cyan")))
  gpus = (((hgc/400)+(hgt/25)+(hgo/10)+(hgm/1000)+(hgb/250)+(hgg*2)+(hgmg/150))/((hgr/hgn)/25))*type #HBM GPU Processing Power Formula
  drive()
def drive():
  print(colored("** The "+gpuname+" has a score of "+str(gpus)+". **", "yellow"))
  global typ
  typ = float(input(colored("Is your boot drive an HDD or SSD? Enter 1 for HDD, 2 for SSD.", "cyan")))
  if typ == 1:
    hdd()
  if typ == 2:
    ssd()
def hdd():
  global free
  global total
  global hds
  rpm = float(input(colored("What is the RPM of your HDD?", "cyan")))
  free = float(input(colored("How much storage is available (not filled) on your boot drive (in GB)", "cyan")))
  total = float(input(colored("What is the total amount of storage on your boot drive (in GB)", "cyan")))
  freespace()
  hds = (((1/p)*100)*(rpm/1000))/30 #HDD Processing Power Formula
  drivetdp()
def ssd():
  global free
  global total
  global hds
  free = float(input(colored("How much storage is available (not filled) on your boot drive (in GB)", "cyan")))
  total = float(input(colored("What is the total amount of storage on your boot drive (in GB)", "cyan")))
  freespace()
  hds = ((((1/p)*100)*5)*typ)/30 #SSD Processing Power Formula
  drivetdp()
def freespace():
  global p
  p = (free/total)*100
  print(colored("* Your boot drive is "+str(p)+"% free. *", "yellow"))
def drivetdp():
  global ssdtdp
  global hddtdp
  ssdtdp = float(input(colored("How many SSDs do you have installed in your system?", "cyan")))
  ssdtdp = ssdtdp*3.25
  hddtdp = float(input(colored("How many HDDs do you have installed in your system?", "cyan")))
  hddtdp = hddtdp*8
  print(colored("** Your boot drive's score is "+str(hds)+". **", "yellow"))
  final()
def final():
  global fns
  global tdp
  global psu
  global fantdp
  fns = (cpus+gpus+hds+rams) #Final Score Formula
  dvdtdp = float(input(colored("How many optical drives do you have installed?", "cyan")))
  dvdtdp = dvdtdp*10*type #1 ODD draws around 20 watts, I'm assuming laptop ODDs use half of that.
  if type == 2:
    fantdp = float(input(colored("How many case fans do you have installed? (counting CPU cooler)", "cyan")))
    fantdp = fantdp*5 #1 120mm fan draws around 5 watts
  if type == 1:
    fantdp = 0
  usbtdp = float(input(colored("How many USB ports does your computer have? (in total)", "cyan")))
  usbtdp = usbtdp*2.5 #USB can only pull 2.5 watts
  tdp = (((cputdp+gputdp)*(4/5))+rtdp+hddtdp+ssdtdp+dvdtdp+fantdp+usbtdp)+50 #estimated max load TDP equation, the +50 watts is for the motherboard
  psu = cputdp+gputdp+rtdp+hddtdp+ssdtdp+dvdtdp+usbtdp+50 #max spec TDP equation
  print(colored("Calculating final score...", "magenta"))
  print(colored("** Your final score is... **", "yellow"))
  print(str(fns))
  print(colored("** Your predicted maximum load wattage is... **", "yellow"))
  print(str(tdp)+" Watts")
  print(colored("** I would recommend using a power supply of at least "+str(psu)+" watts. **", "yellow"))
  print(colored("Thank you for using SPPC!", "magenta"))
  print(colored("Copyright NFR 2018", "green", attrs=["blink"]))
  print(colored("=-_"*50,"white",attrs=["blink"]))
  again()
def again():
  again = input(colored("Do you want to use the calculator again? Y/N", "cyan"))
  if again == "Y":
      start()
start()
#Copyright NFR 2018
\$\endgroup\$
2
2
\$\begingroup\$

Welcome to CodeReview! I think that separation by colors looks very nice :)

Now, I suggest to take a look at PEP 8 style guide and try to follow it. Some text editors and IDEs even have support of highlighting the places where you violate it. They make life much easier.
Some points from there that you could apply to your code:

  • Surround top-level function and class definitions with two blank lines.

  • Use 4 spaces per indentation level.

  • Limit all lines to a maximum of 79 characters.

  • Inline comments should be separated by at least two spaces from the statement. They should start with a # and a single space.

  • Add whitespaces around operators and after commas, for example:

    print(colored("=-_" * 50, "white", attrs=["blink"]))
    

Wrap start() line in the following construct:

if __name__ == '__main__':
    start()

For explanations I suggest to read here.


About globals. Please, don't use them. Read Why is Global State so Evil?.
Instead of using globals learn how to pass parameters to functions. For example, your cpu function could accept variable type like this:

def start():    
    ...
    type = float(input(colored("Is your computer a laptop or desktop? 1 for laptop, 2 for desktop.", "cyan")))
    cpu(type)

def cpu(type):
    ...

Give better names to your variables, not one-letter names. For example:

t -> threads_count
g -> clock_speed
r -> ram_type
etc...

Note that type is a name of a built-in function. You are shadowing it.

Also, some variable names in your code are for different things, like g. In one place it's amount of RAM, in another it's a clock speed. Give different names for them.


If you are with Python 3.6 then you can use f-strings. For example, instead of your

"How many cores does the " + name + " have?"

you could write:

f"How many cores does the {name} have?"

Looks pretty.


You could use partial to reduce amount of code when printing colored output. For example:

from functools import partial

magenta = partial(colored,
                  color='magenta')
...
print(magenta("* Version Alpha 2.2 *"))

As it says by the link above: it just makes new version of a function colored with an argument color already filled in.


Finally, one of the most important things. Now your program runs in a following manner:

def start():
    function_1()


def function_1():
    function_2()


def function_2():
    function_3()

...

if __name__ == '__main__':
   start()

You are making a long chain of functions calling one another. Read When, if ever, should I daisy chain functions? for explanations about why it is bad and what you should do instead.


Probably there is more, I didn't go too much into details. But this should be enough for now. Happy coding! :)


Edit:

In the comment you said that you don't see the point of a lot of the things that I mentioned in my answer. I will try to give explanations to some of them and show you your code after refactoring (after applying all the points).

  • Style guides. This is absolutely voluntary part. You are not obliged to follow them. But I think that it is very nice when you look at other person's code and it looks like it is something that you could write yourself as it looks very similar. Many of the points aren't taken out from thin air. For example, if you'd limit the lines up to 79 characters then we wouldn't need to scroll your code horizontally.

  • if __name__ == '__main__'. If you don't use it then if someone wants to import a module with your code, your code will start to be executed automatically on import. Usually we don't want that. I will show how to use this in the refactored code.

  • Self-explanatory names. Always think that you are writing code for other people. And other people will have no idea what you meant by hgmg or r. I had to look at input messages to understand what you meant by them.

  • Global variables. Long time ago I also thought that there was nothing bad about them until I had to start working with the code where there were hundreds of them... That was pain... Everything could be accessed from anywhere. Whenever I had a problem I had a long process of tracking how and where exactly value for a variable was assigned. And it was always a relief when the problem was with a function that didn't have any global variables inside, it just accepted some parameters and returned a value. If it's not clear for you now then it will become clear later :)

Now refactored code based on the 2nd version that you inserted by edit (shouldn't have done that by the way). Also, note that I didn't fix everything here there is still some work left for you to do ;)

from functools import partial

from termcolor import colored

magenta = partial(colored,
                  color='magenta')
cyan = partial(colored,
               color='cyan')
yellow = partial(colored,
                 color='yellow')


def run():
    pc_type = start()
    cpu_tdp, ram_type, cpu_score = cpu(pc_type)
    ram_score, ram_tdp = ram(ram_type)
    gputdp, gpu_score = gpu(pc_type)
    drive_score, drive_type = drive()
    hddtdp, ssdtdp = drivetdp(drive_score)
    total_tdp = final(pc_type=pc_type,
                      cpu_score=cpu_score,
                      cpu_tdp=cpu_tdp,
                      drive_score=drive_score,
                      gpu_score=gpu_score,
                      gputdp=gputdp,
                      hddtdp=hddtdp,
                      ram_score=ram_score,
                      ram_tdp=ram_tdp,
                      ssdtdp=ssdtdp)
    btlcalc1(pc_type=pc_type,
             cpu_score=cpu_score,
             drive_score=drive_score,
             drive_type=drive_type,
             gpu_score=gpu_score,
             ram_score=ram_score)
    hrscalc(total_tdp=total_tdp)
    again()
    thanks()


def start():
    print(colored("'." * 70,
                  color='white',
                  attrs=['blink']))
    print(magenta("* Welcome to Spicy's  Ultimate Computer Utility *"))
    print(magenta("* Version Alpha 3.0 *"))
    print(magenta("** This program is still in alpha stage "
                  "and isn't perfect **"))
    print(magenta("If you are unsure about one of the questions, "
                  "look up the specs of the part on a website "
                  "like PCPartPicker or TechPowerUP"))
    print(magenta("** Make sure to pay attention to the units "
                  "specified in the questions. **"))
    return float(input(cyan("Is your computer a laptop or desktop? "
                            "1 for laptop, 2 for desktop.")))


def cpu(pc_type):
    name = input(cyan("What is the name of your processor?"))
    tdp = float(input(cyan(f"What is the TDP of the {name}? (in W)")))
    cores_count = float(input(cyan(f"How many cores does the {name} have?")))
    threads_count = float(input(cyan(f"How many threads "
                                     f"does the {name} have?")))
    l1_cache = float(input(cyan(f"How much L1 cache (in total) "
                                f"does the {name} have in KB?")))
    l2_cache = float(input(cyan(f"How much L2 cache (in total) "
                                f"does the {name} have in MB?")))
    l3_cache = float(input(cyan(f"How much L3 cache (in total) "
                                f"does the {name} have in MB?")))
    clock_speed = float(input(cyan(f"What is the clock speed (in GHz) "
                                   f"of the {name}?")))
    fabrication = float(input(cyan(f"What is the fabrication process "
                                   f"of the {name} in nm?")))
    ram_type = float(input(cyan(f"What type of RAM does the {name} use? "
                                f"Enter 3 for DDR3, 4 for DDR4, etc.")))
    score = ((cores_count + threads_count + clock_speed + ram_type + l2_cache
              + (l1_cache / 100) + (.3 * l3_cache))
             / fabrication) * pc_type
    print(yellow(f"** The {name} has a score of {round(score, 5)}. **"))
    return tdp, ram_type, score


def ram(ram_type):
    amount = float(input(cyan("How much RAM does your system have "
                              "(in GB?)")))
    slowest_dimm_speed = float(input(cyan("What is the speed of your slowest "
                                          "installed DIMM? (in MHz)")))
    dimms_count = (float(input(cyan("How many DIMMs do you have installed?")))
                   * 4)
    score = ((ram_type + (slowest_dimm_speed / 500)) * amount) / 150
    print(yellow(f"** Your RAM score is {round(score, 5)} . **"))
    return score, dimms_count


def gpu(pc_type):
    name = input(cyan("What is the name of your GPU?"))
    memory_type = int(input(cyan(f"What type of memory does the {name} use? "
                                 f"0 for GDDR, 1 for HBM")))
    tdp = float(input(cyan(f"What is the TDP of the {name}? (in W)")))

    if memory_type == 0:
        cores_count = float(input(cyan(f"How many cores "
                                       f"does the {name} have?")))
        tmus_count = float(input(cyan(f"How many TMUs "
                                      f"does the {name} have?")))
        rops_count = float(input(cyan(f"How many ROPs "
                                      f"does the {name} have?")))
        memory_size = float(input(cyan(f"How much memory (in MB) "
                                       f"does the {name} have?")))
        memory_type = float(input(cyan(f"What type of memory "
                                       f"does the {name} have? "
                                       f"Enter 3 for GDDR3, 5 for GDDR5, "
                                       f"and 8 for GDDR5X.")))
        # GDDR5X is 8 to account for its additional data rate
        bus_width = float(input(cyan(f"What is the bus width "
                                     f"of the {name}?")))
        clock_speed = float(input(cyan(f"What is the clock speed "
                                       f"of the {name} in GHz?")))
        memory_speed = float(input(cyan(f"What is the effective memory speed "
                                        f"of the {name} in MHz?")))
        fabrication = float(input(cyan(f"What is the fabrication process "
                                       f"of the {name} in nm?")))
        score = ((((cores_count / 400) + (tmus_count / 25) + (rops_count / 10)
                   + (memory_size / 1000) + (bus_width / 30)
                   + (clock_speed * 2) + (memory_speed / 1000))
                  * ((memory_type / fabrication) / 25))) * pc_type

    if memory_type == 1:
        cores_count = float(input(cyan(f"How many cores "
                                       f"does the {name} have?")))
        tmus_count = float(input(cyan(f"How many TMUs "
                                      f"does the {name} have?")))
        rops_count = float(input(cyan(f"How many ROPs "
                                      f"does the {name} have?")))
        memory_size = float(input(cyan(f"How much memory (in MB) "
                                       f"does the {name} have?")))
        memory_type = float(input(cyan(f"What type of memory "
                                       f"does the {name} have? "
                                       f"Enter 1 for HBM, 2 for HBM2, etc.")))
        # GDDR5X is 8 to account for its additional data rate
        bus_width = float(input(cyan(f"What is the bus width "
                                     f"of the {name}?")))
        clock_speed = float(input(cyan(f"What is the clock speed "
                                       f"of the {name} in GHz?")))
        memory_speed = float(input(cyan(f"What is the effective memory speed "
                                        f"of the {name} in MHz?")))
        fabrication = float(input(cyan(f"What is the fabrication process "
                                       f"of the {name} in nm?")))
        score = (((cores_count / 400) + (tmus_count / 25) + (rops_count / 10)
                  + (memory_size / 1000) + (bus_width / 250)
                  + (clock_speed * 2) + (memory_speed / 150))
                 / ((memory_type / fabrication) / 25)) * pc_type
    print(yellow(f"** The {name} has a score of {round(score, 5)} . **"))

    return tdp, score


def drive():
    drive_type = float(input(cyan("Is your boot drive an HDD or SSD? "
                                  "Enter 1 for HDD, 2 for SSD.")))
    if drive_type == 1:
        hdd_rpm = float(input(cyan("What is the RPM of your HDD?")))
        drive_free = float(input(cyan("How much storage is available "
                                      "(not filled) on your boot drive "
                                      "(in GB)")))
        drive_total = float(input(cyan("What is the total amount of storage "
                                       "on your boot drive (in GB)")))
        percent_free = (drive_free / drive_total) * 100
        print(yellow(f"* Your boot drive is "
                     f"{round(percent_free, 3)} % free. *"))
        drive_score = (((1 / percent_free) * 100) * (hdd_rpm / 1000)) / 30
    if drive_type == 2:
        drive_free = float(input(cyan(f"How much storage is available "
                                      f"(not filled) on your boot drive "
                                      f"(in GB)")))
        drive_total = float(input(cyan("What is the total amount of storage "
                                       "on your boot drive (in GB)")))
        percent_free = (drive_free / drive_total) * 100
        print(yellow(f"* Your boot drive is "
                     f"{round(percent_free, 3)} % free. *"))
        drive_score = ((((1 / percent_free) * 100) * 5) * drive_type) / 30

    return drive_score, drive_type


def drivetdp(drive_score):
    ssdtdp = float(input(cyan("How many SSDs do you have "
                              "installed in your system?")))
    ssdtdp *= 3.25  # 1 SSD draws this much watts
    hddtdp = float(input(cyan(f"How many HDDs do you have "
                              f"installed in your system?")))
    hddtdp *= 8  # 1 HDD draws this much watts
    print(colored(f"** Your boot drive's score is "
                  f"{round(drive_score, 5)} . **"))
    return hddtdp, ssdtdp


def final(pc_type,
          cpu_score,
          gpu_score,
          drive_score,
          ram_score,
          cpu_tdp,
          gputdp,
          ram_tdp,
          hddtdp,
          ssdtdp):
    final_score = (cpu_score + gpu_score + drive_score + ram_score)
    dvdtdp = float(input(cyan("How many optical drives "
                              "do you have installed?")))
    # 1 ODD draws around 20 watts, I'm assuming laptop ODDs use half of that.
    dvdtdp = dvdtdp * 10 * pc_type

    if pc_type == 2:
        fantdp = float(input(cyan("How many case fans do you have installed? "
                                  "(counting CPU cooler)")))
        fantdp *= 5  # 1 120mm fan draws around 5 watts
    if pc_type == 1:
        fantdp = 0

    usbtdp = float(input(cyan("How many USB ports does your computer have? "
                              "(in total)")))
    usbtdp *= 2.5  # USB can only pull 2.5 watts
    # Estimated max load TDP equation, the +50 watts is for the motherboard
    total_tdp = (((cpu_tdp + gputdp) * (4 / 5)) + ram_tdp + hddtdp + ssdtdp
                 + dvdtdp + fantdp + usbtdp) + 50
    # max spec TDP equation
    recommended_psu = (cpu_tdp + gputdp + ram_tdp + hddtdp + ssdtdp + dvdtdp
                       + usbtdp + 75)
    print(magenta("Calculating final score..."))
    print(yellow("** Your final score is... **"))
    print(round(final_score, 5))
    print(yellow("** Your predicted maximum load wattage is... **"))
    print(f"{round(total_tdp, 1)} Watts")
    print(yellow(f"** I would recommend using a power supply of at least "
                 f"{int(round(recommended_psu, -1))} watts. **"))
    return total_tdp


def hrscalc(total_tdp):
    hrscalc = input(cyan("Would you also like to factor in "
                         "your energy costs? Y/N"))
    if hrscalc == "Y":
        hrs = float(input(cyan("On average, how many hours do you use "
                               "your computer daily?")))
        price = float(input(cyan("What is the price per kWh "
                                 "where you live? (in dollars)")))
        ktdp = total_tdp / 1000  # TDP in kW
        dailycost = hrs * price * ktdp
        hourcost = dailycost / 24
        weeklycost = dailycost * 7
        monthlycost = dailycost * 30.42
        yearlycost = dailycost * 365
        print(yellow(f"Your cost is ${round(hourcost, 2)} per hour, "
                     f"${round(dailycost, 2)} per day, "
                     f"${round(weeklycost, 2)} per week, "
                     f"${round(monthlycost, 2)} per month, "
                     f"and ${round(yearlycost, 2)} per year."))


def btlcalc1(pc_type,
             gpu_score,
             ram_score,
             drive_score,
             cpu_score,
             drive_type):
    print(yellow("Calculating bottleneck..."))
    if pc_type == 1:  # laptop
        bgpus = gpu_score * 3.5
        brams = ram_score * 4
        bhds = drive_score * 5
        bcpus = cpu_score * 2
    if pc_type == 2:  # desktop
        btlscore = ((gpu_score * 1.75) + (ram_score * 4)
                    + (drive_score * 5) + (cpu_score * 2))
        bgpus = gpu_score * 1.75
        brams = ram_score * 4
        bhds = drive_score * 5
        bcpus = cpu_score
    if bgpus <= brams and bgpus <= bhds and bgpus <= bcpus:
        gpub = 1
        cpub = 0
        ramb = 0
        hdb = 0
    if bcpus <= brams and bcpus <= bhds and bcpus <= bgpus:
        gpub = 0
        cpub = 1
        ramb = 0
        hdb = 0
    if brams <= bcpus and brams <= bhds and brams <= bgpus:
        gpub = 0
        cpub = 0
        ramb = 1
        hdb = 0
    if bhds <= brams and bhds <= bcpus and bhds <= bgpus:
        gpub = 0
        cpub = 0
        ramb = 0
        hdb = 1
    if gpub == 1:
        print(yellow("Your GPU is the bottleneck in your system."))
        print(yellow("You could improve your GPU score "
                     "by overclocking or replacing your GPU."))
    if cpub == 1:
        print(yellow("Your CPU is the bottleneck in your system."))
        print(yellow("You could improve your CPU score "
                     "by overclocking or replacing your CPU."))
    if ramb == 1:
        print(yellow("Your RAM is the bottleneck in your system."))
        print(yellow("You could improve your RAM score "
                     "by overclocking, replacing, "
                     "or installing more or faster RAM."))
    if hdb == 1:
        print(yellow("Your boot disk is the bottleneck in your system."))
        if drive_type == 1:
            print(yellow("You could improve your boot disk score "
                         "by replacing your HDD with a faster HDD or an SSD, "
                         "or by freeing up space."))
        if drive_type == 2:
            print(yellow("You could improve your boot disk score "
                         "by freeing up space."))


def thanks():
    print(magenta("Thank you for using SPPC!"))
    print(colored("Copyright NFR 2018",
                  color='green'))


def again():
    again = input(cyan("Do you want to use the calculator again? Y/N"))
    if again == 'Y':
        start()

if __name__ == '__main__':
    run()

Some other notes that came to mind after refactoring:

  1. Python has augmented assignments. It means that instead of writing a = a * b you can write a *= b.
  2. You don't need to convert numbers to strings when printing them.
  3. btlscore is never used.
  4. Function hrscalc has a variable with the same name in it. Why not name this function like calculate_energy_cost? Why not give more explanatory names to other functions as well?
  5. again() now won't work as intended. Now as you eliminated that daisy-chaining, you will have to think of other way to repeat all the steps if user wants it. How about while-loop?
  6. Now you are checking for positive answer if it is 'Y'. What if I type 'y'? What if I misclicked and typed something else?
  7. You can see that in the refactored code I renamed some variables. For example, in function cpu all your variables were named like cpu_speed. But it is clear that this speed is of a cpu. So name it just speed.
  8. You have many magic numbers in your code. You can make them constants or default function arguments.
  9. You have some blocks of code that have many repetitions. You should fix that :)
\$\endgroup\$
5
  • 1
    \$\begingroup\$ The last point, I think, is the most important. The program is using functions as if they were goto labels, and that is absolutely inappropriate. \$\endgroup\$ Feb 19 '18 at 21:10
  • \$\begingroup\$ See my newest edit, I addressed some of these concerns. However, I personally don't see the point of a lot of these things you want me to change. I still have NO IDEA how not to use globals or why they are bad, and I haven't figured out how to do the if main == name thing either. All the things you told me seem to be structural/formatting things that have little to no impact on the program itself. I'm only in high school and almost all the links you sent are beyond my years. I appreciate your input but frankly your suggestions seem to be a lot of work involved with little to no reward. \$\endgroup\$
    – Spicy
    Feb 22 '18 at 3:38
  • 1
    \$\begingroup\$ @Spicy Please, see my edit. \$\endgroup\$
    – Georgy
    Feb 23 '18 at 20:28
  • \$\begingroup\$ @Georgy Thanks for the detailed explanation, I appreciate it. I think there is some ways I can shorten the code and remove the need for magic numbers and solve some the other issues. And I think I'm beginning to understand how not to use globals. I really appreciate what you've done for the program and I'll work on it some more once school projects cool down a bit and I have more time. Is it fine if I put you in the credits? \$\endgroup\$
    – Spicy
    Feb 25 '18 at 18:34
  • 1
    \$\begingroup\$ Oh, there is no need for that. I am just glad to be of some help :) Good luck with school projects! \$\endgroup\$
    – Georgy
    Feb 25 '18 at 18:55
0
\$\begingroup\$

Version Alpha 3.4 of the program is now out. Not sure what other features/improvements I could add to it. If anyone has suggestions please let me know. The main added feature in this update is the removal of magic numbers and removing unnecessary bits from the code, along with improving function names. Also special thanks to Georgy for help with pretty much the whole thing.

from functools import partial

from termcolor import colored

magenta = partial(colored,
                  color='magenta')
cyan = partial(colored,
               color='cyan')
yellow = partial(colored,
                 color='yellow')


def run():
    pc_type = start()
    cpu_tdp, ram_type, cpu_score = cpu(pc_type)
    ram_score, ram_tdp = ram(ram_type)
    gputdp, gpu_score = gpu(pc_type)
    drive_score, drive_type = drive1()
    hddtdp, ssdtdp = drive2(drive_score)
    total_tdp = final(pc_type=pc_type,
                      cpu_score=cpu_score,
                      cpu_tdp=cpu_tdp,
                      drive_score=drive_score,
                      gpu_score=gpu_score,
                      gputdp=gputdp,
                      hddtdp=hddtdp,
                      ram_score=ram_score,
                      ram_tdp=ram_tdp,
                      ssdtdp=ssdtdp)
    bottleneck(pc_type=pc_type,
             cpu_score=cpu_score,
             drive_score=drive_score,
             drive_type=drive_type,
             gpu_score=gpu_score,
             ram_score=ram_score)
    energy_cost_calc(total_tdp=total_tdp)
    again()
    thanks()


def start():
    print(colored("'." * 70,
                  color='white',
                  attrs=['blink']))
    print(magenta("* Welcome to Spicy's  Ultimate Computer Utility *"))
    print(magenta("* Version Alpha 3.4 *"))
    print(magenta("** This program is still in alpha stage "
                  "and isn't perfect **"))
    print(magenta("If you are unsure about one of the questions, "
                  "look up the specs of the part on a website "
                  "like PCPartPicker or TechPowerUP"))
    print(magenta("** Make sure to pay attention to the units "
                  "specified in the questions. **"))
    return float(input(cyan("Is your computer a laptop or desktop? "
                            "1 for laptop, 2 for desktop.")))


def cpu(pc_type):
    l1_factor = 100 #The smaller this is, the more L1 cache matters
    l3_factor = .3 #The larger this is, the more L3 cache matters
    name = input(cyan("What is the name of your processor?"))
    tdp = float(input(cyan(f"What is the TDP of the {name}? (in W)")))
    cores_count = float(input(cyan(f"How many cores does the {name} have?")))
    threads_count = float(input(cyan(f"How many threads "
                                     f"does the {name} have?")))
    l1_cache = float(input(cyan(f"How much L1 cache (in total) "
                                f"does the {name} have in KB?")))
    l2_cache = float(input(cyan(f"How much L2 cache (in total) "
                                f"does the {name} have in MB?")))
    l3_cache = float(input(cyan(f"How much L3 cache (in total) "
                                f"does the {name} have in MB?")))
    clock_speed = float(input(cyan(f"What is the clock speed (in GHz) "
                                   f"of the {name}?")))
    fabrication = float(input(cyan(f"What is the fabrication process "
                                   f"of the {name} in nm?")))
    ram_type = float(input(cyan(f"What type of RAM does the {name} use? "
                                f"Enter 3 for DDR3, 4 for DDR4, etc.")))
    score = ((cores_count + threads_count + clock_speed + ram_type + l2_cache
              + (l1_cache / l1_factor) + (l3_factor * l3_cache))
             / fabrication) * pc_type
    print(yellow(f"** The {name} has a score of {round(score, 5)}. **"))
    return tdp, ram_type, score


def ram(ram_type):
    ram_tdp_factor = 4 #1 RAM stick draws around 4W
    dimm_speed_factor = 500 #The smaller this is, the more speed matters
    ram_equation_factor = 150 #The smaller this is, the less RAM score matters overall
    amount = float(input(cyan("How much RAM does your system have "
                              "(in GB?)")))
    slowest_dimm_speed = float(input(cyan("What is the speed of your slowest "
                                          "installed DIMM? (in MHz)")))
    dimms_count = (float(input(cyan("How many DIMMs do you have installed?")))
                   * ram_tdp_factor)
    score = ((ram_type + (slowest_dimm_speed / dimm_speed_factor)) * amount) / ram_equation_factor
    print(yellow(f"** Your RAM score is {round(score, 5)}. **"))
    return score, dimms_count


def gpu(pc_type):
    name = input(cyan("What is the name of your GPU?"))
    memory_type = int(input(cyan(f"What type of memory does the {name} use? "
                                 f"0 for GDDR, 1 for HBM")))
    tdp = float(input(cyan(f"What is the TDP of the {name}? (in W)")))

    if memory_type == 0:
        cores_factor = 400 #The smaller this is, the more cores matter
        tmus_factor = 25 #the smaller this is, the more TMUs matter
        rops_factor = 10 #the smaller this is, the more ROPs matter
        memsize_factor = 1000 #the smaller this is, the more VRAM amount matters
        buswidth_factor = 30 #the smaller this is, the more bus width matters
        clockspeed_factor = 2 #the larger this is, the more clockspeed matters
        memspeed_factor = 1000 #the smaller this is, the more VRAM speed matters
        gpu_equation_factor = 25 #the smaller this is, the more GPU score matters overall
        cores_count = float(input(cyan(f"How many cores "
                                       f"does the {name} have?")))
        tmus_count = float(input(cyan(f"How many TMUs "
                                      f"does the {name} have?")))
        rops_count = float(input(cyan(f"How many ROPs "
                                      f"does the {name} have?")))
        memory_size = float(input(cyan(f"How much memory (in MB) "
                                       f"does the {name} have?")))
        memory_type = float(input(cyan(f"What type of memory "
                                       f"does the {name} have? "
                                       f"Enter 3 for GDDR3, 5 for GDDR5, "
                                       f"and 8 for GDDR5X.")))
        # GDDR5X is 8 to account for its additional data rate
        bus_width = float(input(cyan(f"What is the bus width "
                                     f"of the {name}?")))
        clock_speed = float(input(cyan(f"What is the clock speed "
                                       f"of the {name} in GHz?")))
        memory_speed = float(input(cyan(f"What is the effective memory speed "
                                        f"of the {name} in MHz?")))
        fabrication = float(input(cyan(f"What is the fabrication process "
                                       f"of the {name} in nm?")))
        score = ((((cores_count / cores_factor) + (tmus_count / tmus_factor) + (rops_count / rops_factor)
                   + (memory_size / memsize_factor) + (bus_width / buswidth_factor)
                   + (clock_speed * clockspeed_factor) + (memory_speed / memspeed_factor))
                  * ((memory_type / fabrication) / gpu_equation_factor))) * pc_type

    if memory_type == 1:
        cores_factor = 400 #The smaller this is, the more cores matter
        tmus_factor = 25 #the smaller this is, the more TMUs matter
        rops_factor = 10 #the smaller this is, the more ROPs matter
        memsize_factor = 1000 #the smaller this is, the more VRAM amount matters
        buswidth_factor = 250 #the smaller this is, the more bus width matters
        clockspeed_factor = 2 #the larger this is, the more clockspeed matters
        memspeed_factor = 150 #the smaller this is, the more VRAM speed matters
        gpu_equation_factor = 25 #the smaller this is, the more GPU score matters overall
        cores_count = float(input(cyan(f"How many cores "
                                       f"does the {name} have?")))
        tmus_count = float(input(cyan(f"How many TMUs "
                                      f"does the {name} have?")))
        rops_count = float(input(cyan(f"How many ROPs "
                                      f"does the {name} have?")))
        memory_size = float(input(cyan(f"How much memory (in MB) "
                                       f"does the {name} have?")))
        memory_type = float(input(cyan(f"What type of memory "
                                       f"does the {name} have? "
                                       f"Enter 1 for HBM, 2 for HBM2, etc.")))
        # GDDR5X is 8 to account for its additional data rate
        bus_width = float(input(cyan(f"What is the bus width "
                                     f"of the {name}?")))
        clock_speed = float(input(cyan(f"What is the clock speed "
                                       f"of the {name} in GHz?")))
        memory_speed = float(input(cyan(f"What is the effective memory speed "
                                        f"of the {name} in MHz?")))
        fabrication = float(input(cyan(f"What is the fabrication process "
                                       f"of the {name} in nm?")))
        score = (((cores_count / cores_factor) + (tmus_count / tmus_factor) + (rops_count / rops_factor)
                  + (memory_size / memsize_factor) + (bus_width / buswidth_factor)
                  + (clock_speed * clockspeed_factor) + (memory_speed / memspeed_factor))
                 / ((memory_type / fabrication) / gpu_equation_factor)) * pc_type
    print(yellow(f"** The {name} has a score of {round(score, 5)}. **"))

    return tdp, score


def drive1():
    drive_equation_factor = 30 #the smaller this is, the more drive score matters overall
    drive_type = float(input(cyan("Is your boot drive an HDD or SSD? "
                                  "Enter 1 for HDD, 2 for SSD.")))
    if drive_type == 1:
        rpm_factor = 1000 #the smaller this is, the more HDD RPM matters
        hdd_rpm = float(input(cyan("What is the RPM of your HDD?")))
        drive_free = float(input(cyan("How much storage is available "
                                      "(not filled) on your boot drive "
                                      "(in GB)")))
        drive_total = float(input(cyan("What is the total amount of storage "
                                       "on your boot drive (in GB)")))
        percent_free = (drive_free / drive_total) * 100
        print(yellow(f"* Your boot drive is "
                     f"{round(percent_free, 3)}% free. *"))
        drive_score = (((1 / percent_free) * 100) * (hdd_rpm / rpm_factor)) / drive_equation_factor
    if drive_type == 2:
        ssd_factor = 5 #the larger this is, the more drive score will increase if SSD is boot drive
        drive_free = float(input(cyan(f"How much storage is available "
                                      f"(not filled) on your boot drive "
                                      f"(in GB)")))
        drive_total = float(input(cyan("What is the total amount of storage "
                                       "on your boot drive (in GB)")))
        percent_free = (drive_free / drive_total) * 100
        print(yellow(f"* Your boot drive is "
                     f"{round(percent_free, 3)}% free. *"))
        drive_score = ((((1 / percent_free) * 100) * ssd_factor) * drive_type) / drive_equation_factor

    return drive_score, drive_type


def drive2(drive_score):
    ssdtdp = float(input(cyan("How many SSDs do you have "
                              "installed in your system?")))
    ssdtdp *= 3.25  # 1 SSD draws this much watts (the *= thing means ssdtdp = ssdtdp*3.25)
    hddtdp = float(input(cyan(f"How many HDDs do you have "
                              f"installed in your system?")))
    hddtdp *= 8  # 1 HDD draws this much watts
    print(yellow(f"** Your boot drive's score is "
                  f"{round(drive_score, 5)}. **"))
    return hddtdp, ssdtdp


def final(pc_type,
          cpu_score,
          gpu_score,
          drive_score,
          ram_score,
          cpu_tdp,
          gputdp,
          ram_tdp,
          hddtdp,
          ssdtdp):
    cpu_gpu_tdp_factor = 0.8 #the larger this is, the more to remove from CPU and GPU TDP (because they don't reach full spec)
    mainboard_tdp = 50 #the motherboard will draw around 50W by itself
    final_score = (cpu_score + gpu_score + drive_score + ram_score)
    dvdtdp = float(input(cyan("How many optical drives "
                              "do you have installed?")))
    # 1 ODD draws around 20 watts, I'm assuming laptop ODDs use half of that.
    dvdtdp = dvdtdp * 10 * pc_type

    if pc_type == 2:
        fantdp = float(input(cyan("How many case fans do you have installed? "
                                  "(counting CPU cooler)")))
        fantdp *= 4  # 1 120mm fan draws around 4 watts

    if pc_type == 1:
        fantdp = 0.5 #I will assume that laptops' cooling solutions use 0.5 watts total

    usbtdp = float(input(cyan("How many USB ports does your computer have? "
                              "(in total)")))
    usbtdp *= 2.5  # USB can only pull 2.5 watts max
    # Estimated max load TDP equation
    total_tdp = (((cpu_tdp + gputdp) * cpu_gpu_tdp_factor) + ram_tdp + hddtdp + ssdtdp
                 + dvdtdp + fantdp + usbtdp) + mainboard_tdp
    # max spec TDP equation
    psu_factor = 75 #The larger this is, the more "extra" watts to recommend for the PSU 
                    #since a PSU should never reach full spec
    recommended_psu = (cpu_tdp + gputdp + ram_tdp + hddtdp + ssdtdp + dvdtdp
                       + usbtdp + psu_factor)
    print(magenta("Calculating final score..."))
    print(yellow("** Your final score is... **"))
    print(round(final_score, 5))
    print(yellow("** Your predicted maximum load wattage is... **"))
    print(f"{round(total_tdp, 1)} Watts")
    print(yellow(f"** I would recommend using a power supply of at least "
                 f"{int(round(recommended_psu, -1))} watts. **"))
    return total_tdp


def energy_cost_calc(total_tdp):
    hrscalc = input(cyan("Would you also like to factor in "
                         "your energy costs? Y/N"))
    if hrscalc == "Y":
        hrs = float(input(cyan("On average, how many hours do you use "
                               "your computer daily?")))
        price = float(input(cyan("What is the price per kWh "
                                 "where you live? (in dollars)")))
        ktdp = total_tdp / 1000  # TDP in kW
        dailycost = hrs * price * ktdp
        hourcost = dailycost / 24
        weeklycost = dailycost * 7
        monthlycost = dailycost * 30.42 #an average month has 30.42 days
        yearlycost = dailycost * 365
        print(yellow(f"Your cost is ${round(hourcost, 2)} per hour, "
                     f"${round(dailycost, 2)} per day, "
                     f"${round(weeklycost, 2)} per week, "
                     f"${round(monthlycost, 2)} per month, "
                     f"and ${round(yearlycost, 2)} per year."))


def bottleneck(pc_type,
             gpu_score,
             ram_score,
             drive_score,
             cpu_score,
             drive_type):
    print(yellow("Calculating bottleneck..."))
    bram_factor = 4
    bdrive_factor = 5
    if pc_type == 1:  # laptop
        bgpu_factor = 3.5
        bcpu_factor = 2
        bgpus = gpu_score * bgpu_factor
        brams = ram_score * bram_factor
        bhds = drive_score * bdrive_factor
        bcpus = cpu_score * bcpu_factor

    if pc_type == 2:  # desktop
        bgpu_factor = 1.75
        bgpus = gpu_score * bgpu_factor
        brams = ram_score * bram_factor
        bhds = drive_score * bdrive_factor
        bcpus = cpu_score

    if bgpus <= brams and bgpus <= bhds and bgpus <= bcpus:
        gpub = 1
        cpub = 0
        ramb = 0
        hdb = 0
    if bcpus <= brams and bcpus <= bhds and bcpus <= bgpus:
        cpub = 1
        gpub = 0
        ramb = 0
        hdb = 0
    if brams <= bcpus and brams <= bhds and brams <= bgpus:
        ramb = 1
        cpub = 0
        gpub = 0
        hdb = 0
    if bhds <= brams and bhds <= bcpus and bhds <= bgpus:
        hdb = 1
        cpub = 0
        ramb = 0
        gpub = 0
    if gpub == 1:
        print(yellow("Your GPU is the bottleneck in your system."))
        print(yellow("You could improve your GPU score "
                     "by overclocking or replacing your GPU."))

    if cpub == 1:
        print(yellow("Your CPU is the bottleneck in your system."))
        print(yellow("You could improve your CPU score "
                     "by overclocking or replacing your CPU."))

    if ramb == 1:
        print(yellow("Your RAM is the bottleneck in your system."))
        print(yellow("You could improve your RAM score "
                     "by overclocking, replacing, "
                     "or installing more or faster RAM."))

    if hdb == 1:
        print(yellow("Your boot disk is the bottleneck in your system."))

        if drive_type == 1:
            print(yellow("You could improve your boot disk score "
                         "by replacing your HDD with a faster HDD or an SSD, "
                         "or by freeing up space."))

        if drive_type == 2:
            print(yellow("You could improve your boot disk score "
                         "by freeing up space."))


def thanks():
    print(magenta("Thank you for using SPPC!"))
    print(colored("Copyright NFR 2018",
                  color='green'))


def again():
    again = input(cyan("Do you want to use the calculator again? Y/N"))
    if again == 'Y':
        start()

if __name__ == '__main__':
    run()
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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