Mars or bust!

Goats in space

In the last lesson, you saw reusable functions to input strings. Let's take that further. Here's a more complex app that reuses lots of code.

Reuse is key to cost reduction. Employers looooove hearing about cost reduction.

We're planning a trip to Mars. We're going to send goats. There'll be big, medium, and small goats on the ship. Valid values for each one are integers from 0 to 100.

Each goat will need food, water, and oxygen. Water and oxygen are mainly reclaimed, but there'll be some loss. They'll need topping up.

Supplies cost money, of course. Space-grade supplies cost more than their terrestrial versions.

Let's write a program to work out how much food, water, and oxygen we'll need for the trip, and what it will cost. Use input validation loops, so users enter correct values.

Here's a table of requirements for each goat type per month:

Size Food (kg) Water (lt) Oxygen (lt)
Small 60 2.2 2.8
Medium 130 5.1 6.9
Large 200 9.4 12.3

Months is an integer from 1 to 96.

Here's what the supplies cost:

  • Food: $32.50 per kilo
  • Water: $17.23 per liter
  • Oxygen: $31.84 per liter

Here's some sample I/O:

  • How many small goats? 8
  • How many medium goats? some
  • Sorry, you must enter a whole number.
  • How many medium goats? -22
  • Sorry, please enter a number between 0 and 100 .
  • How many medium goats? 4
  • How many large goats? 2.2
  • Sorry, you must enter a whole number.
  • How many large goats? 2
  • How many months?a few
  • Sorry, you must enter a whole number.
  • How many months?28
  • =======================
  • Goats in Space-ace-ace
  •  
  • Input
  • ------
  • Small goats: 8
  • Medium goats: 4
  • Large goats: 2
  • Months: 28
  •  
  • Output
  • ------
  • Food
  •   Amount: 39200 kg
  •   Cost: $ 1274000.0
  • Water
  •   Amount: 1590.4 lt
  •   Cost: $ 27402.59
  • Oxygen
  •   Amount: 2088.8 lt
  •   Cost: $ 66507.39
  •  
  • Total cost: $ 1367909.98

OK, guys... GO!

Structure

Ray
Ray

Wait, what!? We've never learned how to do that! I don't know anything about space stuff!

Adela
Adela

Maybe we have learned how to do it. On the surface, this is about space, but let's look under the surface.

Is there a pattern we can use?

Ethan
Ethan

You know, the I/O looks like we could use the IPO pattern.

Pattern

IPO

One of the simplest patterns:

  • Code to put valid input data into variables.
  • Code to work out anything output needs that isn't in the input.
  • Code to output variable values.

Note

If you don't know how to start planning a program, patterns can help.

Georgina
Georgina

You're right. The I/O has input, processing, and output. We know how to do them.

I'd start with comments.

  • # Compute cost of supplies for Mars trip for goats.
  • # By the Scoobies, July 7, Year of the Dragon.
  •  
  • # Input
  •  
  • # Processing
  •  
  • # Output

That OK?

Adela
Adela

I like making structure diagrams, showing the variables each chunk needs. It is OK if we do that?

Note

A structure diagram shows the chunks making up the program, and the variables linking the chunks. You learned about them earlier.

Georgina
Georgina

Sounds like a plan.

Ray
Ray

If you think it will help. I'm still panicking a bit.

Ethan
Ethan

I think Adela's on the right track. Let's try making a structure diagram, and see where it takes us.

Note

Some people like structure diagrams. Others skip that step, and write comments. That's what I do. Do whatever works for you.

Adela
Adela

OK. I like Draw.IO for these tasks.

(Worky work)

Here's what I've got so far.

Structure diagram

First structure diagram​

Adela
Adela

OK, now I'll add the variables that go from input to processing.

Structure diagram with variables

​Added variables

Ray
Ray

How did you know what to add?

Adela
Adela

