mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(curriculum): add bill splitter workshop (#65517)
Co-authored-by: majestic-owl448 <26656284+majestic-owl448@users.noreply.github.com> Co-authored-by: Dario <105294544+Dario-DC@users.noreply.github.com>
This commit is contained in:
@@ -3754,6 +3754,12 @@
|
||||
"In these lessons, you will learn about numbers and mathematical operations in Python."
|
||||
]
|
||||
},
|
||||
"workshop-bill-splitter": {
|
||||
"title": "Build a Bill Splitter",
|
||||
"intro": [
|
||||
"In this workshop you will build a bill splitter to practice working with numbers and mathematical operations in Python"
|
||||
]
|
||||
},
|
||||
"lecture-booleans-and-conditionals": {
|
||||
"title": "Booleans and Conditionals",
|
||||
"intro": [
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
---
|
||||
id: 69757cc0faae0152c1418aad
|
||||
title: Step 1
|
||||
challengeType: 20
|
||||
dashedName: step-1
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In this workshop, you will practice working with numbers and mathematical operations to build a bill splitter. This tool will calculate how much each person owes after adding meal costs and a tip.
|
||||
|
||||
To start, you need a way to keep track of the total amount as costs are added. In Python, you can use a variable to store an integer (a whole number) that changes over time.
|
||||
|
||||
For example, you might write:
|
||||
|
||||
```py
|
||||
my_number = 2
|
||||
```
|
||||
|
||||
Create a variable named `running_total` and assign it the value `0`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable named `running_total`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_variable('running_total')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should assign the integer `0` to your `running_total` variable.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).find_variable('running_total').is_equivalent('running_total = 0')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: 6976cc0b0c135686a4620b94
|
||||
title: Step 2
|
||||
challengeType: 20
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Next, you need to account for the number of people sharing the bill. Store this value in a variable, as you did in the previous step.
|
||||
|
||||
Create a variable named `num_of_friends` and assign it the value of `4`. This will be used later in the workshop to calculate the final split.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable named `num_of_friends`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_variable('num_of_friends')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should assign the integer `4` to your `num_of_friends` variable.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).find_variable('num_of_friends').is_equivalent('num_of_friends = 4')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
running_total = 0
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
---
|
||||
id: 6976d8a7cd2a1a5ffcd7f9c4
|
||||
title: Step 3
|
||||
challengeType: 20
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Each course has a cost. You need to store these amounts in variables to use them later. Since these amounts include cents, you will use the float type, which is used to represent decimal numbers. Here's an example of a variable with a float value:
|
||||
|
||||
```py
|
||||
change = 2.35
|
||||
```
|
||||
|
||||
Create four variables: `appetizers` set to `37.89`, `main_courses` set to `57.34`, `desserts` set to `39.39`, and `drinks` set to `64.21`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should define a variable named `appetizers` and assign it the value `37.89`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).find_variable('appetizers').is_equivalent('appetizers = 37.89')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should define a variable named `main_courses` and assign it the value `57.34`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).find_variable('main_courses').is_equivalent('main_courses = 57.34')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should define a variable named `desserts` and assign it the value `39.39`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).find_variable('desserts').is_equivalent('desserts = 39.39')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should define a variable named `drinks` and assign it the value `64.21`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).find_variable('drinks').is_equivalent('drinks = 64.21')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
running_total = 0
|
||||
|
||||
num_of_friends = 4
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
---
|
||||
id: 69779dcb44016eccc05c15a4
|
||||
title: Step 5
|
||||
challengeType: 20
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The service was excellent, so the group decides to leave a 25% tip. To calculate a percentage in Python, you can multiply the total by the decimal equivalent of the percentage.
|
||||
|
||||
For example, to find 10% of a value, you would multiply it by `0.10` using the `*` operator:
|
||||
|
||||
```py
|
||||
tax = total * 0.10
|
||||
```
|
||||
|
||||
Create a variable named `tip` and assign it the result of multiplying `running_total` by `0.25`.
|
||||
|
||||
Finally, use `print()` to display the string `Tip amount:` followed by a space and the value of your `tip` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable named `tip`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_variable('tip')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
Your `tip` variable should be the result of `running_total * 0.25`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => runPython(`
|
||||
t = _Node(_code).find_variable('tip')
|
||||
assert t.is_equivalent('tip = running_total * 0.25') or t.is_equivalent('tip = 0.25 * running_total')`)
|
||||
})
|
||||
```
|
||||
|
||||
You should print the string `Tip amount:` followed by a space and the `tip` variable.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_call("print('Tip amount:', tip)") or _Node(_code).has_call("print(f'Tip amount: {tip}')")`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
running_total = 0
|
||||
|
||||
num_of_friends = 4
|
||||
|
||||
appetizers = 37.89
|
||||
main_courses = 57.34
|
||||
desserts = 39.39
|
||||
drinks = 64.21
|
||||
|
||||
running_total = appetizers + main_courses + desserts + drinks
|
||||
print('Total bill so far:', running_total)
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: 6977a4306bb3e856690a4890
|
||||
title: Step 6
|
||||
challengeType: 20
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that you have calculated the tip, you need to add it to your `running_total` to find the final bill amount.
|
||||
|
||||
In Python, you can use the augmented assignment operator `+=` to add a value to a variable and update that variable at the same time. For example, `total += 5` is a shorthand way of writing `total = total + 5`.
|
||||
|
||||
Use the `+=` operator to add the value of `tip` to your `running_total`. Finally, use `print()` to display the string `Total with tip:` followed by a space and the value of `running_total`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `+=` operator to add the value of `tip` to your `running_total`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_stmt('running_total += tip')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should print the string `Total with tip:` followed by a space and the `running_total` variable.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_call("print('Total with tip:', running_total)") or _Node(_code).has_call("print(f'Total with tip: {running_total}')")`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
running_total = 0
|
||||
|
||||
num_of_friends = 4
|
||||
|
||||
appetizers = 37.89
|
||||
main_courses = 57.34
|
||||
desserts = 39.39
|
||||
drinks = 64.21
|
||||
|
||||
running_total = appetizers + main_courses + desserts + drinks
|
||||
print('Total bill so far:', running_total)
|
||||
|
||||
tip = running_total * 0.25
|
||||
print('Tip amount:', tip)
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
---
|
||||
id: 6977a8bbcbdd557886bd0718
|
||||
title: Step 7
|
||||
challengeType: 20
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
With the tip now included, you have the final amount for the entire group. You have to determine how much each person owes by dividing the total bill by the number of friends.
|
||||
|
||||
In Python, you use the forward slash `/` to perform division. For example:
|
||||
|
||||
```py
|
||||
half = 10 / 2
|
||||
```
|
||||
|
||||
Create a variable named `final_bill` and assign it the result of dividing `running_total` by `num_of_friends`.
|
||||
|
||||
Finally, use the `print()` function to display the string `Bill per person:` followed by a space and the value of `final_bill`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should define a variable named `final_bill`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_variable('final_bill')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should use the `/` operator to divide `running_total` by `num_of_friends` and assign the result to your `final_bill` variable.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).find_variable('final_bill').is_equivalent('final_bill = running_total / num_of_friends')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should print the string `Bill per person:` followed by a space and the `final_bill` variable.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_call("print('Bill per person:', final_bill)") or _Node(_code).has_call("print(f'Bill per person: {final_bill}')")`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
running_total = 0
|
||||
|
||||
num_of_friends = 4
|
||||
|
||||
appetizers = 37.89
|
||||
main_courses = 57.34
|
||||
desserts = 39.39
|
||||
drinks = 64.21
|
||||
|
||||
running_total = appetizers + main_courses + desserts + drinks
|
||||
print('Total bill so far:', running_total)
|
||||
|
||||
tip = running_total * 0.25
|
||||
print('Tip amount:', tip)
|
||||
|
||||
running_total += tip
|
||||
print('Total with tip:', running_total)
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
---
|
||||
id: 697a7f71ebfcd9e4cacd69c2
|
||||
title: Step 8
|
||||
challengeType: 20
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The bill is split, but division often results in long decimal numbers. Since money is typically represented with two decimal places, you should round the final result.
|
||||
|
||||
Python provides a built-in `round()` function for this. It takes two arguments: the number you want to round and the number of decimal places to keep. Here's an example:
|
||||
|
||||
```py
|
||||
num = 4.815162342
|
||||
round(num, 3) # 4.815
|
||||
```
|
||||
|
||||
Use the `round()` function to round `final_bill` to two decimal places and assign the result to a new variable named `each_pays`.
|
||||
|
||||
Finally, use `print()` to display the string `Each person pays:` followed by a space and your `each_pays` variable.
|
||||
|
||||
With that, the bill splitter workshop is complete.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should define a variable named `each_pays`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_variable('each_pays')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should use the `round()` function to round `final_bill` to two decimal places and assign the result to your `each_pays` variable.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).find_variable('each_pays').is_equivalent('each_pays = round(final_bill, 2)')
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should use `print()` to display the string `Each person pays:` followed by a space and your `each_pays` variable.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => assert(runPython(`
|
||||
_Node(_code).has_call("print('Each person pays:', each_pays)") or _Node(_code).has_call("print(f'Each person pays: {each_pays}')")`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
running_total = 0
|
||||
|
||||
num_of_friends = 4
|
||||
|
||||
appetizers = 37.89
|
||||
main_courses = 57.34
|
||||
desserts = 39.39
|
||||
drinks = 64.21
|
||||
|
||||
running_total = appetizers + main_courses + desserts + drinks
|
||||
print('Total bill so far:', running_total)
|
||||
|
||||
tip = running_total * 0.25
|
||||
print('Tip amount:', tip)
|
||||
|
||||
running_total += tip
|
||||
print('Total with tip:', running_total)
|
||||
|
||||
final_bill = running_total / num_of_friends
|
||||
print('Bill per person:', final_bill)
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```py
|
||||
running_total = 0
|
||||
|
||||
num_of_friends = 4
|
||||
|
||||
appetizers = 37.89
|
||||
main_courses = 57.34
|
||||
desserts = 39.39
|
||||
drinks = 64.21
|
||||
|
||||
running_total = appetizers + main_courses + desserts + drinks
|
||||
print('Total bill so far:', running_total)
|
||||
|
||||
tip = running_total * 0.25
|
||||
print('Tip amount:', tip)
|
||||
|
||||
running_total += tip
|
||||
print('Total with tip:', running_total)
|
||||
|
||||
final_bill = running_total / num_of_friends
|
||||
print('Bill per person:', final_bill)
|
||||
|
||||
each_pays = round(final_bill, 2)
|
||||
print('Each person pays:', each_pays)
|
||||
```
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
---
|
||||
id: 6982684f3a25f379e195a5fc
|
||||
title: Step 4
|
||||
challengeType: 20
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that you have stored the individual costs, you can calculate the total. In Python, you use the addition operator `+` to sum values together.
|
||||
|
||||
Update the `running_total` variable by adding `appetizers`, `main_courses`, `desserts`, and `drinks` together.
|
||||
|
||||
Finally, use `print()` to display the string `Total bill so far:` followed by a space and the value of `running_total`.
|
||||
|
||||
**Note:** You might notice that the output has more decimal digits than expected. As you learned in a previous lesson, this happens because numbers are stored in binary, and many decimal values cannot be represented exactly in this format, which leads to rounding errors.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should update `running_total` using the `+` operator to sum all four courses cost.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => runPython(`
|
||||
import itertools
|
||||
perms = itertools.permutations(['+ appetizers', '+ main_courses', '+ desserts', '+ drinks'])
|
||||
values = (' '.join(perm).lstrip('+') for perm in perms)
|
||||
solutions = (f'running_total = {v}' for v in values)
|
||||
assert any(_Node(_code).has_stmt(s) for s in solutions)`)
|
||||
})
|
||||
```
|
||||
|
||||
You should print the string `Total bill so far:` followed by a space and the value of `running_total`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => runPython(`
|
||||
sol1 = "print('Total bill so far:', running_total)"
|
||||
sol2 = "print(f'Total bill so far: {running_total}')"
|
||||
assert _Node(_code).has_call(sol1) or _Node(_code).has_call(sol2)`)
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
running_total = 0
|
||||
|
||||
num_of_friends = 4
|
||||
|
||||
appetizers = 37.89
|
||||
main_courses = 57.34
|
||||
desserts = 39.39
|
||||
drinks = 64.21
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Build a Bill Splitter",
|
||||
"isUpcomingChange": false,
|
||||
"dashedName": "workshop-bill-splitter",
|
||||
"helpCategory": "Python",
|
||||
"blockLayout": "challenge-grid",
|
||||
"challengeOrder": [
|
||||
{ "id": "69757cc0faae0152c1418aad", "title": "Step 1" },
|
||||
{ "id": "6976cc0b0c135686a4620b94", "title": "Step 2" },
|
||||
{ "id": "6976d8a7cd2a1a5ffcd7f9c4", "title": "Step 3" },
|
||||
{ "id": "6982684f3a25f379e195a5fc", "title": "Step 4" },
|
||||
{ "id": "69779dcb44016eccc05c15a4", "title": "Step 5" },
|
||||
{ "id": "6977a4306bb3e856690a4890", "title": "Step 6" },
|
||||
{ "id": "6977a8bbcbdd557886bd0718", "title": "Step 7" },
|
||||
{ "id": "697a7f71ebfcd9e4cacd69c2", "title": "Step 8" }
|
||||
],
|
||||
"blockLabel": "workshop",
|
||||
"usesMultifileEditor": true,
|
||||
"hasEditableBoundaries": true
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
"lecture-introduction-to-python-strings",
|
||||
"workshop-employee-profile-generator",
|
||||
"lecture-numbers-and-mathematical-operations",
|
||||
"workshop-bill-splitter",
|
||||
"lecture-booleans-and-conditionals",
|
||||
"workshop-movie-ticket-booking-calculator",
|
||||
"lab-travel-weather-planner",
|
||||
|
||||
Reference in New Issue
Block a user