add new exercise

This commit is contained in:
Andreas Zweili 2021-11-01 20:18:10 +01:00
parent f1c22136a8
commit afbfecdc55
7 changed files with 430 additions and 0 deletions

View File

@ -0,0 +1,10 @@
{
"blurb": "Learn about numbers by solving Chandler's currency exchange conundrums.",
"icon": "hyperia-forex",
"authors": ["Ticktakto", "Yabby1997", "limm-jk", "OMEGA-Y", "wnstj2007", "J08K"],
"files": {
"solution": ["exchange.py"],
"test": ["exchange_test.py"],
"exemplar": [".meta/exemplar.py"]
}
}

View File

@ -0,0 +1 @@
{"track":"python","exercise":"currency-exchange","id":"f1e3f1d8394941a7b649aba8641e3c4a","url":"https://exercism.org/tracks/python/exercises/currency-exchange","handle":"Nebucatnetzer","is_requester":true,"auto_approve":false}

View File

@ -0,0 +1,55 @@
# Help
## Running the tests
To run the included *tests*, run the test file using the `pytest` module, replacing `{exercise_name}`:
```bash
$ python3 -m pytest {exercise_name}_test.py
```
Many IDE's and code editors have built-in support for using Pytest to run tests; check them out [here](https://github.com/exercism/python/blob/main/docs/TOOLS.md#editors-and-ides).
For more information about running tests using `pytest`, checkout our [Python testing guide](https://github.com/exercism/python/blob/main/docs/TESTS.md#pytest).
### Common pytest options
- `-v` : enable verbose output.
- `-x` : stop running tests on first failure.
- `--ff` : run failures from previous test before running other test cases.
For other options, see `python3 -m pytest -h`.
## Submitting your solution
You can submit your solution using the `exercism submit exchange.py` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Python track's documentation](https://exercism.org/docs/tracks/python)
- [Exercism's support channel on gitter](https://gitter.im/exercism/support)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
Below are some resources for getting help if you run into trouble:
- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources.
- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community.
- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the cored developers for the language hang out and get work done.
- [Exercism on Gitter](https://gitter.im/exercism/home) join the Python room for Python-related questions or problems.
- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners.
- [Python Community Forums](https://discuss.python.org/)
- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually.
Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already.
If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question.

View File

@ -0,0 +1,31 @@
# Hints
## General
- [The Python Numbers Tutorial](https://docs.python.org/3/tutorial/introduction.html#numbers) and [Python numeric types](https://docs.python.org/3.9/library/stdtypes.html#numeric-types-int-float-complex) can be a great introduction.
## 1. Estimating exchangeable value
- You can use the [division operator](https://docs.python.org/3/tutorial/introduction.html#numbers) to get the value of exchanged currency.
## 2. Changes after exchanging
- You can use the [subtraction operator](https://docs.python.org/3/tutorial/introduction.html#numbers) to get the amount of changes.
## 3. Calculate value of bills
- You can use the [multiplication operator](https://docs.python.org/3/tutorial/introduction.html#numbers) to get the value of bills.
## 4. Calculate number of bills
- You need to divide `budget` into `denomination`.
- You need to use type casting to _int_ to get the exact number of bills.
- To remove decimal places from a `float`, you can convert it to `int`.
**Note:** The `//` operator also does floor division. But, if the operand has `float`, the result is still `float`.
## 5. Calculate exchangeable value
- You need to calculate `spread` percent of `exchange_rate` using multiplication operator and add it to `exchange_rate` to get the exchanged currency.
- The actual rate needs to be computed. Remember to add exchange rate and exchange fee.
- You can get exchanged money affected by commission by using divide operation and type casting _int_.

View File

@ -0,0 +1,188 @@
# Currency Exchange
Welcome to Currency Exchange on Exercism's Python Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
## Introduction
## Numbers
There are three different kinds of built-in numbers in Python : `ints`, `floats`, and `complex`. However, in this exercise you'll be dealing only with `ints` and `floats`.
### ints
`ints` are whole numbers. e.g. `1234`, `-10`, `20201278`.
Integers in Python have [arbitrary precision][arbitrary-precision] -- the amount of digits is limited only by the available memory of the host system.
### floats
`floats` are numbers containing a decimal point. e.g. `0.0`,`3.14`,`-9.01`.
Floating point numbers are usually implemented in Python using a `double` in C (_15 decimal places of precision_), but will vary in representation based on the host system and other implementation details. This can create some surprises when working with floats, but is "good enough" for most situations.
You can see more details and discussions in the following resources:
- [Python numeric type documentation][numeric-type-docs]
- [The Python Tutorial][floating point math]
- [Documentation for `int()` built in][`int()` built in]
- [Documentation for `float()` built in][`float()` built in]
- [0.30000000000000004.com][0.30000000000000004.com]
## Arithmetic
Python fully supports arithmetic between `ints` and `floats`. It will convert narrower numbers to match their less narrow counterparts when used with the binary arithmetic operators (`+`, `-`, `*`, `/`, `//`, and `%`). When division with `/`, `//` returns the quotient and `%` returns the remainder.
Python considers `ints` narrower than `floats`. So, using a float in an expression ensures the result will be a float too. However, when doing division, the result will always be a float, even if only integers are used.
```python
# The int is widened to a float here, and a float type is returned.
>>> 3 + 4.0
7.0
>>> 3 * 4.0
12.0
>>> 3 - 2.0
1.0
# Division always returns a float.
>>> 6 / 2
3.0
>>> 7 / 4
1.75
# Calculating remainders.
>>> 7 % 4
3
>>> 2 % 4
2
>>> 12.75 % 3
0.75
```
If an int result is needed, you can use `//` to truncate the result.
```python
>>> 6 // 2
3
>>> 7 // 4
1
```
To convert a float to an integer, you can use `int()`. Also, to convert an integer to a float, you can use `float()`.
```python
>>> int(6 / 2)
3
>>> float(1 + 2)
3.0
```
[arbitrary-precision]: https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic#:~:text=In%20computer%20science%2C%20arbitrary%2Dprecision,memory%20of%20the%20host%20system.
[numeric-type-docs]: https://docs.python.org/3/library/stdtypes.html#typesnumeric
[`int()` built in]: https://docs.python.org/3/library/functions.html#int
[`float()` built in]: https://docs.python.org/3/library/functions.html#float
[0.30000000000000004.com]: https://0.30000000000000004.com/
[floating point math]: https://docs.python.org/3.9/tutorial/floatingpoint.html
## Instructions
Your friend Chandler plans to visit exotic countries all around the world. Sadly, Chandler's math skills aren't good. He's pretty worried about being scammed by currency exchanges during his trip - and he wants you to make a currency calculator for him. Here are his specifications for the app:
## 1. Estimate value after exchange
Create the `exchange_money()` function, taking 2 parameters:
1. `budget` : The amount of money you are planning to exchange.
2. `exchange_rate` : Unit value of the foreign currency.
This function should return the value of the exchanged currency.
**Note:** If your currency is USD and you want to exchange USD for EUR with an exchange rate of `1.20`, then `1.20 USD == 1 EUR`.
```python
>>> exchange_money(127.5, 1.2)
106.25
```
## 2. Calculate currency left after an exchange
Create the `get_change()` function, taking 2 parameters:
1. `budget` : Amount of money before exchange.
2. `exchanging_value` : Amount of money that is *taken* from the budget to be exchanged.
This function should return the amount of money that *is left* from the budget.
```python
>>> get_change(127.5, 120)
7.5
```
## 3. Calculate value of bills
Create the `get_value_of_bills()` function, taking 2 parameters:
1. `denomination` : The value of a single bill.
2. `number_of_bills` : Amount of bills you received.
This function should return the total value of the given *bills*.
```python
>>> get_value_of_bills(5, 128)
640
```
## 4. Calculate number of bills
Create the `get_number_of_bills()` function, taking `budget` and `denomination`.
This function should return the *number of bills* that you can get using the *budget*.
**Note: ** You can only receive _whole bills_, not fractions of bills, so remember to divide accordingly.
```python
>>> get_number_of_bills(127.5, 5)
25
```
## 5. Calculate value after exchange
Create the `exchangeable_value()` function, taking `budget`, `exchange_rate`, `spread`, and `denomination`.
Parameter `spread` is the *percentage taken* as an exchange fee.
If `1.00 EUR == 1.20 USD` and the *spread* is `10`, the actual exchange will be: `1.00 EUR == 1.32 USD`.
This function should return the maximum value of the new currency after calculating the *exchange rate* plus the *spread*.
Remember that the currency *denomination* is a whole number, and cannot be sub-divided.
**Note:** Returned value should be `int` type.
```python
>>> exchangeable_value(127.25, 1.20, 10, 20)
80
>>> exchangeable_value(127.25, 1.20, 10, 5)
95
```
## 6. Calculate non-exchangeable value
Create the `non_exchangeable_value()` function, taking `budget`, `exchange_rate`, `spread`, and `denomination`.
This function should return the value that is *not* exchangeable due to the *denomination* of the bills.
**Note:** Returned value should be `int` type.
```python
>>> non_exchangeable_value(127.25, 1.20, 10, 20)
16
>>> non_exchangeable_value(127.25, 1.20, 10, 5)
1
```
## Source
### Created by
- @Ticktakto
- @Yabby1997
- @limm-jk
- @OMEGA-Y
- @wnstj2007
- @J08K

View File

@ -0,0 +1,68 @@
def exchange_money(budget, exchange_rate):
"""
:param budget: float - amount of money you are planning to exchange.
:param exchange_rate: float - unit value of the foreign currency.
:return: float - exchanged value of the foreign currency you can receive.
"""
pass
def get_change(budget, exchanging_value):
"""
:param budget: float - amount of money you own.
:param exchanging_value: int - amount of your money you want to exchange now.
:return: float - amount left of your starting currency after exchanging.
"""
pass
def get_value_of_bills(denomination, number_of_bills):
"""
:param denomination: int - the value of a bill.
:param number_of_bills: int - amount of bills you received.
:return: int - total value of bills you now have.
"""
pass
def get_number_of_bills(budget, denomination):
"""
:param budget: float - the amount of money you are planning to exchange.
:param denomination: int - the value of a single bill.
:return: int - number of bills after exchanging all your money.
"""
pass
def exchangeable_value(budget, exchange_rate, spread, denomination):
"""
:param budget: float - the amount of your money you are planning to exchange.
:param exchange_rate: float - the unit value of the foreign currency.
:param spread: int - percentage that is taken as an exchange fee.
:param denomination: int - the value of a single bill.
:return: int - maximum value you can get.
"""
pass
def non_exchangeable_value(budget, exchange_rate, spread, denomination):
"""
:param budget: float - the amount of your money you are planning to exchange.
:param exchange_rate: float - the unit value of the foreign currency.
:param spread: int - percentage that is taken as an exchange fee.
:param denomination: int - the value of a single bill.
:return: int non-exchangeable value.
"""
pass

View File

@ -0,0 +1,77 @@
import unittest
import pytest
from exchange import (
exchange_money,
get_change,
get_value_of_bills,
get_number_of_bills,
exchangeable_value,
non_exchangeable_value)
class CurrencyExchangeTest(unittest.TestCase):
@pytest.mark.task(taskno=1)
def test_exchange_money(self):
input_data = [(100000, 0.84), (700000, 10.1)]
output_data = [119047, 69306]
for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
with self.subTest(f"variation #{variant}", input_data=input_data, output_data=output_data):
self.assertEqual(int(exchange_money(input_data[0], input_data[1])), output_data)
@pytest.mark.task(taskno=2)
def test_get_change(self):
input_data = [(463000, 5000), (1250, 120), (15000, 1380)]
output_data = [458000, 1130, 13620]
for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
with self.subTest(f"variation #{variant}", input_data=input_data, output_data=output_data):
self.assertEqual(get_change(input_data[0], input_data[1]), output_data)
@pytest.mark.task(taskno=3)
def test_get_value_of_bills(self):
input_data = [(10000, 128), (50, 360), (200, 200)]
output_data = [1280000, 18000, 40000]
for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
with self.subTest(f"variation #{variant}", input_data=input_data, output_data=output_data):
self.assertEqual(get_value_of_bills(input_data[0], input_data[1]), output_data)
@pytest.mark.task(taskno=4)
def test_get_number_of_bills(self):
input_data = [(163270, 50000), (54361, 1000)]
output_data = [3, 54]
for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
with self.subTest(f"variation #{variant}", input_data=input_data, output_data=output_data):
self.assertEqual(get_number_of_bills(input_data[0], input_data[1]), output_data)
@pytest.mark.task(taskno=5)
def test_exchangeable_value(self):
inputs = [
(100000, 10.61, 10, 1),
(1500, 0.84, 25, 40),
(470000, 1050, 30, 10000000000),
(470000, 0.00000009, 30, 700),
(425.33, 0.0009, 30, 700)]
output_data = [8568, 1400, 0, 4017094016600, 363300]
for variant, (inputs, output_data) in enumerate(zip(inputs, output_data), start=1):
with self.subTest(f"variation #{variant}", inputs=inputs, output_data=output_data):
self.assertEqual(exchangeable_value(inputs[0], inputs[1], inputs[2], inputs[3]), output_data)
@pytest.mark.task(taskno=6)
def test_non_exchangeable_value(self):
inputs = [
(100000, 10.61, 10, 1),
(1500, 0.84, 25, 40),
(425.33, 0.0009, 30, 700),
(12000, 0.0096, 10, 50)]
output_data = [0, 28, 229, 13]
for variant, (inputs, output_data) in enumerate(zip(inputs, output_data), start=1):
with self.subTest(f"variation #{variant}", inputs=inputs, output_data=output_data):
self.assertEqual(non_exchangeable_value(inputs[0], inputs[1], inputs[2], inputs[3]), output_data)