I looked at the I/O. It asked the user for four things.

  • How many small goats? 8
  • How many medium goats? some
  • Sorry, you must enter a whole number.
  • How many medium goats? -22
  • Sorry, please enter a number between 0 and 100 .
  • How many medium goats? 4
  • How many large goats? 2.2
  • Sorry, you must enter a whole number.
  • How many large goats? 2
  • How many months?a few
  • Sorry, you must enter a whole number.
  • How many months?28
Ray
Ray

Oh, OK. I see it now.

Adela
Adela

(Worky work)

Structure diagram - final

​​Added more variables

Ray
Ray

I see what you did there. You looked at the output part of the I/O, and made variables for the data the output code needs.

  • How many small goats? 8
  • How many medium goats? some
  • Sorry, you must enter a whole number.
  • How many medium goats? -22
  • Sorry, please enter a number between 0 and 100 .
  • How many medium goats? 4
  • How many large goats? 2.2
  • Sorry, you must enter a whole number.
  • How many large goats? 2
  • How many months?a few
  • Sorry, you must enter a whole number.
  • How many months?28
  • =======================
  • Goats in Space-ace-ace
  •  
  • Input
  • ------
  • Small goats: 8
  • Medium goats: 4
  • Large goats: 2
  • Months: 28
  •  
  • Output
  • ------
  • Food
  •   Amount: 39200 kg
  •   Cost: $ 1274000.0
  • Water
  •   Amount: 1590.4 lt
  •   Cost: $ 27402.59
  • Oxygen
  •   Amount: 2088.8 lt
  •   Cost: $ 66507.39
  •  
  • Total cost: $ 1367909.98
Adela
Adela

Are those variable names OK?

Ethan
Ethan

Yep. Lowercase, underscores, and the names tell you what we'll use the variables for.

Looks like we have a plan for the program.

Input

Note

The Scoobies have finished working on the structure of the program. Now they can drill down on the first bit.

Georgina
Georgina

Great! Now let's work on the input. How about these comments?

  • # Compute cost of supplies for Mars trip for goats.
  • # By the Scoobies, July 7, Year of the Dragon.
  •  
  • # Input
  •  
  • # How many small goats?
  •  
  • # How many medium goats?
  •  
  • # How many large goats?
  •  
  • # How many months?
  •  
  •  
  • # Processing
  •  
  •  
  • # Output
Ethan
Ethan

It might be cool if we used functions for this. We could even have one function to do all the input. What do you think?

Georgina
Georgina

Ooo! I like it! Let's give it a try.

We can call the funciton get_input, or something.

Ray
Ray

OK, but... we'll have code like goats = get_input(), something like that, right?

Georgina
Georgina

Kinda. Like this:

  • def get_input():
  •     Something
  •     return small_goats, medium_goats, large_goats, months
  •  
  • small_goats, medium_goats, large_goats, months = get_input()
Ray
Ray

Oh, right! I forgot, you can get a bunch of things back from a function.

Multiple choice

What's a "prompt" in Python programming?

Saving
A

The start of a story about program design.

B

Code to speed up the processing step of IPO.

C

A label used in output, like "Total:" in:

print('Total: ', total)
D

A label used in input, like "How many? " in:

quantity = int(input('How many? '))

Not graded. So why do it?

Adela
Adela

I like where this is going!

Hey, check out this I/O. The same pattern for each goat size.

  • How many small goats? 8
  • How many medium goats? some
  • Sorry, you must enter a whole number.
  • How many medium goats? -22
  • Sorry, please enter a number between 0 and 100 .
  • How many medium goats? 4
  • How many large goats? 2.2
  • Sorry, you must enter a whole number.
  • How many large goats? 2
Reflect

What does Adela mean?

If you were logged in as a student, the lesson would pause here, and you'd be asked to type in a response. If you want to try that out, ask for an account on this site.
Ethan
Ethan

The I/O's the same for each goat type, almost. Just the prompt's different.

The inputs have the same minimum and maximum values, too, 0 and 100.

Maybe... we could write one function to get one input, and call it three times? With different prompts?

Maybe like:

  • def get_input():
  •     small_goats = get_one_goat_input('small')
  •     medium_goats = get_one_goat_input('medium')
  •     large_goats = get_one_goat_input('large')
Ray
Ray

Nice!

What about the months?

Georgina
Georgina

Let's think this through, see what's different about goats and months. There's the prompt, goats vs. months. The minimum and maximum values are different, too. 0 to 100 for goats, 1 to 96 for months.

Ray
Ray

Oh... so... We could write a function that takes these three things: prompt, minimum valid, and maximum valid. As parameters, I mean.

Maybe like:

  • def get_input():
  •     small_goats = get_one_input('How many small goats? ', 0, 100)
  •     medium_goats = get_one_input('How many medium goats? ', 0, 100)
  •     large_goats = get_one_input('How many large goats? ', 0, 100)
  •     months = get_one_input('How many months? ', 1, 96)
  •     return small_goats, medium_goats, large_goats, months
Ethan
Ethan

Dude, that's great! One function to rule them all.

Georgina
Georgina

So good, my precious. I likses it!

Note

The Scoobies are working on the program structure. They're found some repeated behavior, and are thinking about how to use functions to improve their program. This will make their work easier, and the work of future programmers who update the code.

Adela
Adela

Anyone mind if I try writing the input function?

(The rest of the troupe murmur positively.)

Adela
Adela

Let's see. I'll start with the stuff we wrote before.

  1. is_input_ok = False
  2. while not is_input_ok:
  3.     # Start off assuming data is OK.
  4.     is_input_ok = True
  5.     # Get input from the user.
  6.     user_input = input('Meal cost? ')
  7.     # Is the input numeric?
  8.     try:
  9.         meal_cost = float(user_input)
  10.     except ValueError:
  11.         print('Sorry, you must enter a number.')
  12.         is_input_ok = False
  13.     # Check the range.
  14.     if is_input_ok:
  15.         if meal_cost <= 0 or meal_cost > 1000000:
  16.             print('Sorry, please enter a number more than zero, and less than 1,000,000.')
  17.             is_input_ok = False
Adela
Adela

We need to change is line 6, change the prompt. It's a parameter now...

  • def get_one_input(prompt, min, max):
  •     ...
  •     user_input = input(prompt)
Adela
Adela

OK, line 9 is meal_cost = float(user_input). We can't use meal_cost anymore. I'll just call it value for now.

  • value = float(user_input)
Georgina
Georgina

Should it be a float?

Adela
Adela

Huh? Let's see... Oh! The spec says:

- - DOODLEE DOO, DOODLEE DOO (that's flashback music) - -

There'll be big, medium, and small goats on the ship. Valid values for each one are integers from 0 to 100.

...

Months is an integer from 1 to 96.

- - DOO DOODLEE, DOO DOODLEE - -

You're right. It should be:

  • value = int(user_input)
Adela
Adela

The only other thing we need to change is here:

  •         if meal_cost <= 0 or meal_cost > 1000000:
  •             print('Sorry, please enter a number more than zero, and less than 1,000,000.')
Adela
Adela

Should be:

  •             if value < min or value > max:
  •                 print('Sorry, please enter a number between ' + str(min) + ' and ' + str(max) + '.')
Adela
Adela

Oh, and the return. Here's the whole function.

  • def get_one_input(prompt, min, max):
  •     is_input_ok = False
  •     while not is_input_ok:
  •         # Start off assuming data is OK.
  •         is_input_ok = True
  •         # Get input from the user.
  •         user_input = input(prompt)
  •         # Is the input an integer?
  •         try:
  •             value = int(user_input)
  •         except ValueError:
  •             print('Sorry, you must enter a whole number.')
  •             is_input_ok = False
  •         # Check the range.
  •         if is_input_ok:
  •             if value < min or value > max:
  •                 print('Sorry, please enter a number between ' + str(min) + ' and ' + str(max) + '.')
  •                 is_input_ok = False
  •     return value
Ethan
Ethan

Could we put this in a test program? Just this function. Isolate it from the rest.

Maybe like this:

  • def get_one_input(prompt, min, max):
  •     is_input_ok = False
  •     while not is_input_ok:
  •         # Start off assuming data is OK.
  •         is_input_ok = True
  •         # Get input from the user.
  •         user_input = input(prompt)
  •         # Is the input an integer?
  •         try:
  •             value = int(user_input)
  •         except ValueError:
  •             print('Sorry, you must enter a whole number.')
  •             is_input_ok = False
  •         # Check the range.
  •         if is_input_ok:
  •             if value < min or value > max:
  •                 print('Sorry, please enter a number between ' + str(min) + ' and ' + str(max) + '.')
  •                 is_input_ok = False
  •     return value
  •  
  • value = get_one_input('Type an int:' , 0, 100)
  • print('Value: ' + str(value))
Principle

Incremental testing

Test code as you write it. Write a bit, test a bit, write a bit, test a bit.

It's more efficient than writing an entire program at once, and then testing it.

Adela
Adela

Good idea!

Reflect

Does the test program work?

If you were logged in as a student, the lesson would pause here, and you'd be asked to type in a response. If you want to try that out, ask for an account on this site.
  • runfile('D:/documentz/python course...')
  • Type an int:9
  • Value: 9
  •  
  • runfile('D:/documentz/python course...')
  • Type an int: 32
  • Value: 32
  •  
  • runfile('D:/documentz/python course...')
  • Type an int:-1
  • Sorry, please enter a number between 0 and 100 .
  • Type an int:1000
  • Sorry, please enter a number between 0 and 100 .
  • Type an int:2.7
  • Sorry, you must enter a whole number.
  • Type an int:66
  • Value: 66
Adela
Adela

Scoobies FTW!

Note

It's common to write test programs for code chunks.

The code so far, including docstrings:

  • # Compute cost of supplies for Mars trip for goats.
  • # By the Scoobies, July 12, Year of the Dragon.
  •  
  • def get_input():
  •     '''
  •     Get and validate input.
  •  
  •     Returns
  •     -------
  •     small_goats : int
  •         Number of small goats.
  •     medium_goats : int
  •         Number of medium goats.
  •     large_goats : int
  •         Number of large goats.
  •     months : int
  •         Estimated travel time.
  •  
  •     '''
  •     small_goats = get_one_input('How many small goats? ', 0, 100)
  •     medium_goats = get_one_input('How many medium goats? ', 0, 100)
  •     large_goats = get_one_input('How many large goats? ', 0, 100)
  •     months = get_one_input('How many months?', 1, 96)
  •     return small_goats, medium_goats, large_goats, months
  •  
  •  
  • def get_one_input(prompt, min, max):
  •     '''
  •     Get a numeric input value.
  •  
  •     Parameters
  •     ----------
  •     prompt : string
  •         Prompt to show the user.
  •     min : int
  •         Smallest value allowed.
  •     max : int
  •         Largest value allowed.
  •  
  •     Returns
  •     -------
  •     value : int
  •         What the user typed.
  •  
  •     '''
  •     is_input_ok = False
  •     while not is_input_ok:
  •         # Start off assuming data is OK.
  •         is_input_ok = True
  •         # Get input from the user.
  •         user_input = input(prompt)
  •         # Is the input an integer?
  •         try:
  •             value = int(user_input)
  •         except ValueError:
  •             print('Sorry, you must enter a whole number.')
  •             is_input_ok = False
  •         # Check the range.
  •         if is_input_ok:
  •             if value < min or value > max:
  •                 print('Sorry, please enter a number between ' + str(min) + ' and ' + str(max) + '.')
  •                 is_input_ok = False
  •     return value
  •  
  • # Input
  •  
  • small_goats, medium_goats, large_goats, months = get_input()

Processing

Ray
Ray

Processing looks hard. What do we do?

Ethan
Ethan

You know how we did the program's structure?

Ray
Ray

Oh, yeah. The thing Adela drew.

Structure diagram - final

​​Structure diagram

Note

The structure shows the parameters and return values of big program chunks. Particularly helpful when you're using functions.

Adela
Adela

OK, if we make one processing function, we can call it as usual. But... we'll let me show you.

  • food_needed, food_cost, water_needed, water_cost, oxy_needed, oxy_cost, total_cost = compute_stuff(small_goats, medium_goats, large_goats)
Georgina
Georgina

Wow, that's messy. It's be easy to mess up, too, get variables in the wrong order. I read earlier that's a common mistake.

Ethan
Ethan

Yeah. But... there's kinda two things going on. Two big steps to working everything out.

Reflect

What are the two big steps in processing?

If you were logged in as a student, the lesson would pause here, and you'd be asked to type in a response. If you want to try that out, ask for an account on this site.
Georgina
Georgina

I see it now.

  • Use number of goats to work out food, water, and oxy needed.
  • Use food, water, and oxy needed to work out costs.

Think we should split them up?

Ethan
Ethan

Would that work?

Georgina
Georgina

It should. Let me give the calls a try.

  • # Input
  • small_goats, medium_goats, large_goats, months = get_input()
  •  
  • # Processing
  • food_needed, water_needed, oxy_needed = compute_resources_needed(small_goats, medium_goats, large_goats, months)
  • food_cost, water_cost, oxy_cost, total_cost = compute_resource_costs(food_needed, water_needed, oxy_needed)

Note

Try to keep the number of parameters and return values to three or four.

Multiple choice

What is a function's signature?

Saving
A

The function's name, parameters, and return types.

B

A mapping from a function's parameters to its return values.

C

The function's docstring.

D

Deets on who wrote the function, and when.

Not graded. So why do it?

Reflect

Write compute_resources_needed.

If you were logged in as a student, the lesson would pause here, and you'd be asked to type in a response. If you want to try that out, ask for an account on this site.

Ray?

Ray
Ray

Me again? Um, OK.

Let me check the specs.

- - DOODLEE DOO, DOODLEE DOO - -

Here's a table of requirements for each goat type per month:

Size Food (kg) Water (lt) Oxygen (lt)
Small 60 2.2 2.8
Medium 130 5.1 6.9
Large 200 9.4 12.3

- - DOO DOODLEE, DOO DOODLEE - -

We got goats, we got these numbers... I'll start with the signature.

  • def compute_resources_needed(small_goats, medium_goats, large_goats, months):
  •     Stuff
  •     return food_needed, water_needed, oxy_needed
Ray
Ray

Now the calcs. Use the table... here.

  • def compute_resources_needed(small_goats, medium_goats, large_goats, months):
  •     food_needed = (small_goats * 60 + medium_goats * 130 + large_goats * 200) * months
  •     water_needed = (small_goats * 2.2 + medium_goats * 5.1 + large_goats * 9.4) * months
  •     oxy_needed = (small_goats * 2.8 + medium_goats * 6.9 + large_goats * 12.3) * months
  •     return food_needed, water_needed, oxy_needed
Ray
Ray

Add docstring... Umm, the parameters are ints, but there are things like 2.2 and 2.8 in the calcs. They're floats. food_needed and the others might be floats.

  • def compute_resources_needed(small_goats, medium_goats, large_goats, months):
  •     '''
  •     Work out how much of each resources will be needed,
  •     given number of goats and mission length.
  •  
  •     Parameters
  •     ----------
  •     small_goats : int
  •         Number of small goats.
  •     medium_goats : int
  •         Number of medium goats.
  •     large_goats : int
  •         Number of large goats.
  •     months : int
  •         Number of months the mission will take.
  •  
  •     Returns
  •     -------
  •     food_needed : float
  •         Food needed in kg.
  •     water_needed : float
  •         Water needed in liters.
  •     oxy_needed : float
  •         Oxy needed in liters.
  •     '''
  •     food_needed = (small_goats * 60 + medium_goats * 130 + large_goats * 200) * months
  •     water_needed = (small_goats * 2.2 + medium_goats * 5.1 + large_goats * 9.4) * months
  •     oxy_needed = (small_goats * 2.8 + medium_goats * 6.9 + large_goats * 12.3) * months
  •     return food_needed, water_needed, oxy_needed

Testing

Reflect

Write a test program to see if the code above works.

If you were logged in as a student, the lesson would pause here, and you'd be asked to type in a response. If you want to try that out, ask for an account on this site.
Georgina
Georgina

Yes! I'll do this one.

I'll put the code into a new program, and add a few lines.

Ready to test

Ray
Ray

I see what you did there. Put in a breakpoint on line 37. Then we check the Variable Explorer.

Georgina
Georgina

Yep! And I put simple values in the variables, easy to test.

Let's give it a try.

Results

Adela
Adela

Let's see... 60 plus 130 plus...

Everything works!

Adela
Adela

Let's try some different values for the variables...

Yay! Works!

Processing part deux

Georgina
Georgina

We have part 1 of the processing. Onto the next bit.

  • # Input
  • small_goats, medium_goats, large_goats, months = get_input()
  •  
  • # Processing
  • food_needed, water_needed, oxy_needed = compute_resources_needed(small_goats, medium_goats, large_goats, months)
  • food_cost, water_cost, oxy_cost, total_cost = compute_resource_costs(food_needed, water_needed, oxy_needed)
Ray
Ray

Can I give it a try?

Let's see... Here's the signature first.

  • def compute_resource_costs(food_needed, water_needed, oxy_needed):
  •  
  •     return food_cost, water_cost, oxy_cost, total_cost

Note

Ray's written the code connecting the new function to the rest of the program. Now he can work on the deets.

Reflect

Write the new function, and a test program for it.

If you were logged in as a student, the lesson would pause here, and you'd be asked to type in a response. If you want to try that out, ask for an account on this site.
Ray
Ray

Here's the specs:

- - DOODLEE DOO, DOODLEE DOO - -

Here's what the supplies cost:

Food: $32.50 per kilo Water: $17.23 per liter Oxygen: $31.84 per liter

- - DOO DOODLEE, DOO DOODLEE - -

OK, here's what I have, with the docstring.

  • def compute_resource_costs(food_needed, water_needed, oxy_needed):
  •     '''
  •     Work out how much the supplies will cost.
  •  
  •     Parameters
  •     ----------
  •     food_needed : float
  •         Food needed.
  •     water_needed : float
  •         Water needed.
  •     oxy_needed : float
  •         Oxygen needed.
  •  
  •     Returns
  •     -------
  •     food_cost : float
  •         Food cost.
  •     water_cost : float
  •         Water cost.
  •     oxy_cost : float
  •         Oxygen cost.
  •     total_cost : float
  •         Total cost.
  •  
  •     '''
  •     food_cost = food_needed * 32.5
  •     water_cost = water_needed * 17.23
  •     oxy_cost = oxy_needed * 31.84
  •     total_cost = food_cost + water_cost + oxy_cost
  •     return food_cost, water_cost, oxy_cost, total_cost
  •  
  • food_needed = 1
  • water_needed = 1
  • oxy_needed = 1
  •  
  • food_cost, water_cost, oxy_cost, total_cost \
  •     = compute_resource_costs(food_needed, water_needed, oxy_needed)
  •  
  • print('Break and use VE')
Ray
Ray

Ya know, that was much easier than I thought.

Note

The function was easy for Ray because the Scoobies had broken the task into chunks. Easy is good.

Ray
Ray

For the test program, I'm using Georgina's method. Put a breakpoint at the end, and check the VE.

Debug results

Ray
Ray

They're all good, except for total_cost. It's a tiny bit out.

Is that a problem, Kieran?

No. Just a result of how Python handles floats.

Ethan
Ethan

Could we round it to two decimal places if we like?

Aye. Various ways, but the easiest is the round function.

  • round(value, 2)

Use this in the output.

Reflect

Try round in the console. Does it work?

If you were logged in as a student, the lesson would pause here, and you'd be asked to type in a response. If you want to try that out, ask for an account on this site.
Ray
Ray

I put this in the console: round(23.13293993, 2) in the console. I got 23.13. That's a round down.

I tried this: round(23.666666, 2) in the console. I got 23.67. That's a round up.

Works!

Output

Adela
Adela

Just output to go.

We can make a function for that, too. It's gonna have oodles of parameters, though!

I'll give it a try. Might as well use it in the final program.

  • # Compute cost of supplies for Mars trip for goats.
  • # By the Scoobies, July 12, Year of the Dragon.
  •  
  • def get_input():
  •     '''
  •     Get and validate input.
  •  
  •     Returns
  •     -------
  •     small_goats : int
  •         Number of small goats.
  •     medium_goats : int
  •         Number of medium goats.
  •     large_goats : int
  •         Number of large goats.
  •     months : int
  •         Estimated travel time.
  •  
  •     '''
  •     small_goats = get_one_input('How many small goats? ', 0, 100)
  •     medium_goats = get_one_input('How many medium goats? ', 0, 100)
  •     large_goats = get_one_input('How many large goats? ', 0, 100)
  •     months = get_one_input('How many months? ', 1, 96)
  •     return small_goats, medium_goats, large_goats, months
  •  
  •  
  • def get_one_input(prompt, min, max):
  •     '''
  •     Get a numeric input value.
  •  
  •     Parameters
  •     ----------
  •     prompt : string
  •         Prompt to show the user.
  •     min : int
  •         Smallest value allowed.
  •     max : int
  •         Largest value allowed.
  •  
  •     Returns
  •     -------
  •     value : int
  •         What the user typed.
  •  
  •     '''
  •     is_input_ok = False
  •     while not is_input_ok:
  •         # Start off assuming data is OK.
  •         is_input_ok = True
  •         # Get input from the user.
  •         user_input = input(prompt)
  •         # Is the input an integer?
  •         try:
  •             value = int(user_input)
  •         except ValueError:
  •             print('Sorry, you must enter a whole number.')
  •             is_input_ok = False
  •         # Check the range.
  •         if is_input_ok:
  •             if value < min or value > max:
  •                 print('Sorry, please enter a number between ' + str(min) + ' and ' + str(max) + '.')
  •                 is_input_ok = False
  •     return value
  •  
  • def compute_resources_needed(small_goats, medium_goats, large_goats, months):
  •     '''
  •     Work out how much of each resources will be needed,
  •     given number of goats and mission length.
  •  
  •     Parameters
  •     ----------
  •     small_goats : int
  •         Number of small goats.
  •     medium_goats : int
  •         Number of medium goats.
  •     large_goats : int
  •         Number of large goats.
  •     months : int
  •         Number of months the mission will take.
  •  
  •     Returns
  •     -------
  •     food_needed : float
  •         Food needed in kg.
  •     water_needed : float
  •         Water needed in liters.
  •     oxy_needed : float
  •         Oxy needed in liters.
  •     '''
  •     food_needed = (small_goats * 60 + medium_goats * 130 + large_goats * 200) * months
  •     water_needed = (small_goats * 2.2 + medium_goats * 5.1 + large_goats * 9.4) * months
  •     oxy_needed = (small_goats * 2.8 + medium_goats * 6.9 + large_goats * 12.3) * months
  •     return food_needed, water_needed, oxy_needed
  •  
  • def compute_resource_costs(food_needed, water_needed, oxy_needed):
  •     '''
  •     Work out how much the supplies will cost.
  •  
  •     Parameters
  •     ----------
  •     food_needed : float
  •         Food needed.
  •     water_needed : float
  •         Water needed.
  •     oxy_needed : float
  •         Oxygen needed.
  •  
  •     Returns
  •     -------
  •     food_cost : float
  •         Food cost.
  •     water_cost : float
  •         Water cost.
  •     oxy_cost : float
  •         Oxygen cost.
  •     total_cost : float
  •         Total cost.
  •  
  •     '''
  •     food_cost = food_needed * 32.5
  •     water_cost = water_needed * 17.23
  •     oxy_cost = oxy_needed * 31.84
  •     total_cost = food_cost + water_cost + oxy_cost
  •     return food_cost, water_cost, oxy_cost, total_cost
  •  
  •  
  • def show_output(small_goats, medium_goats, large_goats, months,
  •             food_needed, water_needed, oxy_needed,
  •             food_cost, water_cost, oxy_cost, total_cost):
  •     '''
  •     Output results.
  •  
  •     Parameters
  •     ----------
  •     small_goats : int
  •         Small goats to send.
  •     medium_goats : int
  •         Medium goats to send.
  •     large_goats : int
  •         Large goats to send.
  •     months : int
  •         Mission length.
  •     food_needed : float
  •         How much food we need.
  •     water_needed : float
  •         How much water we need.
  •     oxy_needed : float
  •         How much oxygen we need.
  •     food_cost : float
  •         Food cost.
  •     water_cost : float
  •         Water cost.
  •     oxy_cost : float
  •         Oxygen cost.
  •     total_cost : float
  •         Total cost.
  •  
  •     Returns
  •     -------
  •     None.
  •  
  •     '''
  •     print('=======================')
  •     print('Goats in Space-ace-ace')
  •     print()
  •     print('Input')
  •     print('------')
  •     print('Small goats: ' + str(small_goats))
  •     print('Medium goats: ' + str(medium_goats))
  •     print('Large goats: ' + str(large_goats))
  •     print('Months: ' + str(months))
  •     print()
  •     print('Output')
  •     print('------')
  •     print('Food')
  •     print(' Amount: ' + str(round(food_needed, 2)) + 'kg')
  •     print(' Cost: $' + str(round(food_cost, 2)))
  •     print('Water')
  •     print(' Amount: ' + str(round(water_needed, 2)) + 'lt')
  •     print(' Cost: $' + str(round(water_cost, 2)))
  •     print('Oxygen')
  •     print(' Amount: ' + str(round(oxy_needed, 2)), 'lt')
  •     print(' Cost: $' + str(round(oxy_cost, 2)))
  •     print()
  •     print('Total cost: $'+ str(total_cost))
  •  
  • # Input
  • small_goats, medium_goats, large_goats, months = get_input()
  •  
  • # Processing
  • food_needed, water_needed, oxy_needed = compute_resources_needed(small_goats, medium_goats, large_goats, months)
  • food_cost, water_cost, oxy_cost, total_cost = compute_resource_costs(food_needed, water_needed, oxy_needed)
  •  
  • # Output
  • show_output(small_goats, medium_goats, large_goats, months,
  •             food_needed, water_needed, oxy_needed,
  •             food_cost, water_cost, oxy_cost, total_cost)

(Test, test, test, test...)

Adela
Adela

It all worked, cowboys! Pow pow pow! We rock!

Summary

  • The Scoobies broke the program into three pieces, following the IPO template.
  • They made a structure diagram to show what data passed between the chunks.
  • All input is gathered by one function (get_one_input). The Scoobies used parameters to customize the prompt, min, and max.
  • They broke processing into two functions, to keep things easy.
  • The round() function rounds floats.